.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Copyright 2016-17 IBM Corp. |
---|
3 | | - * |
---|
4 | | - * This program is free software; you can redistribute it and/or |
---|
5 | | - * modify it under the terms of the GNU General Public License |
---|
6 | | - * as published by the Free Software Foundation; either version |
---|
7 | | - * 2 of the License, or (at your option) any later version. |
---|
8 | 4 | */ |
---|
9 | 5 | |
---|
10 | 6 | #define pr_fmt(fmt) "vas: " fmt |
---|
.. | .. |
---|
18 | 14 | #include <linux/of_platform.h> |
---|
19 | 15 | #include <linux/of_address.h> |
---|
20 | 16 | #include <linux/of.h> |
---|
| 17 | +#include <linux/irqdomain.h> |
---|
| 18 | +#include <linux/interrupt.h> |
---|
21 | 19 | #include <asm/prom.h> |
---|
| 20 | +#include <asm/xive.h> |
---|
22 | 21 | |
---|
23 | 22 | #include "vas.h" |
---|
24 | 23 | |
---|
.. | .. |
---|
27 | 26 | |
---|
28 | 27 | static DEFINE_PER_CPU(int, cpu_vas_id); |
---|
29 | 28 | |
---|
| 29 | +static int vas_irq_fault_window_setup(struct vas_instance *vinst) |
---|
| 30 | +{ |
---|
| 31 | + char devname[64]; |
---|
| 32 | + int rc = 0; |
---|
| 33 | + |
---|
| 34 | + snprintf(devname, sizeof(devname), "vas-%d", vinst->vas_id); |
---|
| 35 | + rc = request_threaded_irq(vinst->virq, vas_fault_handler, |
---|
| 36 | + vas_fault_thread_fn, 0, devname, vinst); |
---|
| 37 | + |
---|
| 38 | + if (rc) { |
---|
| 39 | + pr_err("VAS[%d]: Request IRQ(%d) failed with %d\n", |
---|
| 40 | + vinst->vas_id, vinst->virq, rc); |
---|
| 41 | + goto out; |
---|
| 42 | + } |
---|
| 43 | + |
---|
| 44 | + rc = vas_setup_fault_window(vinst); |
---|
| 45 | + if (rc) |
---|
| 46 | + free_irq(vinst->virq, vinst); |
---|
| 47 | + |
---|
| 48 | +out: |
---|
| 49 | + return rc; |
---|
| 50 | +} |
---|
| 51 | + |
---|
30 | 52 | static int init_vas_instance(struct platform_device *pdev) |
---|
31 | 53 | { |
---|
32 | | - int rc, cpu, vasid; |
---|
33 | | - struct resource *res; |
---|
34 | | - struct vas_instance *vinst; |
---|
35 | 54 | struct device_node *dn = pdev->dev.of_node; |
---|
| 55 | + struct vas_instance *vinst; |
---|
| 56 | + struct xive_irq_data *xd; |
---|
| 57 | + uint32_t chipid, hwirq; |
---|
| 58 | + struct resource *res; |
---|
| 59 | + int rc, cpu, vasid; |
---|
36 | 60 | |
---|
37 | 61 | rc = of_property_read_u32(dn, "ibm,vas-id", &vasid); |
---|
38 | 62 | if (rc) { |
---|
39 | 63 | pr_err("No ibm,vas-id property for %s?\n", pdev->name); |
---|
| 64 | + return -ENODEV; |
---|
| 65 | + } |
---|
| 66 | + |
---|
| 67 | + rc = of_property_read_u32(dn, "ibm,chip-id", &chipid); |
---|
| 68 | + if (rc) { |
---|
| 69 | + pr_err("No ibm,chip-id property for %s?\n", pdev->name); |
---|
40 | 70 | return -ENODEV; |
---|
41 | 71 | } |
---|
42 | 72 | |
---|
.. | .. |
---|
73 | 103 | |
---|
74 | 104 | vinst->paste_win_id_shift = 63 - res->end; |
---|
75 | 105 | |
---|
76 | | - pr_devel("Initialized instance [%s, %d], paste_base 0x%llx, " |
---|
77 | | - "paste_win_id_shift 0x%llx\n", pdev->name, vasid, |
---|
78 | | - vinst->paste_base_addr, vinst->paste_win_id_shift); |
---|
| 106 | + hwirq = xive_native_alloc_irq_on_chip(chipid); |
---|
| 107 | + if (!hwirq) { |
---|
| 108 | + pr_err("Inst%d: Unable to allocate global irq for chip %d\n", |
---|
| 109 | + vinst->vas_id, chipid); |
---|
| 110 | + return -ENOENT; |
---|
| 111 | + } |
---|
| 112 | + |
---|
| 113 | + vinst->virq = irq_create_mapping(NULL, hwirq); |
---|
| 114 | + if (!vinst->virq) { |
---|
| 115 | + pr_err("Inst%d: Unable to map global irq %d\n", |
---|
| 116 | + vinst->vas_id, hwirq); |
---|
| 117 | + return -EINVAL; |
---|
| 118 | + } |
---|
| 119 | + |
---|
| 120 | + xd = irq_get_handler_data(vinst->virq); |
---|
| 121 | + if (!xd) { |
---|
| 122 | + pr_err("Inst%d: Invalid virq %d\n", |
---|
| 123 | + vinst->vas_id, vinst->virq); |
---|
| 124 | + return -EINVAL; |
---|
| 125 | + } |
---|
| 126 | + |
---|
| 127 | + vinst->irq_port = xd->trig_page; |
---|
| 128 | + pr_devel("Initialized instance [%s, %d] paste_base 0x%llx paste_win_id_shift 0x%llx IRQ %d Port 0x%llx\n", |
---|
| 129 | + pdev->name, vasid, vinst->paste_base_addr, |
---|
| 130 | + vinst->paste_win_id_shift, vinst->virq, |
---|
| 131 | + vinst->irq_port); |
---|
79 | 132 | |
---|
80 | 133 | for_each_possible_cpu(cpu) { |
---|
81 | 134 | if (cpu_to_chip_id(cpu) == of_get_ibm_chip_id(dn)) |
---|
.. | .. |
---|
86 | 139 | list_add(&vinst->node, &vas_instances); |
---|
87 | 140 | mutex_unlock(&vas_mutex); |
---|
88 | 141 | |
---|
| 142 | + spin_lock_init(&vinst->fault_lock); |
---|
| 143 | + /* |
---|
| 144 | + * IRQ and fault handling setup is needed only for user space |
---|
| 145 | + * send windows. |
---|
| 146 | + */ |
---|
| 147 | + if (vinst->virq) { |
---|
| 148 | + rc = vas_irq_fault_window_setup(vinst); |
---|
| 149 | + /* |
---|
| 150 | + * Fault window is used only for user space send windows. |
---|
| 151 | + * So if vinst->virq is NULL, tx_win_open returns -ENODEV |
---|
| 152 | + * for user space. |
---|
| 153 | + */ |
---|
| 154 | + if (rc) |
---|
| 155 | + vinst->virq = 0; |
---|
| 156 | + } |
---|
| 157 | + |
---|
89 | 158 | vas_instance_init_dbgdir(vinst); |
---|
90 | 159 | |
---|
91 | 160 | dev_set_drvdata(&pdev->dev, vinst); |
---|