aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pci/host/pci-exynos.c44
-rw-r--r--drivers/pci/host/pcie-designware.c240
-rw-r--r--drivers/pci/host/pcie-designware.h14
3 files changed, 298 insertions, 0 deletions
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index 94e096bb2d0a..f062acaf052a 100644
--- a/drivers/pci/host/pci-exynos.c
+++ b/drivers/pci/host/pci-exynos.c
@@ -48,6 +48,7 @@ struct exynos_pcie {
48#define PCIE_IRQ_SPECIAL 0x008 48#define PCIE_IRQ_SPECIAL 0x008
49#define PCIE_IRQ_EN_PULSE 0x00c 49#define PCIE_IRQ_EN_PULSE 0x00c
50#define PCIE_IRQ_EN_LEVEL 0x010 50#define PCIE_IRQ_EN_LEVEL 0x010
51#define IRQ_MSI_ENABLE (0x1 << 2)
51#define PCIE_IRQ_EN_SPECIAL 0x014 52#define PCIE_IRQ_EN_SPECIAL 0x014
52#define PCIE_PWR_RESET 0x018 53#define PCIE_PWR_RESET 0x018
53#define PCIE_CORE_RESET 0x01c 54#define PCIE_CORE_RESET 0x01c
@@ -342,9 +343,36 @@ static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
342 return IRQ_HANDLED; 343 return IRQ_HANDLED;
343} 344}
344 345
346static irqreturn_t exynos_pcie_msi_irq_handler(int irq, void *arg)
347{
348 struct pcie_port *pp = arg;
349
350 dw_handle_msi_irq(pp);
351
352 return IRQ_HANDLED;
353}
354
355static void exynos_pcie_msi_init(struct pcie_port *pp)
356{
357 u32 val;
358 struct exynos_pcie *exynos_pcie = to_exynos_pcie(pp);
359
360 dw_pcie_msi_init(pp);
361
362 /* enable MSI interrupt */
363 val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_EN_LEVEL);
364 val |= IRQ_MSI_ENABLE;
365 exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_LEVEL);
366 return;
367}
368
345static void exynos_pcie_enable_interrupts(struct pcie_port *pp) 369static void exynos_pcie_enable_interrupts(struct pcie_port *pp)
346{ 370{
347 exynos_pcie_enable_irq_pulse(pp); 371 exynos_pcie_enable_irq_pulse(pp);
372
373 if (IS_ENABLED(CONFIG_PCI_MSI))
374 exynos_pcie_msi_init(pp);
375
348 return; 376 return;
349} 377}
350 378
@@ -430,6 +458,22 @@ static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev)
430 return ret; 458 return ret;
431 } 459 }
432 460
461 if (IS_ENABLED(CONFIG_PCI_MSI)) {
462 pp->msi_irq = platform_get_irq(pdev, 0);
463 if (!pp->msi_irq) {
464 dev_err(&pdev->dev, "failed to get msi irq\n");
465 return -ENODEV;
466 }
467
468 ret = devm_request_irq(&pdev->dev, pp->msi_irq,
469 exynos_pcie_msi_irq_handler,
470 IRQF_SHARED, "exynos-pcie", pp);
471 if (ret) {
472 dev_err(&pdev->dev, "failed to request msi irq\n");
473 return ret;
474 }
475 }
476
433 pp->root_bus_nr = -1; 477 pp->root_bus_nr = -1;
434 pp->ops = &exynos_pcie_host_ops; 478 pp->ops = &exynos_pcie_host_ops;
435 479
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index c10e9ac9bbbc..896301788e9d 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -11,8 +11,11 @@
11 * published by the Free Software Foundation. 11 * published by the Free Software Foundation.
12 */ 12 */
13 13
14#include <linux/irq.h>
15#include <linux/irqdomain.h>
14#include <linux/kernel.h> 16#include <linux/kernel.h>
15#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/msi.h>
16#include <linux/of_address.h> 19#include <linux/of_address.h>
17#include <linux/pci.h> 20#include <linux/pci.h>
18#include <linux/pci_regs.h> 21#include <linux/pci_regs.h>
@@ -142,6 +145,204 @@ int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
142 return ret; 145 return ret;
143} 146}
144 147
148static struct irq_chip dw_msi_irq_chip = {
149 .name = "PCI-MSI",
150 .irq_enable = unmask_msi_irq,
151 .irq_disable = mask_msi_irq,
152 .irq_mask = mask_msi_irq,
153 .irq_unmask = unmask_msi_irq,
154};
155
156/* MSI int handler */
157void dw_handle_msi_irq(struct pcie_port *pp)
158{
159 unsigned long val;
160 int i, pos;
161
162 for (i = 0; i < MAX_MSI_CTRLS; i++) {
163 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4,
164 (u32 *)&val);
165 if (val) {
166 pos = 0;
167 while ((pos = find_next_bit(&val, 32, pos)) != 32) {
168 generic_handle_irq(pp->msi_irq_start
169 + (i * 32) + pos);
170 pos++;
171 }
172 }
173 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, val);
174 }
175}
176
177void dw_pcie_msi_init(struct pcie_port *pp)
178{
179 pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
180
181 /* program the msi_data */
182 dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
183 virt_to_phys((void *)pp->msi_data));
184 dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0);
185}
186
187static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
188{
189 int flag = 1;
190
191 do {
192 pos = find_next_zero_bit(pp->msi_irq_in_use,
193 MAX_MSI_IRQS, pos);
194 /*if you have reached to the end then get out from here.*/
195 if (pos == MAX_MSI_IRQS)
196 return -ENOSPC;
197 /*
198 * Check if this position is at correct offset.nvec is always a
199 * power of two. pos0 must be nvec bit alligned.
200 */
201 if (pos % msgvec)
202 pos += msgvec - (pos % msgvec);
203 else
204 flag = 0;
205 } while (flag);
206
207 *pos0 = pos;
208 return 0;
209}
210
211static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
212{
213 int res, bit, irq, pos0, pos1, i;
214 u32 val;
215 struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
216
217 if (!pp) {
218 BUG();
219 return -EINVAL;
220 }
221
222 pos0 = find_first_zero_bit(pp->msi_irq_in_use,
223 MAX_MSI_IRQS);
224 if (pos0 % no_irqs) {
225 if (find_valid_pos0(pp, no_irqs, pos0, &pos0))
226 goto no_valid_irq;
227 }
228 if (no_irqs > 1) {
229 pos1 = find_next_bit(pp->msi_irq_in_use,
230 MAX_MSI_IRQS, pos0);
231 /* there must be nvec number of consecutive free bits */
232 while ((pos1 - pos0) < no_irqs) {
233 if (find_valid_pos0(pp, no_irqs, pos1, &pos0))
234 goto no_valid_irq;
235 pos1 = find_next_bit(pp->msi_irq_in_use,
236 MAX_MSI_IRQS, pos0);
237 }
238 }
239
240 irq = (pp->msi_irq_start + pos0);
241
242 if ((irq + no_irqs) > (pp->msi_irq_start + MAX_MSI_IRQS-1))
243 goto no_valid_irq;
244
245 i = 0;
246 while (i < no_irqs) {
247 set_bit(pos0 + i, pp->msi_irq_in_use);
248 irq_alloc_descs((irq + i), (irq + i), 1, 0);
249 irq_set_msi_desc(irq + i, desc);
250 /*Enable corresponding interrupt in MSI interrupt controller */
251 res = ((pos0 + i) / 32) * 12;
252 bit = (pos0 + i) % 32;
253 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
254 val |= 1 << bit;
255 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
256 i++;
257 }
258
259 *pos = pos0;
260 return irq;
261
262no_valid_irq:
263 *pos = pos0;
264 return -ENOSPC;
265}
266
267static void clear_irq(unsigned int irq)
268{
269 int res, bit, val, pos;
270 struct irq_desc *desc;
271 struct msi_desc *msi;
272 struct pcie_port *pp;
273
274 /* get the port structure */
275 desc = irq_to_desc(irq);
276 msi = irq_desc_get_msi_desc(desc);
277 pp = sys_to_pcie(msi->dev->bus->sysdata);
278 if (!pp) {
279 BUG();
280 return;
281 }
282
283 pos = irq - pp->msi_irq_start;
284
285 irq_free_desc(irq);
286
287 clear_bit(pos, pp->msi_irq_in_use);
288
289 /* Disable corresponding interrupt on MSI interrupt controller */
290 res = (pos / 32) * 12;
291 bit = pos % 32;
292 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
293 val &= ~(1 << bit);
294 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
295}
296
297static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
298 struct msi_desc *desc)
299{
300 int irq, pos, msgvec;
301 u16 msg_ctr;
302 struct msi_msg msg;
303 struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
304
305 if (!pp) {
306 BUG();
307 return -EINVAL;
308 }
309
310 pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS,
311 &msg_ctr);
312 msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
313 if (msgvec == 0)
314 msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
315 if (msgvec > 5)
316 msgvec = 0;
317
318 irq = assign_irq((1 << msgvec), desc, &pos);
319 if (irq < 0)
320 return irq;
321
322 msg_ctr &= ~PCI_MSI_FLAGS_QSIZE;
323 msg_ctr |= msgvec << 4;
324 pci_write_config_word(pdev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
325 msg_ctr);
326 desc->msi_attrib.multiple = msgvec;
327
328 msg.address_lo = virt_to_phys((void *)pp->msi_data);
329 msg.address_hi = 0x0;
330 msg.data = pos;
331 write_msi_msg(irq, &msg);
332
333 return 0;
334}
335
336static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
337{
338 clear_irq(irq);
339}
340
341static struct msi_chip dw_pcie_msi_chip = {
342 .setup_irq = dw_msi_setup_irq,
343 .teardown_irq = dw_msi_teardown_irq,
344};
345
145int dw_pcie_link_up(struct pcie_port *pp) 346int dw_pcie_link_up(struct pcie_port *pp)
146{ 347{
147 if (pp->ops->link_up) 348 if (pp->ops->link_up)
@@ -150,6 +351,20 @@ int dw_pcie_link_up(struct pcie_port *pp)
150 return 0; 351 return 0;
151} 352}
152 353
354static int dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
355 irq_hw_number_t hwirq)
356{
357 irq_set_chip_and_handler(irq, &dw_msi_irq_chip, handle_simple_irq);
358 irq_set_chip_data(irq, domain->host_data);
359 set_irq_flags(irq, IRQF_VALID);
360
361 return 0;
362}
363
364static const struct irq_domain_ops msi_domain_ops = {
365 .map = dw_pcie_msi_map,
366};
367
153int __init dw_pcie_host_init(struct pcie_port *pp) 368int __init dw_pcie_host_init(struct pcie_port *pp)
154{ 369{
155 struct device_node *np = pp->dev->of_node; 370 struct device_node *np = pp->dev->of_node;
@@ -157,6 +372,8 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
157 struct of_pci_range_parser parser; 372 struct of_pci_range_parser parser;
158 u32 val; 373 u32 val;
159 374
375 struct irq_domain *irq_domain;
376
160 if (of_pci_range_parser_init(&parser, np)) { 377 if (of_pci_range_parser_init(&parser, np)) {
161 dev_err(pp->dev, "missing ranges property\n"); 378 dev_err(pp->dev, "missing ranges property\n");
162 return -EINVAL; 379 return -EINVAL;
@@ -223,6 +440,18 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
223 return -EINVAL; 440 return -EINVAL;
224 } 441 }
225 442
443 if (IS_ENABLED(CONFIG_PCI_MSI)) {
444 irq_domain = irq_domain_add_linear(pp->dev->of_node,
445 MAX_MSI_IRQS, &msi_domain_ops,
446 &dw_pcie_msi_chip);
447 if (!irq_domain) {
448 dev_err(pp->dev, "irq domain init failed\n");
449 return -ENXIO;
450 }
451
452 pp->msi_irq_start = irq_find_mapping(irq_domain, 0);
453 }
454
226 if (pp->ops->host_init) 455 if (pp->ops->host_init)
227 pp->ops->host_init(pp); 456 pp->ops->host_init(pp);
228 457
@@ -485,10 +714,21 @@ int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
485 return pp->irq; 714 return pp->irq;
486} 715}
487 716
717static void dw_pcie_add_bus(struct pci_bus *bus)
718{
719 if (IS_ENABLED(CONFIG_PCI_MSI)) {
720 struct pcie_port *pp = sys_to_pcie(bus->sysdata);
721
722 dw_pcie_msi_chip.dev = pp->dev;
723 bus->msi = &dw_pcie_msi_chip;
724 }
725}
726
488static struct hw_pci dw_pci = { 727static struct hw_pci dw_pci = {
489 .setup = dw_pcie_setup, 728 .setup = dw_pcie_setup,
490 .scan = dw_pcie_scan_bus, 729 .scan = dw_pcie_scan_bus,
491 .map_irq = dw_pcie_map_irq, 730 .map_irq = dw_pcie_map_irq,
731 .add_bus = dw_pcie_add_bus,
492}; 732};
493 733
494void dw_pcie_setup_rc(struct pcie_port *pp) 734void dw_pcie_setup_rc(struct pcie_port *pp)
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 133820f1da97..faccbbf31907 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -20,6 +20,14 @@ struct pcie_port_info {
20 phys_addr_t mem_bus_addr; 20 phys_addr_t mem_bus_addr;
21}; 21};
22 22
23/*
24 * Maximum number of MSI IRQs can be 256 per controller. But keep
25 * it 32 as of now. Probably we will never need more than 32. If needed,
26 * then increment it in multiple of 32.
27 */
28#define MAX_MSI_IRQS 32
29#define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32)
30
23struct pcie_port { 31struct pcie_port {
24 struct device *dev; 32 struct device *dev;
25 u8 root_bus_nr; 33 u8 root_bus_nr;
@@ -38,6 +46,10 @@ struct pcie_port {
38 int irq; 46 int irq;
39 u32 lanes; 47 u32 lanes;
40 struct pcie_host_ops *ops; 48 struct pcie_host_ops *ops;
49 int msi_irq;
50 int msi_irq_start;
51 unsigned long msi_data;
52 DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
41}; 53};
42 54
43struct pcie_host_ops { 55struct pcie_host_ops {
@@ -57,6 +69,8 @@ int cfg_read(void __iomem *addr, int where, int size, u32 *val);
57int cfg_write(void __iomem *addr, int where, int size, u32 val); 69int cfg_write(void __iomem *addr, int where, int size, u32 val);
58int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, u32 val); 70int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size, u32 val);
59int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val); 71int dw_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val);
72void dw_handle_msi_irq(struct pcie_port *pp);
73void dw_pcie_msi_init(struct pcie_port *pp);
60int dw_pcie_link_up(struct pcie_port *pp); 74int dw_pcie_link_up(struct pcie_port *pp);
61void dw_pcie_setup_rc(struct pcie_port *pp); 75void dw_pcie_setup_rc(struct pcie_port *pp);
62int dw_pcie_host_init(struct pcie_port *pp); 76int dw_pcie_host_init(struct pcie_port *pp);