source: rtems-libbsd/linux/drivers/soc/fsl/qbman/qman_portal.c @ 936b597

55-freebsd-126-freebsd-12
Last change on this file since 936b597 was 33356a8, checked in by Sebastian Huber <sebastian.huber@…>, on 08/23/17 at 08:08:16

dpaa: Improve QMan portal initialization

Be less dependent on the device tree content.

  • Property mode set to 100644
File size: 13.3 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3#include <rtems/bsd/local/opt_dpaa.h>
4
5/* Copyright 2008 - 2016 Freescale Semiconductor, Inc.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 *     * Redistributions of source code must retain the above copyright
10 *       notice, this list of conditions and the following disclaimer.
11 *     * Redistributions in binary form must reproduce the above copyright
12 *       notice, this list of conditions and the following disclaimer in the
13 *       documentation and/or other materials provided with the distribution.
14 *     * Neither the name of Freescale Semiconductor nor the
15 *       names of its contributors may be used to endorse or promote products
16 *       derived from this software without specific prior written permission.
17 *
18 * ALTERNATIVELY, this software may be distributed under the terms of the
19 * GNU General Public License ("GPL") as published by the Free Software
20 * Foundation, either version 2 of that License or (at your option) any
21 * later version.
22 *
23 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
27 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "qman_priv.h"
36#ifdef __rtems__
37#include <bsp/qoriq.h>
38#undef dev_crit
39#undef dev_info
40#define dev_crit(dev, fmt, ...) printf(fmt, ##__VA_ARGS__)
41#define dev_info dev_crit
42#endif /* __rtems__ */
43
44#ifndef __rtems__
45struct qman_portal *qman_dma_portal;
46EXPORT_SYMBOL(qman_dma_portal);
47#endif /* __rtems__ */
48
49/* Enable portal interupts (as opposed to polling mode) */
50#define CONFIG_FSL_DPA_PIRQ_SLOW  1
51#define CONFIG_FSL_DPA_PIRQ_FAST  1
52
53#ifndef __rtems__
54static struct cpumask portal_cpus;
55/* protect qman global registers and global data shared among portals */
56static DEFINE_SPINLOCK(qman_lock);
57#endif /* __rtems__ */
58
59static void portal_set_cpu(struct qm_portal_config *pcfg, int cpu)
60{
61#ifdef CONFIG_FSL_PAMU
62        struct device *dev = pcfg->dev;
63        int window_count = 1;
64        struct iommu_domain_geometry geom_attr;
65        struct pamu_stash_attribute stash_attr;
66        int ret;
67
68        pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type);
69        if (!pcfg->iommu_domain) {
70                dev_err(dev, "%s(): iommu_domain_alloc() failed", __func__);
71                goto no_iommu;
72        }
73        geom_attr.aperture_start = 0;
74        geom_attr.aperture_end =
75                ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1;
76        geom_attr.force_aperture = true;
77        ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY,
78                                    &geom_attr);
79        if (ret < 0) {
80                dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__,
81                        ret);
82                goto out_domain_free;
83        }
84        ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS,
85                                    &window_count);
86        if (ret < 0) {
87                dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__,
88                        ret);
89                goto out_domain_free;
90        }
91        stash_attr.cpu = cpu;
92        stash_attr.cache = PAMU_ATTR_CACHE_L1;
93        ret = iommu_domain_set_attr(pcfg->iommu_domain,
94                                    DOMAIN_ATTR_FSL_PAMU_STASH,
95                                    &stash_attr);
96        if (ret < 0) {
97                dev_err(dev, "%s(): iommu_domain_set_attr() = %d",
98                        __func__, ret);
99                goto out_domain_free;
100        }
101        ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36,
102                                         IOMMU_READ | IOMMU_WRITE);
103        if (ret < 0) {
104                dev_err(dev, "%s(): iommu_domain_window_enable() = %d",
105                        __func__, ret);
106                goto out_domain_free;
107        }
108        ret = iommu_attach_device(pcfg->iommu_domain, dev);
109        if (ret < 0) {
110                dev_err(dev, "%s(): iommu_device_attach() = %d", __func__,
111                        ret);
112                goto out_domain_free;
113        }
114        ret = iommu_domain_set_attr(pcfg->iommu_domain,
115                                    DOMAIN_ATTR_FSL_PAMU_ENABLE,
116                                    &window_count);
117        if (ret < 0) {
118                dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__,
119                        ret);
120                goto out_detach_device;
121        }
122
123no_iommu:
124#endif
125        qman_set_sdest(pcfg->channel, cpu);
126
127        return;
128
129#ifdef CONFIG_FSL_PAMU
130out_detach_device:
131        iommu_detach_device(pcfg->iommu_domain, NULL);
132out_domain_free:
133        iommu_domain_free(pcfg->iommu_domain);
134        pcfg->iommu_domain = NULL;
135#endif
136}
137
138static struct qman_portal *init_pcfg(struct qm_portal_config *pcfg)
139{
140        struct qman_portal *p;
141        u32 irq_sources = 0;
142
143        /* We need the same LIODN offset for all portals */
144        qman_liodn_fixup(pcfg->channel);
145
146#ifndef __rtems__
147        pcfg->iommu_domain = NULL;
148#endif /* __rtems__ */
149        portal_set_cpu(pcfg, pcfg->cpu);
150        p = qman_create_affine_portal(pcfg, NULL);
151        if (!p) {
152                dev_crit(pcfg->dev, "%s: Portal failure on cpu %d\n",
153                         __func__, pcfg->cpu);
154                return NULL;
155        }
156
157        /* Determine what should be interrupt-vs-poll driven */
158#ifdef CONFIG_FSL_DPA_PIRQ_SLOW
159        irq_sources |= QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI |
160                       QM_PIRQ_CSCI;
161#endif
162#ifdef CONFIG_FSL_DPA_PIRQ_FAST
163        irq_sources |= QM_PIRQ_DQRI;
164#endif
165        qman_p_irqsource_add(p, irq_sources);
166
167#ifndef __rtems__
168        spin_lock(&qman_lock);
169        if (cpumask_equal(&portal_cpus, cpu_possible_mask)) {
170                /* all assigned portals are initialized now */
171                qman_init_cgr_all();
172        }
173
174        if (!qman_dma_portal)
175                qman_dma_portal = p;
176
177        spin_unlock(&qman_lock);
178#endif /* __rtems__ */
179
180        dev_info(pcfg->dev, "Portal initialised, cpu %d\n", pcfg->cpu);
181
182        return p;
183}
184
185static void qman_portal_update_sdest(const struct qm_portal_config *pcfg,
186                                                        unsigned int cpu)
187{
188#ifdef CONFIG_FSL_PAMU /* TODO */
189        struct pamu_stash_attribute stash_attr;
190        int ret;
191
192        if (pcfg->iommu_domain) {
193                stash_attr.cpu = cpu;
194                stash_attr.cache = PAMU_ATTR_CACHE_L1;
195                ret = iommu_domain_set_attr(pcfg->iommu_domain,
196                                DOMAIN_ATTR_FSL_PAMU_STASH, &stash_attr);
197                if (ret < 0) {
198                        dev_err(pcfg->dev,
199                                "Failed to update pamu stash setting\n");
200                        return;
201                }
202        }
203#endif
204        qman_set_sdest(pcfg->channel, cpu);
205}
206
207#ifndef __rtems__
208static int qman_offline_cpu(unsigned int cpu)
209{
210        struct qman_portal *p;
211        const struct qm_portal_config *pcfg;
212
213        p = affine_portals[cpu];
214        if (p) {
215                pcfg = qman_get_qm_portal_config(p);
216                if (pcfg) {
217                        irq_set_affinity(pcfg->irq, cpumask_of(0));
218                        qman_portal_update_sdest(pcfg, 0);
219                }
220        }
221        return 0;
222}
223
224static int qman_online_cpu(unsigned int cpu)
225{
226        struct qman_portal *p;
227        const struct qm_portal_config *pcfg;
228
229        p = affine_portals[cpu];
230        if (p) {
231                pcfg = qman_get_qm_portal_config(p);
232                if (pcfg) {
233                        irq_set_affinity(pcfg->irq, cpumask_of(cpu));
234                        qman_portal_update_sdest(pcfg, cpu);
235                }
236        }
237        return 0;
238}
239
240static int qman_portal_probe(struct platform_device *pdev)
241{
242        struct device *dev = &pdev->dev;
243        struct device_node *node = dev->of_node;
244        struct qm_portal_config *pcfg;
245        struct resource *addr_phys[2];
246        void __iomem *va;
247        int irq, cpu, err;
248        u32 val;
249
250        pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
251        if (!pcfg)
252                return -ENOMEM;
253
254        pcfg->dev = dev;
255
256        addr_phys[0] = platform_get_resource(pdev, IORESOURCE_MEM,
257                                             DPAA_PORTAL_CE);
258        if (!addr_phys[0]) {
259                dev_err(dev, "Can't get %s property 'reg::CE'\n",
260                        node->full_name);
261                return -ENXIO;
262        }
263
264        addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM,
265                                             DPAA_PORTAL_CI);
266        if (!addr_phys[1]) {
267                dev_err(dev, "Can't get %s property 'reg::CI'\n",
268                        node->full_name);
269                return -ENXIO;
270        }
271
272        err = of_property_read_u32(node, "cell-index", &val);
273        if (err) {
274                dev_err(dev, "Can't get %s property 'cell-index'\n",
275                        node->full_name);
276                return err;
277        }
278        pcfg->channel = val;
279        pcfg->cpu = -1;
280        irq = platform_get_irq(pdev, 0);
281        if (irq < 0) {
282                dev_err(dev, "Can't get %s IRQ\n", node->full_name);
283                return -ENXIO;
284        }
285        pcfg->irq = irq;
286
287        va = ioremap_prot(addr_phys[0]->start, resource_size(addr_phys[0]), 0);
288        if (!va) {
289                dev_err(dev, "ioremap::CE failed\n");
290                goto err_ioremap1;
291        }
292
293        pcfg->addr_virt[DPAA_PORTAL_CE] = va;
294
295        va = ioremap_prot(addr_phys[1]->start, resource_size(addr_phys[1]),
296                          _PAGE_GUARDED | _PAGE_NO_CACHE);
297        if (!va) {
298                dev_err(dev, "ioremap::CI failed\n");
299                goto err_ioremap2;
300        }
301
302        pcfg->addr_virt[DPAA_PORTAL_CI] = va;
303
304        pcfg->pools = qm_get_pools_sdqcr();
305
306        spin_lock(&qman_lock);
307        cpu = cpumask_next_zero(-1, &portal_cpus);
308        if (cpu >= nr_cpu_ids) {
309                /* unassigned portal, skip init */
310                spin_unlock(&qman_lock);
311                return 0;
312        }
313
314        cpumask_set_cpu(cpu, &portal_cpus);
315        spin_unlock(&qman_lock);
316        pcfg->cpu = cpu;
317
318        if (dma_set_mask(dev, DMA_BIT_MASK(40))) {
319                dev_err(dev, "dma_set_mask() failed\n");
320                goto err_portal_init;
321        }
322
323        if (!init_pcfg(pcfg)) {
324                dev_err(dev, "portal init failed\n");
325                goto err_portal_init;
326        }
327
328        /* clear irq affinity if assigned cpu is offline */
329        if (!cpu_online(cpu))
330                qman_offline_cpu(cpu);
331
332        return 0;
333
334err_portal_init:
335        iounmap(pcfg->addr_virt[DPAA_PORTAL_CI]);
336err_ioremap2:
337        iounmap(pcfg->addr_virt[DPAA_PORTAL_CE]);
338err_ioremap1:
339        return -ENXIO;
340}
341
342static const struct of_device_id qman_portal_ids[] = {
343        {
344                .compatible = "fsl,qman-portal",
345        },
346        {}
347};
348MODULE_DEVICE_TABLE(of, qman_portal_ids);
349
350static struct platform_driver qman_portal_driver = {
351        .driver = {
352                .name = KBUILD_MODNAME,
353                .of_match_table = qman_portal_ids,
354        },
355        .probe = qman_portal_probe,
356};
357
358static int __init qman_portal_driver_register(struct platform_driver *drv)
359{
360        int ret;
361
362        ret = platform_driver_register(drv);
363        if (ret < 0)
364                return ret;
365
366        ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
367                                        "soc/qman_portal:online",
368                                        qman_online_cpu, qman_offline_cpu);
369        if (ret < 0) {
370                pr_err("qman: failed to register hotplug callbacks.\n");
371                platform_driver_unregister(drv);
372                return ret;
373        }
374        return 0;
375}
376
377module_driver(qman_portal_driver,
378              qman_portal_driver_register, platform_driver_unregister);
379#else /* __rtems__ */
380#include <bsp/fdt.h>
381#include <linux/of_address.h>
382#include <linux/of_irq.h>
383
384#define MAX_QMAN_PORTALS 50
385
386static struct qm_portal_config qman_configs[MAX_QMAN_PORTALS];
387
388static LIST_HEAD(qman_free_portals);
389
390struct qman_portal *
391qman_get_dedicated_portal(int cpu)
392{
393        struct qm_portal_config *pcfg;
394        struct qman_portal *p;
395        u32 irq_sources;
396
397        if (list_empty(&qman_free_portals))
398                return (NULL);
399
400        pcfg = list_first_entry(&qman_free_portals, struct qm_portal_config,
401           node);
402        pcfg->cpu = cpu;
403        p = qman_create_dedicated_portal(pcfg, NULL);
404        if (p == NULL)
405                return (NULL);
406
407        list_del(&pcfg->node);
408
409        irq_sources = QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI | QM_PIRQ_CSCI
410            | QM_PIRQ_DQRI;
411        qman_p_irqsource_add(p, irq_sources);
412        return (p);
413}
414
415static bool
416is_dequeue_enabled(const struct device_node *dn)
417{
418        const char *dequeue;
419        int len;
420
421        dequeue = of_get_property(dn, "libbsd,dequeue", &len);
422        return (len <= 0 || strcmp(dequeue, "disabled") != 0);
423}
424
425static void
426do_init_pcfg(struct device_node *dn, struct qm_portal_config *pcfg,
427    int cpu_count)
428{
429        struct qman_portal *portal;
430        struct resource res;
431        int ret;
432        u32 val;
433
434        ret = of_address_to_resource(dn, 0, &res);
435        if (ret != 0)
436                panic("qman: no portal CE address");
437        pcfg->addr_virt[0] = (__iomem void *)
438            ((uintptr_t)&qoriq_qman_portal[0][0] + (uintptr_t)res.start);
439        BSD_ASSERT((uintptr_t)pcfg->addr_virt[0] >=
440            (uintptr_t)&qoriq_qman_portal[0][0]);
441        BSD_ASSERT((uintptr_t)pcfg->addr_virt[0] <
442            (uintptr_t)&qoriq_qman_portal[1][0]);
443
444        ret = of_address_to_resource(dn, 1, &res);
445        if (ret != 0)
446                panic("qman: no portal CI address");
447        pcfg->addr_virt[1] = (__iomem void *)
448            ((uintptr_t)&qoriq_qman_portal[0][0] + (uintptr_t)res.start);
449        BSD_ASSERT((uintptr_t)pcfg->addr_virt[1] >=
450            (uintptr_t)&qoriq_qman_portal[1][0]);
451        BSD_ASSERT((uintptr_t)pcfg->addr_virt[1] <
452            (uintptr_t)&qoriq_qman_portal[2][0]);
453
454        ret = of_property_read_u32(dn, "cell-index", &val);
455        if (ret != 0)
456                panic("qman: no cell-index");
457        pcfg->channel = val;
458
459        pcfg->irq = of_irq_to_resource(dn, 0, NULL);
460        if (pcfg->irq == NO_IRQ)
461                panic("qman: no portal interrupt");
462
463        if (val < cpu_count) {
464                pcfg->cpu = val;
465
466                if (is_dequeue_enabled(dn)) {
467                        pcfg->pools = qm_get_pools_sdqcr();
468                }
469
470                portal = init_pcfg(pcfg);
471                if (portal == NULL)
472                        panic("qman: cannot create portal");
473
474                qman_portal_update_sdest(pcfg, val);
475        } else {
476                pcfg->cpu = -1;
477                list_add_tail(&pcfg->node, &qman_free_portals);
478        }
479}
480
481void
482qman_sysinit_portals(void)
483{
484        const char *fdt = bsp_fdt_get();
485        struct device_node dn;
486        const char *name;
487        int cpu_count = (int)rtems_get_processor_count();
488        int i;
489        int node;
490        int parent;
491
492        memset(&dn, 0, sizeof(dn));
493
494        name = "fsl,qman-portal";
495        node = fdt_node_offset_by_compatible(fdt, 0, name);
496        if (node < 0)
497                panic("qman: no portals in FDT");
498        parent = fdt_parent_offset(fdt, node);
499        if (parent < 0)
500                panic("qman: no parent of portals in FDT");
501        node = fdt_first_subnode(fdt, parent);
502
503        dn.full_name = name;
504        dn.offset = node;
505
506        qoriq_clear_ce_portal(&qoriq_qman_portal[0][0],
507            sizeof(qoriq_qman_portal[0]));
508        qoriq_clear_ci_portal(&qoriq_qman_portal[1][0],
509            sizeof(qoriq_qman_portal[1]));
510
511        i = 0;
512        while (node >= 0 && i < MAX_QMAN_PORTALS) {
513                if (fdt_node_check_compatible(fdt, node, name) == 0) {
514                        do_init_pcfg(&dn, &qman_configs[i], cpu_count);
515                        ++i;
516                }
517
518                node = fdt_next_subnode(fdt, node);
519                dn.offset = node;
520        }
521
522        if (i < cpu_count)
523                panic("qman: not enough portals in FDT");
524
525        /* all assigned portals are initialized now */
526        qman_init_cgr_all();
527}
528#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.