diff options
Diffstat (limited to 'arch/mips/pci')
-rw-r--r-- | arch/mips/pci/Makefile | 1 | ||||
-rw-r--r-- | arch/mips/pci/fixup-malta.c | 11 | ||||
-rw-r--r-- | arch/mips/pci/fixup-rc32434.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/fixup-sb1250.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/msi-octeon.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/msi-xlp.c | 494 | ||||
-rw-r--r-- | arch/mips/pci/ops-bcm63xx.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/ops-bonito64.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/ops-lantiq.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/ops-loongson2.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/ops-mace.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/ops-msc.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/ops-nile4.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/ops-rc32434.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/pci-ip27.c | 1 | ||||
-rw-r--r-- | arch/mips/pci/pci-malta.c | 6 | ||||
-rw-r--r-- | arch/mips/pci/pci-rt3883.c | 3 | ||||
-rw-r--r-- | arch/mips/pci/pci-xlp.c | 110 |
18 files changed, 589 insertions, 48 deletions
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 719e4557e22e..137f2a6feb25 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile | |||
@@ -60,4 +60,5 @@ obj-$(CONFIG_CPU_XLP) += pci-xlp.o | |||
60 | 60 | ||
61 | ifdef CONFIG_PCI_MSI | 61 | ifdef CONFIG_PCI_MSI |
62 | obj-$(CONFIG_CAVIUM_OCTEON_SOC) += msi-octeon.o | 62 | obj-$(CONFIG_CAVIUM_OCTEON_SOC) += msi-octeon.o |
63 | obj-$(CONFIG_CPU_XLP) += msi-xlp.o | ||
63 | endif | 64 | endif |
diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c index df36e2327c54..7a0eda782e35 100644 --- a/arch/mips/pci/fixup-malta.c +++ b/arch/mips/pci/fixup-malta.c | |||
@@ -54,6 +54,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev) | |||
54 | static void malta_piix_func0_fixup(struct pci_dev *pdev) | 54 | static void malta_piix_func0_fixup(struct pci_dev *pdev) |
55 | { | 55 | { |
56 | unsigned char reg_val; | 56 | unsigned char reg_val; |
57 | u32 reg_val32; | ||
57 | /* PIIX PIRQC[A:D] irq mappings */ | 58 | /* PIIX PIRQC[A:D] irq mappings */ |
58 | static int piixirqmap[PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX] = { | 59 | static int piixirqmap[PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX] = { |
59 | 0, 0, 0, 3, | 60 | 0, 0, 0, 3, |
@@ -83,6 +84,16 @@ static void malta_piix_func0_fixup(struct pci_dev *pdev) | |||
83 | pci_write_config_byte(pdev, PIIX4_FUNC0_TOM, reg_val | | 84 | pci_write_config_byte(pdev, PIIX4_FUNC0_TOM, reg_val | |
84 | PIIX4_FUNC0_TOM_TOP_OF_MEMORY_MASK); | 85 | PIIX4_FUNC0_TOM_TOP_OF_MEMORY_MASK); |
85 | } | 86 | } |
87 | |||
88 | /* Mux SERIRQ to its pin */ | ||
89 | pci_read_config_dword(pdev, PIIX4_FUNC0_GENCFG, ®_val32); | ||
90 | pci_write_config_dword(pdev, PIIX4_FUNC0_GENCFG, | ||
91 | reg_val32 | PIIX4_FUNC0_GENCFG_SERIRQ); | ||
92 | |||
93 | /* Enable SERIRQ */ | ||
94 | pci_read_config_byte(pdev, PIIX4_FUNC0_SERIRQC, ®_val); | ||
95 | reg_val |= PIIX4_FUNC0_SERIRQC_EN | PIIX4_FUNC0_SERIRQC_CONT; | ||
96 | pci_write_config_byte(pdev, PIIX4_FUNC0_SERIRQC, reg_val); | ||
86 | } | 97 | } |
87 | 98 | ||
88 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, | 99 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, |
diff --git a/arch/mips/pci/fixup-rc32434.c b/arch/mips/pci/fixup-rc32434.c index d0f6ecbf35f7..7fcafd5da7da 100644 --- a/arch/mips/pci/fixup-rc32434.c +++ b/arch/mips/pci/fixup-rc32434.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/types.h> | 27 | #include <linux/types.h> |
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/init.h> | ||
31 | 30 | ||
32 | #include <asm/mach-rc32434/rc32434.h> | 31 | #include <asm/mach-rc32434/rc32434.h> |
33 | #include <asm/mach-rc32434/irq.h> | 32 | #include <asm/mach-rc32434/irq.h> |
diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c index 1441becdcb6c..8feae9154baf 100644 --- a/arch/mips/pci/fixup-sb1250.c +++ b/arch/mips/pci/fixup-sb1250.c | |||
@@ -8,7 +8,6 @@ | |||
8 | * 2 of the License, or (at your option) any later version. | 8 | * 2 of the License, or (at your option) any later version. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/pci.h> | 11 | #include <linux/pci.h> |
13 | 12 | ||
14 | /* | 13 | /* |
diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c index d37be36dc659..2b91b0e61566 100644 --- a/arch/mips/pci/msi-octeon.c +++ b/arch/mips/pci/msi-octeon.c | |||
@@ -150,6 +150,7 @@ msi_irq_allocated: | |||
150 | msg.address_lo = | 150 | msg.address_lo = |
151 | ((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff; | 151 | ((128ul << 20) + CVMX_PCI_MSI_RCV) & 0xffffffff; |
152 | msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32; | 152 | msg.address_hi = ((128ul << 20) + CVMX_PCI_MSI_RCV) >> 32; |
153 | break; | ||
153 | case OCTEON_DMA_BAR_TYPE_BIG: | 154 | case OCTEON_DMA_BAR_TYPE_BIG: |
154 | /* When using big bar, Bar 0 is based at 0 */ | 155 | /* When using big bar, Bar 0 is based at 0 */ |
155 | msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff; | 156 | msg.address_lo = (0 + CVMX_PCI_MSI_RCV) & 0xffffffff; |
diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c new file mode 100644 index 000000000000..afd8405e0188 --- /dev/null +++ b/arch/mips/pci/msi-xlp.c | |||
@@ -0,0 +1,494 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2003-2012 Broadcom Corporation | ||
3 | * All Rights Reserved | ||
4 | * | ||
5 | * This software is available to you under a choice of one of two | ||
6 | * licenses. You may choose to be licensed under the terms of the GNU | ||
7 | * General Public License (GPL) Version 2, available from the file | ||
8 | * COPYING in the main directory of this source tree, or the Broadcom | ||
9 | * license below: | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * | ||
15 | * 1. Redistributions of source code must retain the above copyright | ||
16 | * notice, this list of conditions and the following disclaimer. | ||
17 | * 2. Redistributions in binary form must reproduce the above copyright | ||
18 | * notice, this list of conditions and the following disclaimer in | ||
19 | * the documentation and/or other materials provided with the | ||
20 | * distribution. | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR | ||
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
24 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE | ||
26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR | ||
29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE | ||
31 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN | ||
32 | * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/types.h> | ||
36 | #include <linux/pci.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/init.h> | ||
39 | #include <linux/msi.h> | ||
40 | #include <linux/mm.h> | ||
41 | #include <linux/irq.h> | ||
42 | #include <linux/irqdesc.h> | ||
43 | #include <linux/console.h> | ||
44 | |||
45 | #include <asm/io.h> | ||
46 | |||
47 | #include <asm/netlogic/interrupt.h> | ||
48 | #include <asm/netlogic/haldefs.h> | ||
49 | #include <asm/netlogic/common.h> | ||
50 | #include <asm/netlogic/mips-extns.h> | ||
51 | |||
52 | #include <asm/netlogic/xlp-hal/iomap.h> | ||
53 | #include <asm/netlogic/xlp-hal/xlp.h> | ||
54 | #include <asm/netlogic/xlp-hal/pic.h> | ||
55 | #include <asm/netlogic/xlp-hal/pcibus.h> | ||
56 | #include <asm/netlogic/xlp-hal/bridge.h> | ||
57 | |||
58 | #define XLP_MSIVEC_PER_LINK 32 | ||
59 | #define XLP_MSIXVEC_TOTAL 32 | ||
60 | #define XLP_MSIXVEC_PER_LINK 8 | ||
61 | |||
62 | /* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */ | ||
63 | static inline int nlm_link_msiirq(int link, int msivec) | ||
64 | { | ||
65 | return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec; | ||
66 | } | ||
67 | |||
68 | static inline int nlm_irq_msivec(int irq) | ||
69 | { | ||
70 | return irq % XLP_MSIVEC_PER_LINK; | ||
71 | } | ||
72 | |||
73 | static inline int nlm_irq_msilink(int irq) | ||
74 | { | ||
75 | return (irq % (XLP_MSIVEC_PER_LINK * PCIE_NLINKS)) / | ||
76 | XLP_MSIVEC_PER_LINK; | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * Only 32 MSI-X vectors are possible because there are only 32 PIC | ||
81 | * interrupts for MSI. We split them statically and use 8 MSI-X vectors | ||
82 | * per link - this keeps the allocation and lookup simple. | ||
83 | */ | ||
84 | static inline int nlm_link_msixirq(int link, int bit) | ||
85 | { | ||
86 | return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit; | ||
87 | } | ||
88 | |||
89 | static inline int nlm_irq_msixvec(int irq) | ||
90 | { | ||
91 | return irq % XLP_MSIXVEC_TOTAL; /* works when given xirq */ | ||
92 | } | ||
93 | |||
94 | static inline int nlm_irq_msixlink(int irq) | ||
95 | { | ||
96 | return nlm_irq_msixvec(irq) / XLP_MSIXVEC_PER_LINK; | ||
97 | } | ||
98 | |||
99 | /* | ||
100 | * Per link MSI and MSI-X information, set as IRQ handler data for | ||
101 | * MSI and MSI-X interrupts. | ||
102 | */ | ||
103 | struct xlp_msi_data { | ||
104 | struct nlm_soc_info *node; | ||
105 | uint64_t lnkbase; | ||
106 | uint32_t msi_enabled_mask; | ||
107 | uint32_t msi_alloc_mask; | ||
108 | uint32_t msix_alloc_mask; | ||
109 | spinlock_t msi_lock; | ||
110 | }; | ||
111 | |||
112 | /* | ||
113 | * MSI Chip definitions | ||
114 | * | ||
115 | * On XLP, there is a PIC interrupt associated with each PCIe link on the | ||
116 | * chip (which appears as a PCI bridge to us). This gives us 32 MSI irqa | ||
117 | * per link and 128 overall. | ||
118 | * | ||
119 | * When a device connected to the link raises a MSI interrupt, we get a | ||
120 | * link interrupt and we then have to look at PCIE_MSI_STATUS register at | ||
121 | * the bridge to map it to the IRQ | ||
122 | */ | ||
123 | static void xlp_msi_enable(struct irq_data *d) | ||
124 | { | ||
125 | struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); | ||
126 | unsigned long flags; | ||
127 | int vec; | ||
128 | |||
129 | vec = nlm_irq_msivec(d->irq); | ||
130 | spin_lock_irqsave(&md->msi_lock, flags); | ||
131 | md->msi_enabled_mask |= 1u << vec; | ||
132 | nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); | ||
133 | spin_unlock_irqrestore(&md->msi_lock, flags); | ||
134 | } | ||
135 | |||
136 | static void xlp_msi_disable(struct irq_data *d) | ||
137 | { | ||
138 | struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); | ||
139 | unsigned long flags; | ||
140 | int vec; | ||
141 | |||
142 | vec = nlm_irq_msivec(d->irq); | ||
143 | spin_lock_irqsave(&md->msi_lock, flags); | ||
144 | md->msi_enabled_mask &= ~(1u << vec); | ||
145 | nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask); | ||
146 | spin_unlock_irqrestore(&md->msi_lock, flags); | ||
147 | } | ||
148 | |||
149 | static void xlp_msi_mask_ack(struct irq_data *d) | ||
150 | { | ||
151 | struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); | ||
152 | int link, vec; | ||
153 | |||
154 | link = nlm_irq_msilink(d->irq); | ||
155 | vec = nlm_irq_msivec(d->irq); | ||
156 | xlp_msi_disable(d); | ||
157 | |||
158 | /* Ack MSI on bridge */ | ||
159 | nlm_write_reg(md->lnkbase, PCIE_MSI_STATUS, 1u << vec); | ||
160 | |||
161 | /* Ack at eirr and PIC */ | ||
162 | ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link)); | ||
163 | nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link)); | ||
164 | } | ||
165 | |||
166 | static struct irq_chip xlp_msi_chip = { | ||
167 | .name = "XLP-MSI", | ||
168 | .irq_enable = xlp_msi_enable, | ||
169 | .irq_disable = xlp_msi_disable, | ||
170 | .irq_mask_ack = xlp_msi_mask_ack, | ||
171 | .irq_unmask = xlp_msi_enable, | ||
172 | }; | ||
173 | |||
174 | /* | ||
175 | * The MSI-X interrupt handling is different from MSI, there are 32 | ||
176 | * MSI-X interrupts generated by the PIC and each of these correspond | ||
177 | * to a MSI-X vector (0-31) that can be assigned. | ||
178 | * | ||
179 | * We divide the MSI-X vectors to 8 per link and do a per-link | ||
180 | * allocation | ||
181 | * | ||
182 | * Enable and disable done using standard MSI functions. | ||
183 | */ | ||
184 | static void xlp_msix_mask_ack(struct irq_data *d) | ||
185 | { | ||
186 | struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); | ||
187 | int link, msixvec; | ||
188 | |||
189 | msixvec = nlm_irq_msixvec(d->irq); | ||
190 | link = nlm_irq_msixlink(d->irq); | ||
191 | mask_msi_irq(d); | ||
192 | |||
193 | /* Ack MSI on bridge */ | ||
194 | nlm_write_reg(md->lnkbase, PCIE_MSIX_STATUS, 1u << msixvec); | ||
195 | |||
196 | /* Ack at eirr and PIC */ | ||
197 | ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link)); | ||
198 | nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_MSIX_INDEX(msixvec)); | ||
199 | } | ||
200 | |||
201 | static struct irq_chip xlp_msix_chip = { | ||
202 | .name = "XLP-MSIX", | ||
203 | .irq_enable = unmask_msi_irq, | ||
204 | .irq_disable = mask_msi_irq, | ||
205 | .irq_mask_ack = xlp_msix_mask_ack, | ||
206 | .irq_unmask = unmask_msi_irq, | ||
207 | }; | ||
208 | |||
209 | void destroy_irq(unsigned int irq) | ||
210 | { | ||
211 | /* nothing to do yet */ | ||
212 | } | ||
213 | |||
214 | void arch_teardown_msi_irq(unsigned int irq) | ||
215 | { | ||
216 | destroy_irq(irq); | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Setup a PCIe link for MSI. By default, the links are in | ||
221 | * legacy interrupt mode. We will switch them to MSI mode | ||
222 | * at the first MSI request. | ||
223 | */ | ||
224 | static void xlp_config_link_msi(uint64_t lnkbase, int lirq, uint64_t msiaddr) | ||
225 | { | ||
226 | u32 val; | ||
227 | |||
228 | val = nlm_read_reg(lnkbase, PCIE_INT_EN0); | ||
229 | if ((val & 0x200) == 0) { | ||
230 | val |= 0x200; /* MSI Interrupt enable */ | ||
231 | nlm_write_reg(lnkbase, PCIE_INT_EN0, val); | ||
232 | } | ||
233 | |||
234 | val = nlm_read_reg(lnkbase, 0x1); /* CMD */ | ||
235 | if ((val & 0x0400) == 0) { | ||
236 | val |= 0x0400; | ||
237 | nlm_write_reg(lnkbase, 0x1, val); | ||
238 | } | ||
239 | |||
240 | /* Update IRQ in the PCI irq reg */ | ||
241 | val = nlm_read_pci_reg(lnkbase, 0xf); | ||
242 | val &= ~0x1fu; | ||
243 | val |= (1 << 8) | lirq; | ||
244 | nlm_write_pci_reg(lnkbase, 0xf, val); | ||
245 | |||
246 | /* MSI addr */ | ||
247 | nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRH, msiaddr >> 32); | ||
248 | nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRL, msiaddr & 0xffffffff); | ||
249 | |||
250 | /* MSI cap for bridge */ | ||
251 | val = nlm_read_reg(lnkbase, PCIE_BRIDGE_MSI_CAP); | ||
252 | if ((val & (1 << 16)) == 0) { | ||
253 | val |= 0xb << 16; /* mmc32, msi enable */ | ||
254 | nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_CAP, val); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | /* | ||
259 | * Allocate a MSI vector on a link | ||
260 | */ | ||
261 | static int xlp_setup_msi(uint64_t lnkbase, int node, int link, | ||
262 | struct msi_desc *desc) | ||
263 | { | ||
264 | struct xlp_msi_data *md; | ||
265 | struct msi_msg msg; | ||
266 | unsigned long flags; | ||
267 | int msivec, irt, lirq, xirq, ret; | ||
268 | uint64_t msiaddr; | ||
269 | |||
270 | /* Get MSI data for the link */ | ||
271 | lirq = PIC_PCIE_LINK_MSI_IRQ(link); | ||
272 | xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); | ||
273 | md = irq_get_handler_data(xirq); | ||
274 | msiaddr = MSI_LINK_ADDR(node, link); | ||
275 | |||
276 | spin_lock_irqsave(&md->msi_lock, flags); | ||
277 | if (md->msi_alloc_mask == 0) { | ||
278 | /* switch the link IRQ to MSI range */ | ||
279 | xlp_config_link_msi(lnkbase, lirq, msiaddr); | ||
280 | irt = PIC_IRT_PCIE_LINK_INDEX(link); | ||
281 | nlm_setup_pic_irq(node, lirq, lirq, irt); | ||
282 | nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq, | ||
283 | node * nlm_threads_per_node(), 1 /*en */); | ||
284 | } | ||
285 | |||
286 | /* allocate a MSI vec, and tell the bridge about it */ | ||
287 | msivec = fls(md->msi_alloc_mask); | ||
288 | if (msivec == XLP_MSIVEC_PER_LINK) { | ||
289 | spin_unlock_irqrestore(&md->msi_lock, flags); | ||
290 | return -ENOMEM; | ||
291 | } | ||
292 | md->msi_alloc_mask |= (1u << msivec); | ||
293 | spin_unlock_irqrestore(&md->msi_lock, flags); | ||
294 | |||
295 | msg.address_hi = msiaddr >> 32; | ||
296 | msg.address_lo = msiaddr & 0xffffffff; | ||
297 | msg.data = 0xc00 | msivec; | ||
298 | |||
299 | xirq = xirq + msivec; /* msi mapped to global irq space */ | ||
300 | ret = irq_set_msi_desc(xirq, desc); | ||
301 | if (ret < 0) { | ||
302 | destroy_irq(xirq); | ||
303 | return ret; | ||
304 | } | ||
305 | |||
306 | write_msi_msg(xirq, &msg); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | /* | ||
311 | * Switch a link to MSI-X mode | ||
312 | */ | ||
313 | static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr) | ||
314 | { | ||
315 | u32 val; | ||
316 | |||
317 | val = nlm_read_reg(lnkbase, 0x2C); | ||
318 | if ((val & 0x80000000U) == 0) { | ||
319 | val |= 0x80000000U; | ||
320 | nlm_write_reg(lnkbase, 0x2C, val); | ||
321 | } | ||
322 | val = nlm_read_reg(lnkbase, PCIE_INT_EN0); | ||
323 | if ((val & 0x200) == 0) { | ||
324 | val |= 0x200; /* MSI Interrupt enable */ | ||
325 | nlm_write_reg(lnkbase, PCIE_INT_EN0, val); | ||
326 | } | ||
327 | |||
328 | val = nlm_read_reg(lnkbase, 0x1); /* CMD */ | ||
329 | if ((val & 0x0400) == 0) { | ||
330 | val |= 0x0400; | ||
331 | nlm_write_reg(lnkbase, 0x1, val); | ||
332 | } | ||
333 | |||
334 | /* Update IRQ in the PCI irq reg */ | ||
335 | val = nlm_read_pci_reg(lnkbase, 0xf); | ||
336 | val &= ~0x1fu; | ||
337 | val |= (1 << 8) | lirq; | ||
338 | nlm_write_pci_reg(lnkbase, 0xf, val); | ||
339 | |||
340 | /* MSI-X addresses */ | ||
341 | nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_BASE, msixaddr >> 8); | ||
342 | nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_LIMIT, | ||
343 | (msixaddr + MSI_ADDR_SZ) >> 8); | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | * Allocate a MSI-X vector | ||
348 | */ | ||
349 | static int xlp_setup_msix(uint64_t lnkbase, int node, int link, | ||
350 | struct msi_desc *desc) | ||
351 | { | ||
352 | struct xlp_msi_data *md; | ||
353 | struct msi_msg msg; | ||
354 | unsigned long flags; | ||
355 | int t, msixvec, lirq, xirq, ret; | ||
356 | uint64_t msixaddr; | ||
357 | |||
358 | /* Get MSI data for the link */ | ||
359 | lirq = PIC_PCIE_MSIX_IRQ(link); | ||
360 | xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); | ||
361 | md = irq_get_handler_data(xirq); | ||
362 | msixaddr = MSIX_LINK_ADDR(node, link); | ||
363 | |||
364 | spin_lock_irqsave(&md->msi_lock, flags); | ||
365 | /* switch the PCIe link to MSI-X mode at the first alloc */ | ||
366 | if (md->msix_alloc_mask == 0) | ||
367 | xlp_config_link_msix(lnkbase, lirq, msixaddr); | ||
368 | |||
369 | /* allocate a MSI-X vec, and tell the bridge about it */ | ||
370 | t = fls(md->msix_alloc_mask); | ||
371 | if (t == XLP_MSIXVEC_PER_LINK) { | ||
372 | spin_unlock_irqrestore(&md->msi_lock, flags); | ||
373 | return -ENOMEM; | ||
374 | } | ||
375 | md->msix_alloc_mask |= (1u << t); | ||
376 | spin_unlock_irqrestore(&md->msi_lock, flags); | ||
377 | |||
378 | xirq += t; | ||
379 | msixvec = nlm_irq_msixvec(xirq); | ||
380 | msg.address_hi = msixaddr >> 32; | ||
381 | msg.address_lo = msixaddr & 0xffffffff; | ||
382 | msg.data = 0xc00 | msixvec; | ||
383 | |||
384 | ret = irq_set_msi_desc(xirq, desc); | ||
385 | if (ret < 0) { | ||
386 | destroy_irq(xirq); | ||
387 | return ret; | ||
388 | } | ||
389 | |||
390 | write_msi_msg(xirq, &msg); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) | ||
395 | { | ||
396 | struct pci_dev *lnkdev; | ||
397 | uint64_t lnkbase; | ||
398 | int node, link, slot; | ||
399 | |||
400 | lnkdev = xlp_get_pcie_link(dev); | ||
401 | if (lnkdev == NULL) { | ||
402 | dev_err(&dev->dev, "Could not find bridge\n"); | ||
403 | return 1; | ||
404 | } | ||
405 | slot = PCI_SLOT(lnkdev->devfn); | ||
406 | link = PCI_FUNC(lnkdev->devfn); | ||
407 | node = slot / 8; | ||
408 | lnkbase = nlm_get_pcie_base(node, link); | ||
409 | |||
410 | if (desc->msi_attrib.is_msix) | ||
411 | return xlp_setup_msix(lnkbase, node, link, desc); | ||
412 | else | ||
413 | return xlp_setup_msi(lnkbase, node, link, desc); | ||
414 | } | ||
415 | |||
416 | void __init xlp_init_node_msi_irqs(int node, int link) | ||
417 | { | ||
418 | struct nlm_soc_info *nodep; | ||
419 | struct xlp_msi_data *md; | ||
420 | int irq, i, irt, msixvec; | ||
421 | |||
422 | pr_info("[%d %d] Init node PCI IRT\n", node, link); | ||
423 | nodep = nlm_get_node(node); | ||
424 | |||
425 | /* Alloc an MSI block for the link */ | ||
426 | md = kzalloc(sizeof(*md), GFP_KERNEL); | ||
427 | spin_lock_init(&md->msi_lock); | ||
428 | md->msi_enabled_mask = 0; | ||
429 | md->msi_alloc_mask = 0; | ||
430 | md->msix_alloc_mask = 0; | ||
431 | md->node = nodep; | ||
432 | md->lnkbase = nlm_get_pcie_base(node, link); | ||
433 | |||
434 | /* extended space for MSI interrupts */ | ||
435 | irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); | ||
436 | for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) { | ||
437 | irq_set_chip_and_handler(i, &xlp_msi_chip, handle_level_irq); | ||
438 | irq_set_handler_data(i, md); | ||
439 | } | ||
440 | |||
441 | for (i = 0; i < XLP_MSIXVEC_PER_LINK; i++) { | ||
442 | /* Initialize MSI-X irts to generate one interrupt per link */ | ||
443 | msixvec = link * XLP_MSIXVEC_PER_LINK + i; | ||
444 | irt = PIC_IRT_PCIE_MSIX_INDEX(msixvec); | ||
445 | nlm_pic_init_irt(nodep->picbase, irt, PIC_PCIE_MSIX_IRQ(link), | ||
446 | node * nlm_threads_per_node(), 1 /* enable */); | ||
447 | |||
448 | /* Initialize MSI-X extended irq space for the link */ | ||
449 | irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); | ||
450 | irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); | ||
451 | irq_set_handler_data(irq, md); | ||
452 | } | ||
453 | |||
454 | } | ||
455 | |||
456 | void nlm_dispatch_msi(int node, int lirq) | ||
457 | { | ||
458 | struct xlp_msi_data *md; | ||
459 | int link, i, irqbase; | ||
460 | u32 status; | ||
461 | |||
462 | link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; | ||
463 | irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); | ||
464 | md = irq_get_handler_data(irqbase); | ||
465 | status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) & | ||
466 | md->msi_enabled_mask; | ||
467 | while (status) { | ||
468 | i = __ffs(status); | ||
469 | do_IRQ(irqbase + i); | ||
470 | status &= status - 1; | ||
471 | } | ||
472 | } | ||
473 | |||
474 | void nlm_dispatch_msix(int node, int lirq) | ||
475 | { | ||
476 | struct xlp_msi_data *md; | ||
477 | int link, i, irqbase; | ||
478 | u32 status; | ||
479 | |||
480 | link = lirq - PIC_PCIE_MSIX_IRQ_BASE; | ||
481 | irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); | ||
482 | md = irq_get_handler_data(irqbase); | ||
483 | status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS); | ||
484 | |||
485 | /* narrow it down to the MSI-x vectors for our link */ | ||
486 | status = (status >> (link * XLP_MSIXVEC_PER_LINK)) & | ||
487 | ((1 << XLP_MSIXVEC_PER_LINK) - 1); | ||
488 | |||
489 | while (status) { | ||
490 | i = __ffs(status); | ||
491 | do_IRQ(irqbase + i); | ||
492 | status &= status - 1; | ||
493 | } | ||
494 | } | ||
diff --git a/arch/mips/pci/ops-bcm63xx.c b/arch/mips/pci/ops-bcm63xx.c index 6144bb337e44..13eea696bbe7 100644 --- a/arch/mips/pci/ops-bcm63xx.c +++ b/arch/mips/pci/ops-bcm63xx.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/pci.h> | 10 | #include <linux/pci.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/init.h> | ||
13 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
14 | #include <linux/io.h> | 13 | #include <linux/io.h> |
15 | 14 | ||
diff --git a/arch/mips/pci/ops-bonito64.c b/arch/mips/pci/ops-bonito64.c index 830352e3aeda..c06205a87348 100644 --- a/arch/mips/pci/ops-bonito64.c +++ b/arch/mips/pci/ops-bonito64.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | #include <linux/pci.h> | 23 | #include <linux/pci.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/init.h> | ||
26 | 25 | ||
27 | #include <asm/mips-boards/bonito64.h> | 26 | #include <asm/mips-boards/bonito64.h> |
28 | 27 | ||
diff --git a/arch/mips/pci/ops-lantiq.c b/arch/mips/pci/ops-lantiq.c index 16e7c2526d77..e5738ee26f4f 100644 --- a/arch/mips/pci/ops-lantiq.c +++ b/arch/mips/pci/ops-lantiq.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
10 | #include <linux/pci.h> | 10 | #include <linux/pci.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/init.h> | ||
13 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
14 | #include <linux/mm.h> | 13 | #include <linux/mm.h> |
15 | #include <asm/addrspace.h> | 14 | #include <asm/addrspace.h> |
diff --git a/arch/mips/pci/ops-loongson2.c b/arch/mips/pci/ops-loongson2.c index 98254afa0287..24138bb0cbe1 100644 --- a/arch/mips/pci/ops-loongson2.c +++ b/arch/mips/pci/ops-loongson2.c | |||
@@ -14,7 +14,6 @@ | |||
14 | #include <linux/types.h> | 14 | #include <linux/types.h> |
15 | #include <linux/pci.h> | 15 | #include <linux/pci.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/init.h> | ||
18 | #include <linux/export.h> | 17 | #include <linux/export.h> |
19 | 18 | ||
20 | #include <loongson.h> | 19 | #include <loongson.h> |
diff --git a/arch/mips/pci/ops-mace.c b/arch/mips/pci/ops-mace.c index 1cfb5588699f..6b5821febc38 100644 --- a/arch/mips/pci/ops-mace.c +++ b/arch/mips/pci/ops-mace.c | |||
@@ -6,7 +6,6 @@ | |||
6 | * Copyright (C) 2000, 2001 Keith M Wesolowski | 6 | * Copyright (C) 2000, 2001 Keith M Wesolowski |
7 | */ | 7 | */ |
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
9 | #include <linux/init.h> | ||
10 | #include <linux/pci.h> | 9 | #include <linux/pci.h> |
11 | #include <linux/types.h> | 10 | #include <linux/types.h> |
12 | #include <asm/pci.h> | 11 | #include <asm/pci.h> |
diff --git a/arch/mips/pci/ops-msc.c b/arch/mips/pci/ops-msc.c index 92a8543361bb..dbbf3657896c 100644 --- a/arch/mips/pci/ops-msc.c +++ b/arch/mips/pci/ops-msc.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/init.h> | ||
28 | 27 | ||
29 | #include <asm/mips-boards/msc01_pci.h> | 28 | #include <asm/mips-boards/msc01_pci.h> |
30 | 29 | ||
diff --git a/arch/mips/pci/ops-nile4.c b/arch/mips/pci/ops-nile4.c index 499e35c3eb35..a1a7c9f4096e 100644 --- a/arch/mips/pci/ops-nile4.c +++ b/arch/mips/pci/ops-nile4.c | |||
@@ -1,5 +1,4 @@ | |||
1 | #include <linux/kernel.h> | 1 | #include <linux/kernel.h> |
2 | #include <linux/init.h> | ||
3 | #include <linux/pci.h> | 2 | #include <linux/pci.h> |
4 | #include <asm/bootinfo.h> | 3 | #include <asm/bootinfo.h> |
5 | 4 | ||
diff --git a/arch/mips/pci/ops-rc32434.c b/arch/mips/pci/ops-rc32434.c index 7c7182e2350a..874ed6df9768 100644 --- a/arch/mips/pci/ops-rc32434.c +++ b/arch/mips/pci/ops-rc32434.c | |||
@@ -26,7 +26,6 @@ | |||
26 | * 675 Mass Ave, Cambridge, MA 02139, USA. | 26 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
27 | */ | 27 | */ |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/init.h> | ||
30 | #include <linux/io.h> | 29 | #include <linux/io.h> |
31 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
32 | #include <linux/types.h> | 31 | #include <linux/types.h> |
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c index 162b4cb29dba..0f09eafa5e3a 100644 --- a/arch/mips/pci/pci-ip27.c +++ b/arch/mips/pci/pci-ip27.c | |||
@@ -7,7 +7,6 @@ | |||
7 | * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org) | 7 | * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org) |
8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. | 8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
9 | */ | 9 | */ |
10 | #include <linux/init.h> | ||
11 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
12 | #include <linux/export.h> | 11 | #include <linux/export.h> |
13 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
diff --git a/arch/mips/pci/pci-malta.c b/arch/mips/pci/pci-malta.c index 37134ddfeaa5..f1a73890dd4f 100644 --- a/arch/mips/pci/pci-malta.c +++ b/arch/mips/pci/pci-malta.c | |||
@@ -241,9 +241,9 @@ void __init mips_pcibios_init(void) | |||
241 | return; | 241 | return; |
242 | } | 242 | } |
243 | 243 | ||
244 | /* Change start address to avoid conflicts with ACPI and SMB devices */ | 244 | /* PIIX4 ACPI starts at 0x1000 */ |
245 | if (controller->io_resource->start < 0x00002000UL) | 245 | if (controller->io_resource->start < 0x00001000UL) |
246 | controller->io_resource->start = 0x00002000UL; | 246 | controller->io_resource->start = 0x00001000UL; |
247 | 247 | ||
248 | iomem_resource.end &= 0xfffffffffULL; /* 64 GB */ | 248 | iomem_resource.end &= 0xfffffffffULL; /* 64 GB */ |
249 | ioport_resource.end = controller->io_resource->end; | 249 | ioport_resource.end = controller->io_resource->end; |
diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index adeff2bfe4cd..72919aeef42b 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c | |||
@@ -436,9 +436,6 @@ static int rt3883_pci_probe(struct platform_device *pdev) | |||
436 | return -ENOMEM; | 436 | return -ENOMEM; |
437 | 437 | ||
438 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 438 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
439 | if (!res) | ||
440 | return -EINVAL; | ||
441 | |||
442 | rpc->base = devm_ioremap_resource(dev, res); | 439 | rpc->base = devm_ioremap_resource(dev, res); |
443 | if (IS_ERR(rpc->base)) | 440 | if (IS_ERR(rpc->base)) |
444 | return PTR_ERR(rpc->base); | 441 | return PTR_ERR(rpc->base); |
diff --git a/arch/mips/pci/pci-xlp.c b/arch/mips/pci/pci-xlp.c index 653d2db9e0c5..7babf01600cb 100644 --- a/arch/mips/pci/pci-xlp.c +++ b/arch/mips/pci/pci-xlp.c | |||
@@ -47,10 +47,11 @@ | |||
47 | #include <asm/netlogic/interrupt.h> | 47 | #include <asm/netlogic/interrupt.h> |
48 | #include <asm/netlogic/haldefs.h> | 48 | #include <asm/netlogic/haldefs.h> |
49 | #include <asm/netlogic/common.h> | 49 | #include <asm/netlogic/common.h> |
50 | #include <asm/netlogic/mips-extns.h> | ||
50 | 51 | ||
51 | #include <asm/netlogic/xlp-hal/iomap.h> | 52 | #include <asm/netlogic/xlp-hal/iomap.h> |
52 | #include <asm/netlogic/xlp-hal/pic.h> | ||
53 | #include <asm/netlogic/xlp-hal/xlp.h> | 53 | #include <asm/netlogic/xlp-hal/xlp.h> |
54 | #include <asm/netlogic/xlp-hal/pic.h> | ||
54 | #include <asm/netlogic/xlp-hal/pcibus.h> | 55 | #include <asm/netlogic/xlp-hal/pcibus.h> |
55 | #include <asm/netlogic/xlp-hal/bridge.h> | 56 | #include <asm/netlogic/xlp-hal/bridge.h> |
56 | 57 | ||
@@ -66,9 +67,22 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn, | |||
66 | u32 *cfgaddr; | 67 | u32 *cfgaddr; |
67 | 68 | ||
68 | where &= ~3; | 69 | where &= ~3; |
69 | if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) | 70 | if (cpu_is_xlp9xx()) { |
71 | /* be very careful on SoC buses */ | ||
72 | if (bus->number == 0) { | ||
73 | /* Scan only existing nodes - uboot bug? */ | ||
74 | if (PCI_SLOT(devfn) != 0 || | ||
75 | !nlm_node_present(PCI_FUNC(devfn))) | ||
76 | return 0xffffffff; | ||
77 | } else if (bus->parent->number == 0) { /* SoC bus */ | ||
78 | if (PCI_SLOT(devfn) == 0) /* b.0.0 hangs */ | ||
79 | return 0xffffffff; | ||
80 | if (devfn == 44) /* b.5.4 hangs */ | ||
81 | return 0xffffffff; | ||
82 | } | ||
83 | } else if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) { | ||
70 | return 0xffffffff; | 84 | return 0xffffffff; |
71 | 85 | } | |
72 | cfgaddr = (u32 *)(pci_config_base + | 86 | cfgaddr = (u32 *)(pci_config_base + |
73 | pci_cfg_addr(bus->number, devfn, where)); | 87 | pci_cfg_addr(bus->number, devfn, where)); |
74 | data = *cfgaddr; | 88 | data = *cfgaddr; |
@@ -162,27 +176,39 @@ struct pci_controller nlm_pci_controller = { | |||
162 | .io_offset = 0x00000000UL, | 176 | .io_offset = 0x00000000UL, |
163 | }; | 177 | }; |
164 | 178 | ||
165 | static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) | 179 | struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev) |
166 | { | 180 | { |
167 | struct pci_bus *bus, *p; | 181 | struct pci_bus *bus, *p; |
168 | 182 | ||
169 | /* Find the bridge on bus 0 */ | ||
170 | bus = dev->bus; | 183 | bus = dev->bus; |
171 | for (p = bus->parent; p && p->number != 0; p = p->parent) | ||
172 | bus = p; | ||
173 | 184 | ||
174 | return p ? bus->self : NULL; | 185 | if (cpu_is_xlp9xx()) { |
186 | /* find bus with grand parent number == 0 */ | ||
187 | for (p = bus->parent; p && p->parent && p->parent->number != 0; | ||
188 | p = p->parent) | ||
189 | bus = p; | ||
190 | return (p && p->parent) ? bus->self : NULL; | ||
191 | } else { | ||
192 | /* Find the bridge on bus 0 */ | ||
193 | for (p = bus->parent; p && p->number != 0; p = p->parent) | ||
194 | bus = p; | ||
195 | |||
196 | return p ? bus->self : NULL; | ||
197 | } | ||
175 | } | 198 | } |
176 | 199 | ||
177 | static inline int nlm_pci_link_to_irq(int link) | 200 | int xlp_socdev_to_node(const struct pci_dev *lnkdev) |
178 | { | 201 | { |
179 | return PIC_PCIE_LINK_0_IRQ + link; | 202 | if (cpu_is_xlp9xx()) |
203 | return PCI_FUNC(lnkdev->bus->self->devfn); | ||
204 | else | ||
205 | return PCI_SLOT(lnkdev->devfn) / 8; | ||
180 | } | 206 | } |
181 | 207 | ||
182 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | 208 | int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) |
183 | { | 209 | { |
184 | struct pci_dev *lnkdev; | 210 | struct pci_dev *lnkdev; |
185 | int lnkslot, lnkfunc; | 211 | int lnkfunc, node; |
186 | 212 | ||
187 | /* | 213 | /* |
188 | * For XLP PCIe, there is an IRQ per Link, find out which | 214 | * For XLP PCIe, there is an IRQ per Link, find out which |
@@ -191,9 +217,11 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | |||
191 | lnkdev = xlp_get_pcie_link(dev); | 217 | lnkdev = xlp_get_pcie_link(dev); |
192 | if (lnkdev == NULL) | 218 | if (lnkdev == NULL) |
193 | return 0; | 219 | return 0; |
220 | |||
194 | lnkfunc = PCI_FUNC(lnkdev->devfn); | 221 | lnkfunc = PCI_FUNC(lnkdev->devfn); |
195 | lnkslot = PCI_SLOT(lnkdev->devfn); | 222 | node = xlp_socdev_to_node(lnkdev); |
196 | return nlm_irq_to_xirq(lnkslot / 8, nlm_pci_link_to_irq(lnkfunc)); | 223 | |
224 | return nlm_irq_to_xirq(node, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc)); | ||
197 | } | 225 | } |
198 | 226 | ||
199 | /* Do platform specific device initialization at pci_enable_device() time */ | 227 | /* Do platform specific device initialization at pci_enable_device() time */ |
@@ -220,17 +248,38 @@ static void xlp_config_pci_bswap(int node, int link) | |||
220 | * Enable byte swap in hardware. Program each link's PCIe SWAP regions | 248 | * Enable byte swap in hardware. Program each link's PCIe SWAP regions |
221 | * from the link's address ranges. | 249 | * from the link's address ranges. |
222 | */ | 250 | */ |
223 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); | 251 | if (cpu_is_xlp9xx()) { |
224 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); | 252 | reg = nlm_read_bridge_reg(nbubase, |
225 | 253 | BRIDGE_9XX_PCIEMEM_BASE0 + link); | |
226 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link); | 254 | nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_MEM_BASE, reg); |
227 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); | 255 | |
228 | 256 | reg = nlm_read_bridge_reg(nbubase, | |
229 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); | 257 | BRIDGE_9XX_PCIEMEM_LIMIT0 + link); |
230 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); | 258 | nlm_write_pci_reg(lnkbase, |
231 | 259 | PCIE_9XX_BYTE_SWAP_MEM_LIM, reg | 0xfff); | |
232 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); | 260 | |
233 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); | 261 | reg = nlm_read_bridge_reg(nbubase, |
262 | BRIDGE_9XX_PCIEIO_BASE0 + link); | ||
263 | nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_IO_BASE, reg); | ||
264 | |||
265 | reg = nlm_read_bridge_reg(nbubase, | ||
266 | BRIDGE_9XX_PCIEIO_LIMIT0 + link); | ||
267 | nlm_write_pci_reg(lnkbase, | ||
268 | PCIE_9XX_BYTE_SWAP_IO_LIM, reg | 0xfff); | ||
269 | } else { | ||
270 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link); | ||
271 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg); | ||
272 | |||
273 | reg = nlm_read_bridge_reg(nbubase, | ||
274 | BRIDGE_PCIEMEM_LIMIT0 + link); | ||
275 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff); | ||
276 | |||
277 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link); | ||
278 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg); | ||
279 | |||
280 | reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link); | ||
281 | nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff); | ||
282 | } | ||
234 | } | 283 | } |
235 | #else | 284 | #else |
236 | /* Swap configuration not needed in little-endian mode */ | 285 | /* Swap configuration not needed in little-endian mode */ |
@@ -239,7 +288,6 @@ static inline void xlp_config_pci_bswap(int node, int link) {} | |||
239 | 288 | ||
240 | static int __init pcibios_init(void) | 289 | static int __init pcibios_init(void) |
241 | { | 290 | { |
242 | struct nlm_soc_info *nodep; | ||
243 | uint64_t pciebase; | 291 | uint64_t pciebase; |
244 | int link, n; | 292 | int link, n; |
245 | u32 reg; | 293 | u32 reg; |
@@ -253,20 +301,20 @@ static int __init pcibios_init(void) | |||
253 | ioport_resource.end = ~0; | 301 | ioport_resource.end = ~0; |
254 | 302 | ||
255 | for (n = 0; n < NLM_NR_NODES; n++) { | 303 | for (n = 0; n < NLM_NR_NODES; n++) { |
256 | nodep = nlm_get_node(n); | 304 | if (!nlm_node_present(n)) |
257 | if (!nodep->coremask) | 305 | continue; |
258 | continue; /* node does not exist */ | ||
259 | 306 | ||
260 | for (link = 0; link < 4; link++) { | 307 | for (link = 0; link < PCIE_NLINKS; link++) { |
261 | pciebase = nlm_get_pcie_base(n, link); | 308 | pciebase = nlm_get_pcie_base(n, link); |
262 | if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) | 309 | if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff) |
263 | continue; | 310 | continue; |
264 | xlp_config_pci_bswap(n, link); | 311 | xlp_config_pci_bswap(n, link); |
312 | xlp_init_node_msi_irqs(n, link); | ||
265 | 313 | ||
266 | /* put in intpin and irq - u-boot does not */ | 314 | /* put in intpin and irq - u-boot does not */ |
267 | reg = nlm_read_pci_reg(pciebase, 0xf); | 315 | reg = nlm_read_pci_reg(pciebase, 0xf); |
268 | reg &= ~0x1fu; | 316 | reg &= ~0x1ffu; |
269 | reg |= (1 << 8) | nlm_pci_link_to_irq(link); | 317 | reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link); |
270 | nlm_write_pci_reg(pciebase, 0xf, reg); | 318 | nlm_write_pci_reg(pciebase, 0xf, reg); |
271 | pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); | 319 | pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link); |
272 | } | 320 | } |