kernel: update kernel 4.4 to 4.4.52
[openwrt/staging/yousong.git] / target / linux / layerscape / patches-4.4 / 8239-irqchip-ls-scfg-msi-add-LS1046a-MSI-support.patch
1 From 20fd0e76257005cb46a2ce1a30018a45d96199bf Mon Sep 17 00:00:00 2001
2 From: Minghuan Lian <Minghuan.Lian@nxp.com>
3 Date: Tue, 17 Jan 2017 17:32:41 +0800
4 Subject: [PATCH 10/13] irqchip/ls-scfg-msi: add LS1046a MSI support
5
6 Cherry-pick patchwork patch with context adjustment.
7
8 LS1046a includes 4 MSIRs, each MSIR is assigned a dedicate GIC
9 SPI interrupt and provides 32 MSI interrupts. Compared to previous
10 MSI, LS1046a's IBS(interrupt bit select) shift is changed to 2 and
11 total MSI interrupt number is changed to 128.
12
13 The patch adds structure 'ls_scfg_msir' to describe MSIR setting and
14 'ibs_shift' to store the different value between the SoCs.
15
16 Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
17 Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
18 ---
19 drivers/irqchip/irq-ls-scfg-msi.c | 168 +++++++++++++++++++++++++++++---------
20 1 file changed, 131 insertions(+), 37 deletions(-)
21
22 --- a/drivers/irqchip/irq-ls-scfg-msi.c
23 +++ b/drivers/irqchip/irq-ls-scfg-msi.c
24 @@ -17,13 +17,24 @@
25 #include <linux/irq.h>
26 #include <linux/irqchip/chained_irq.h>
27 #include <linux/irqdomain.h>
28 +#include <linux/of_irq.h>
29 #include <linux/of_pci.h>
30 #include <linux/of_platform.h>
31 #include <linux/spinlock.h>
32
33 -#define MSI_MAX_IRQS 32
34 -#define MSI_IBS_SHIFT 3
35 -#define MSIR 4
36 +#define MSI_IRQS_PER_MSIR 32
37 +#define MSI_MSIR_OFFSET 4
38 +
39 +struct ls_scfg_msi_cfg {
40 + u32 ibs_shift; /* Shift of interrupt bit select */
41 +};
42 +
43 +struct ls_scfg_msir {
44 + struct ls_scfg_msi *msi_data;
45 + unsigned int index;
46 + unsigned int gic_irq;
47 + void __iomem *reg;
48 +};
49
50 struct ls_scfg_msi {
51 spinlock_t lock;
52 @@ -32,8 +43,11 @@ struct ls_scfg_msi {
53 struct irq_domain *msi_domain;
54 void __iomem *regs;
55 phys_addr_t msiir_addr;
56 - int irq;
57 - DECLARE_BITMAP(used, MSI_MAX_IRQS);
58 + struct ls_scfg_msi_cfg *cfg;
59 + u32 msir_num;
60 + struct ls_scfg_msir *msir;
61 + u32 irqs_num;
62 + unsigned long *used;
63 };
64
65 static struct irq_chip ls_scfg_msi_irq_chip = {
66 @@ -55,7 +69,7 @@ static void ls_scfg_msi_compose_msg(stru
67
68 msg->address_hi = upper_32_bits(msi_data->msiir_addr);
69 msg->address_lo = lower_32_bits(msi_data->msiir_addr);
70 - msg->data = data->hwirq << MSI_IBS_SHIFT;
71 + msg->data = data->hwirq;
72 }
73
74 static int ls_scfg_msi_set_affinity(struct irq_data *irq_data,
75 @@ -81,8 +95,8 @@ static int ls_scfg_msi_domain_irq_alloc(
76 WARN_ON(nr_irqs != 1);
77
78 spin_lock(&msi_data->lock);
79 - pos = find_first_zero_bit(msi_data->used, MSI_MAX_IRQS);
80 - if (pos < MSI_MAX_IRQS)
81 + pos = find_first_zero_bit(msi_data->used, msi_data->irqs_num);
82 + if (pos < msi_data->irqs_num)
83 __set_bit(pos, msi_data->used);
84 else
85 err = -ENOSPC;
86 @@ -106,7 +120,7 @@ static void ls_scfg_msi_domain_irq_free(
87 int pos;
88
89 pos = d->hwirq;
90 - if (pos < 0 || pos >= MSI_MAX_IRQS) {
91 + if (pos < 0 || pos >= msi_data->irqs_num) {
92 pr_err("failed to teardown msi. Invalid hwirq %d\n", pos);
93 return;
94 }
95 @@ -123,15 +137,17 @@ static const struct irq_domain_ops ls_sc
96
97 static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
98 {
99 - struct ls_scfg_msi *msi_data = irq_desc_get_handler_data(desc);
100 + struct ls_scfg_msir *msir = irq_desc_get_handler_data(desc);
101 + struct ls_scfg_msi *msi_data = msir->msi_data;
102 unsigned long val;
103 - int pos, virq;
104 + int pos, virq, hwirq;
105
106 chained_irq_enter(irq_desc_get_chip(desc), desc);
107
108 - val = ioread32be(msi_data->regs + MSIR);
109 - for_each_set_bit(pos, &val, MSI_MAX_IRQS) {
110 - virq = irq_find_mapping(msi_data->parent, (31 - pos));
111 + val = ioread32be(msir->reg);
112 + for_each_set_bit(pos, &val, MSI_IRQS_PER_MSIR) {
113 + hwirq = ((31 - pos) << msi_data->cfg->ibs_shift) | msir->index;
114 + virq = irq_find_mapping(msi_data->parent, hwirq);
115 if (virq)
116 generic_handle_irq(virq);
117 }
118 @@ -143,7 +159,7 @@ static int ls_scfg_msi_domains_init(stru
119 {
120 /* Initialize MSI domain parent */
121 msi_data->parent = irq_domain_add_linear(NULL,
122 - MSI_MAX_IRQS,
123 + msi_data->irqs_num,
124 &ls_scfg_msi_domain_ops,
125 msi_data);
126 if (!msi_data->parent) {
127 @@ -164,16 +180,88 @@ static int ls_scfg_msi_domains_init(stru
128 return 0;
129 }
130
131 +static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
132 +{
133 + struct ls_scfg_msir *msir;
134 + int virq, i, hwirq;
135 +
136 + virq = platform_get_irq(msi_data->pdev, index);
137 + if (virq <= 0)
138 + return -ENODEV;
139 +
140 + msir = &msi_data->msir[index];
141 + msir->index = index;
142 + msir->msi_data = msi_data;
143 + msir->gic_irq = virq;
144 + msir->reg = msi_data->regs + MSI_MSIR_OFFSET + 4 * index;
145 +
146 + irq_set_chained_handler_and_data(msir->gic_irq,
147 + ls_scfg_msi_irq_handler,
148 + msir);
149 +
150 + /* Release the hwirqs corresponding to this MSIR */
151 + for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
152 + hwirq = i << msi_data->cfg->ibs_shift | msir->index;
153 + bitmap_clear(msi_data->used, hwirq, 1);
154 + }
155 +
156 + return 0;
157 +}
158 +
159 +static int ls_scfg_msi_teardown_hwirq(struct ls_scfg_msir *msir)
160 +{
161 + struct ls_scfg_msi *msi_data = msir->msi_data;
162 + int i, hwirq;
163 +
164 + if (msir->gic_irq > 0)
165 + irq_set_chained_handler_and_data(msir->gic_irq, NULL, NULL);
166 +
167 + for (i = 0; i < MSI_IRQS_PER_MSIR; i++) {
168 + hwirq = i << msi_data->cfg->ibs_shift | msir->index;
169 + bitmap_set(msi_data->used, hwirq, 1);
170 + }
171 +
172 + return 0;
173 +}
174 +
175 +static struct ls_scfg_msi_cfg ls1021_msi_cfg = {
176 + .ibs_shift = 3,
177 +};
178 +
179 +static struct ls_scfg_msi_cfg ls1046_msi_cfg = {
180 + .ibs_shift = 2,
181 +};
182 +
183 +static const struct of_device_id ls_scfg_msi_id[] = {
184 + /* The following two misspelled compatibles are obsolete */
185 + { .compatible = "fsl,1s1021a-msi", .data = &ls1021_msi_cfg},
186 + { .compatible = "fsl,1s1043a-msi", .data = &ls1021_msi_cfg},
187 +
188 + { .compatible = "fsl,ls1012a-msi", .data = &ls1021_msi_cfg },
189 + { .compatible = "fsl,ls1021a-msi", .data = &ls1021_msi_cfg },
190 + { .compatible = "fsl,ls1043a-msi", .data = &ls1021_msi_cfg },
191 + { .compatible = "fsl,ls1046a-msi", .data = &ls1046_msi_cfg },
192 + {},
193 +};
194 +MODULE_DEVICE_TABLE(of, ls_scfg_msi_id);
195 +
196 static int ls_scfg_msi_probe(struct platform_device *pdev)
197 {
198 + const struct of_device_id *match;
199 struct ls_scfg_msi *msi_data;
200 struct resource *res;
201 - int ret;
202 + int i, ret;
203 +
204 + match = of_match_device(ls_scfg_msi_id, &pdev->dev);
205 + if (!match)
206 + return -ENODEV;
207
208 msi_data = devm_kzalloc(&pdev->dev, sizeof(*msi_data), GFP_KERNEL);
209 if (!msi_data)
210 return -ENOMEM;
211
212 + msi_data->cfg = (struct ls_scfg_msi_cfg *) match->data;
213 +
214 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
215 msi_data->regs = devm_ioremap_resource(&pdev->dev, res);
216 if (IS_ERR(msi_data->regs)) {
217 @@ -182,23 +270,37 @@ static int ls_scfg_msi_probe(struct plat
218 }
219 msi_data->msiir_addr = res->start;
220
221 - msi_data->irq = platform_get_irq(pdev, 0);
222 - if (msi_data->irq <= 0) {
223 - dev_err(&pdev->dev, "failed to get MSI irq\n");
224 - return -ENODEV;
225 - }
226 -
227 msi_data->pdev = pdev;
228 spin_lock_init(&msi_data->lock);
229
230 + msi_data->irqs_num = MSI_IRQS_PER_MSIR *
231 + (1 << msi_data->cfg->ibs_shift);
232 + msi_data->used = devm_kcalloc(&pdev->dev,
233 + BITS_TO_LONGS(msi_data->irqs_num),
234 + sizeof(*msi_data->used),
235 + GFP_KERNEL);
236 + if (!msi_data->used)
237 + return -ENOMEM;
238 + /*
239 + * Reserve all the hwirqs
240 + * The available hwirqs will be released in ls1_msi_setup_hwirq()
241 + */
242 + bitmap_set(msi_data->used, 0, msi_data->irqs_num);
243 +
244 + msi_data->msir_num = of_irq_count(pdev->dev.of_node);
245 + msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num,
246 + sizeof(*msi_data->msir),
247 + GFP_KERNEL);
248 + if (!msi_data->msir)
249 + return -ENOMEM;
250 +
251 + for (i = 0; i < msi_data->msir_num; i++)
252 + ls_scfg_msi_setup_hwirq(msi_data, i);
253 +
254 ret = ls_scfg_msi_domains_init(msi_data);
255 if (ret)
256 return ret;
257
258 - irq_set_chained_handler_and_data(msi_data->irq,
259 - ls_scfg_msi_irq_handler,
260 - msi_data);
261 -
262 platform_set_drvdata(pdev, msi_data);
263
264 return 0;
265 @@ -207,8 +309,10 @@ static int ls_scfg_msi_probe(struct plat
266 static int ls_scfg_msi_remove(struct platform_device *pdev)
267 {
268 struct ls_scfg_msi *msi_data = platform_get_drvdata(pdev);
269 + int i;
270
271 - irq_set_chained_handler_and_data(msi_data->irq, NULL, NULL);
272 + for (i = 0; i < msi_data->msir_num; i++)
273 + ls_scfg_msi_teardown_hwirq(&msi_data->msir[i]);
274
275 irq_domain_remove(msi_data->msi_domain);
276 irq_domain_remove(msi_data->parent);
277 @@ -218,16 +322,6 @@ static int ls_scfg_msi_remove(struct pla
278 return 0;
279 }
280
281 -static const struct of_device_id ls_scfg_msi_id[] = {
282 - { .compatible = "fsl,ls1012a-msi", },
283 - { .compatible = "fsl,1s1021a-msi", }, /* a typo */
284 - { .compatible = "fsl,1s1043a-msi", }, /* a typo */
285 - { .compatible = "fsl,ls1021a-msi", },
286 - { .compatible = "fsl,ls1043a-msi", },
287 - { .compatible = "fsl,ls1046a-msi", },
288 - {},
289 -};
290 -
291 static struct platform_driver ls_scfg_msi_driver = {
292 .driver = {
293 .name = "ls-scfg-msi",