source: rtems-libbsd/linux/drivers/soc/fsl/qbman/qman_portal.c @ 45149ec

55-freebsd-126-freebsd-12
Last change on this file since 45149ec was 45149ec, checked in by Sebastian Huber <sebastian.huber@…>, on 10/26/17 at 13:02:24

Fix general PowerPC build

  • Property mode set to 100644
File size: 13.4 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#undef dev_crit
38#undef dev_info
39#define dev_crit(dev, fmt, ...) printf(fmt, ##__VA_ARGS__)
40#define dev_info dev_crit
41#endif /* __rtems__ */
42
43#ifndef __rtems__
44struct qman_portal *qman_dma_portal;
45EXPORT_SYMBOL(qman_dma_portal);
46#endif /* __rtems__ */
47
48/* Enable portal interupts (as opposed to polling mode) */
49#define CONFIG_FSL_DPA_PIRQ_SLOW  1
50#define CONFIG_FSL_DPA_PIRQ_FAST  1
51
52#ifndef __rtems__
53static struct cpumask portal_cpus;
54/* protect qman global registers and global data shared among portals */
55static DEFINE_SPINLOCK(qman_lock);
56#endif /* __rtems__ */
57
58static void portal_set_cpu(struct qm_portal_config *pcfg, int cpu)
59{
60#ifdef CONFIG_FSL_PAMU
61        struct device *dev = pcfg->dev;
62        int window_count = 1;
63        struct iommu_domain_geometry geom_attr;
64        struct pamu_stash_attribute stash_attr;
65        int ret;
66
67        pcfg->iommu_domain = iommu_domain_alloc(&platform_bus_type);
68        if (!pcfg->iommu_domain) {
69                dev_err(dev, "%s(): iommu_domain_alloc() failed", __func__);
70                goto no_iommu;
71        }
72        geom_attr.aperture_start = 0;
73        geom_attr.aperture_end =
74                ((dma_addr_t)1 << min(8 * sizeof(dma_addr_t), (size_t)36)) - 1;
75        geom_attr.force_aperture = true;
76        ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_GEOMETRY,
77                                    &geom_attr);
78        if (ret < 0) {
79                dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__,
80                        ret);
81                goto out_domain_free;
82        }
83        ret = iommu_domain_set_attr(pcfg->iommu_domain, DOMAIN_ATTR_WINDOWS,
84                                    &window_count);
85        if (ret < 0) {
86                dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__,
87                        ret);
88                goto out_domain_free;
89        }
90        stash_attr.cpu = cpu;
91        stash_attr.cache = PAMU_ATTR_CACHE_L1;
92        ret = iommu_domain_set_attr(pcfg->iommu_domain,
93                                    DOMAIN_ATTR_FSL_PAMU_STASH,
94                                    &stash_attr);
95        if (ret < 0) {
96                dev_err(dev, "%s(): iommu_domain_set_attr() = %d",
97                        __func__, ret);
98                goto out_domain_free;
99        }
100        ret = iommu_domain_window_enable(pcfg->iommu_domain, 0, 0, 1ULL << 36,
101                                         IOMMU_READ | IOMMU_WRITE);
102        if (ret < 0) {
103                dev_err(dev, "%s(): iommu_domain_window_enable() = %d",
104                        __func__, ret);
105                goto out_domain_free;
106        }
107        ret = iommu_attach_device(pcfg->iommu_domain, dev);
108        if (ret < 0) {
109                dev_err(dev, "%s(): iommu_device_attach() = %d", __func__,
110                        ret);
111                goto out_domain_free;
112        }
113        ret = iommu_domain_set_attr(pcfg->iommu_domain,
114                                    DOMAIN_ATTR_FSL_PAMU_ENABLE,
115                                    &window_count);
116        if (ret < 0) {
117                dev_err(dev, "%s(): iommu_domain_set_attr() = %d", __func__,
118                        ret);
119                goto out_detach_device;
120        }
121
122no_iommu:
123#endif
124        qman_set_sdest(pcfg->channel, cpu);
125
126        return;
127
128#ifdef CONFIG_FSL_PAMU
129out_detach_device:
130        iommu_detach_device(pcfg->iommu_domain, NULL);
131out_domain_free:
132        iommu_domain_free(pcfg->iommu_domain);
133        pcfg->iommu_domain = NULL;
134#endif
135}
136
137static struct qman_portal *init_pcfg(struct qm_portal_config *pcfg)
138{
139        struct qman_portal *p;
140        u32 irq_sources = 0;
141
142        /* We need the same LIODN offset for all portals */
143        qman_liodn_fixup(pcfg->channel);
144
145#ifndef __rtems__
146        pcfg->iommu_domain = NULL;
147#endif /* __rtems__ */
148        portal_set_cpu(pcfg, pcfg->cpu);
149        p = qman_create_affine_portal(pcfg, NULL);
150        if (!p) {
151                dev_crit(pcfg->dev, "%s: Portal failure on cpu %d\n",
152                         __func__, pcfg->cpu);
153                return NULL;
154        }
155
156        /* Determine what should be interrupt-vs-poll driven */
157#ifdef CONFIG_FSL_DPA_PIRQ_SLOW
158        irq_sources |= QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI |
159                       QM_PIRQ_CSCI;
160#endif
161#ifdef CONFIG_FSL_DPA_PIRQ_FAST
162        irq_sources |= QM_PIRQ_DQRI;
163#endif
164        qman_p_irqsource_add(p, irq_sources);
165
166#ifndef __rtems__
167        spin_lock(&qman_lock);
168        if (cpumask_equal(&portal_cpus, cpu_possible_mask)) {
169                /* all assigned portals are initialized now */
170                qman_init_cgr_all();
171        }
172
173        if (!qman_dma_portal)
174                qman_dma_portal = p;
175
176        spin_unlock(&qman_lock);
177#endif /* __rtems__ */
178
179        dev_info(pcfg->dev, "Portal initialised, cpu %d\n", pcfg->cpu);
180
181        return p;
182}
183
184static void qman_portal_update_sdest(const struct qm_portal_config *pcfg,
185                                                        unsigned int cpu)
186{
187#ifdef CONFIG_FSL_PAMU /* TODO */
188        struct pamu_stash_attribute stash_attr;
189        int ret;
190
191        if (pcfg->iommu_domain) {
192                stash_attr.cpu = cpu;
193                stash_attr.cache = PAMU_ATTR_CACHE_L1;
194                ret = iommu_domain_set_attr(pcfg->iommu_domain,
195                                DOMAIN_ATTR_FSL_PAMU_STASH, &stash_attr);
196                if (ret < 0) {
197                        dev_err(pcfg->dev,
198                                "Failed to update pamu stash setting\n");
199                        return;
200                }
201        }
202#endif
203        qman_set_sdest(pcfg->channel, cpu);
204}
205
206#ifndef __rtems__
207static int qman_offline_cpu(unsigned int cpu)
208{
209        struct qman_portal *p;
210        const struct qm_portal_config *pcfg;
211
212        p = affine_portals[cpu];
213        if (p) {
214                pcfg = qman_get_qm_portal_config(p);
215                if (pcfg) {
216                        irq_set_affinity(pcfg->irq, cpumask_of(0));
217                        qman_portal_update_sdest(pcfg, 0);
218                }
219        }
220        return 0;
221}
222
223static int qman_online_cpu(unsigned int cpu)
224{
225        struct qman_portal *p;
226        const struct qm_portal_config *pcfg;
227
228        p = affine_portals[cpu];
229        if (p) {
230                pcfg = qman_get_qm_portal_config(p);
231                if (pcfg) {
232                        irq_set_affinity(pcfg->irq, cpumask_of(cpu));
233                        qman_portal_update_sdest(pcfg, cpu);
234                }
235        }
236        return 0;
237}
238
239static int qman_portal_probe(struct platform_device *pdev)
240{
241        struct device *dev = &pdev->dev;
242        struct device_node *node = dev->of_node;
243        struct qm_portal_config *pcfg;
244        struct resource *addr_phys[2];
245        void __iomem *va;
246        int irq, cpu, err;
247        u32 val;
248
249        pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
250        if (!pcfg)
251                return -ENOMEM;
252
253        pcfg->dev = dev;
254
255        addr_phys[0] = platform_get_resource(pdev, IORESOURCE_MEM,
256                                             DPAA_PORTAL_CE);
257        if (!addr_phys[0]) {
258                dev_err(dev, "Can't get %s property 'reg::CE'\n",
259                        node->full_name);
260                return -ENXIO;
261        }
262
263        addr_phys[1] = platform_get_resource(pdev, IORESOURCE_MEM,
264                                             DPAA_PORTAL_CI);
265        if (!addr_phys[1]) {
266                dev_err(dev, "Can't get %s property 'reg::CI'\n",
267                        node->full_name);
268                return -ENXIO;
269        }
270
271        err = of_property_read_u32(node, "cell-index", &val);
272        if (err) {
273                dev_err(dev, "Can't get %s property 'cell-index'\n",
274                        node->full_name);
275                return err;
276        }
277        pcfg->channel = val;
278        pcfg->cpu = -1;
279        irq = platform_get_irq(pdev, 0);
280        if (irq < 0) {
281                dev_err(dev, "Can't get %s IRQ\n", node->full_name);
282                return -ENXIO;
283        }
284        pcfg->irq = irq;
285
286        va = ioremap_prot(addr_phys[0]->start, resource_size(addr_phys[0]), 0);
287        if (!va) {
288                dev_err(dev, "ioremap::CE failed\n");
289                goto err_ioremap1;
290        }
291
292        pcfg->addr_virt[DPAA_PORTAL_CE] = va;
293
294        va = ioremap_prot(addr_phys[1]->start, resource_size(addr_phys[1]),
295                          _PAGE_GUARDED | _PAGE_NO_CACHE);
296        if (!va) {
297                dev_err(dev, "ioremap::CI failed\n");
298                goto err_ioremap2;
299        }
300
301        pcfg->addr_virt[DPAA_PORTAL_CI] = va;
302
303        pcfg->pools = qm_get_pools_sdqcr();
304
305        spin_lock(&qman_lock);
306        cpu = cpumask_next_zero(-1, &portal_cpus);
307        if (cpu >= nr_cpu_ids) {
308                /* unassigned portal, skip init */
309                spin_unlock(&qman_lock);
310                return 0;
311        }
312
313        cpumask_set_cpu(cpu, &portal_cpus);
314        spin_unlock(&qman_lock);
315        pcfg->cpu = cpu;
316
317        if (dma_set_mask(dev, DMA_BIT_MASK(40))) {
318                dev_err(dev, "dma_set_mask() failed\n");
319                goto err_portal_init;
320        }
321
322        if (!init_pcfg(pcfg)) {
323                dev_err(dev, "portal init failed\n");
324                goto err_portal_init;
325        }
326
327        /* clear irq affinity if assigned cpu is offline */
328        if (!cpu_online(cpu))
329                qman_offline_cpu(cpu);
330
331        return 0;
332
333err_portal_init:
334        iounmap(pcfg->addr_virt[DPAA_PORTAL_CI]);
335err_ioremap2:
336        iounmap(pcfg->addr_virt[DPAA_PORTAL_CE]);
337err_ioremap1:
338        return -ENXIO;
339}
340
341static const struct of_device_id qman_portal_ids[] = {
342        {
343                .compatible = "fsl,qman-portal",
344        },
345        {}
346};
347MODULE_DEVICE_TABLE(of, qman_portal_ids);
348
349static struct platform_driver qman_portal_driver = {
350        .driver = {
351                .name = KBUILD_MODNAME,
352                .of_match_table = qman_portal_ids,
353        },
354        .probe = qman_portal_probe,
355};
356
357static int __init qman_portal_driver_register(struct platform_driver *drv)
358{
359        int ret;
360
361        ret = platform_driver_register(drv);
362        if (ret < 0)
363                return ret;
364
365        ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
366                                        "soc/qman_portal:online",
367                                        qman_online_cpu, qman_offline_cpu);
368        if (ret < 0) {
369                pr_err("qman: failed to register hotplug callbacks.\n");
370                platform_driver_unregister(drv);
371                return ret;
372        }
373        return 0;
374}
375
376module_driver(qman_portal_driver,
377              qman_portal_driver_register, platform_driver_unregister);
378#else /* __rtems__ */
379#include <bsp/fdt.h>
380#include <linux/of_address.h>
381#include <linux/of_irq.h>
382
383#define MAX_QMAN_PORTALS 50
384
385static struct qm_portal_config qman_configs[MAX_QMAN_PORTALS];
386
387static LIST_HEAD(qman_free_portals);
388
389struct qman_portal *
390qman_get_dedicated_portal(int cpu)
391{
392        struct qm_portal_config *pcfg;
393        struct qman_portal *p;
394        u32 irq_sources;
395
396        if (list_empty(&qman_free_portals))
397                return (NULL);
398
399        pcfg = list_first_entry(&qman_free_portals, struct qm_portal_config,
400           node);
401        pcfg->cpu = cpu;
402        p = qman_create_dedicated_portal(pcfg, NULL);
403        if (p == NULL)
404                return (NULL);
405
406        list_del(&pcfg->node);
407
408        irq_sources = QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI | QM_PIRQ_CSCI
409            | QM_PIRQ_DQRI;
410        qman_p_irqsource_add(p, irq_sources);
411        return (p);
412}
413
414static bool
415is_dequeue_enabled(const struct device_node *dn)
416{
417        const char *dequeue;
418        int len;
419
420        dequeue = of_get_property(dn, "libbsd,dequeue", &len);
421        return (len <= 0 || strcmp(dequeue, "disabled") != 0);
422}
423
424static void
425do_init_pcfg(struct device_node *dn, struct qm_portal_config *pcfg,
426    int cpu_count)
427{
428        struct qman_portal *portal;
429        struct resource res;
430        int ret;
431        u32 val;
432
433        ret = of_address_to_resource(dn, 0, &res);
434        if (ret != 0)
435                panic("qman: no portal CE address");
436#if QORIQ_CHIP_IS_T_VARIANT(QORIQ_CHIP_VARIANT)
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#endif
444
445        ret = of_address_to_resource(dn, 1, &res);
446        if (ret != 0)
447                panic("qman: no portal CI address");
448#if QORIQ_CHIP_IS_T_VARIANT(QORIQ_CHIP_VARIANT)
449        pcfg->addr_virt[1] = (__iomem void *)
450            ((uintptr_t)&qoriq_qman_portal[0][0] + (uintptr_t)res.start);
451        BSD_ASSERT((uintptr_t)pcfg->addr_virt[1] >=
452            (uintptr_t)&qoriq_qman_portal[1][0]);
453        BSD_ASSERT((uintptr_t)pcfg->addr_virt[1] <
454            (uintptr_t)&qoriq_qman_portal[2][0]);
455#endif
456
457        ret = of_property_read_u32(dn, "cell-index", &val);
458        if (ret != 0)
459                panic("qman: no cell-index");
460        pcfg->channel = val;
461
462        pcfg->irq = of_irq_to_resource(dn, 0, NULL);
463        if (pcfg->irq == NO_IRQ)
464                panic("qman: no portal interrupt");
465
466        if (val < cpu_count) {
467                pcfg->cpu = val;
468
469                if (is_dequeue_enabled(dn)) {
470                        pcfg->pools = qm_get_pools_sdqcr();
471                }
472
473                portal = init_pcfg(pcfg);
474                if (portal == NULL)
475                        panic("qman: cannot create portal");
476
477                qman_portal_update_sdest(pcfg, val);
478        } else {
479                pcfg->cpu = -1;
480                list_add_tail(&pcfg->node, &qman_free_portals);
481        }
482}
483
484void
485qman_sysinit_portals(void)
486{
487        const char *fdt = bsp_fdt_get();
488        struct device_node dn;
489        const char *name;
490        int cpu_count = (int)rtems_get_processor_count();
491        int i;
492        int node;
493        int parent;
494
495        memset(&dn, 0, sizeof(dn));
496
497        name = "fsl,qman-portal";
498        node = fdt_node_offset_by_compatible(fdt, 0, name);
499        if (node < 0)
500                panic("qman: no portals in FDT");
501        parent = fdt_parent_offset(fdt, node);
502        if (parent < 0)
503                panic("qman: no parent of portals in FDT");
504        node = fdt_first_subnode(fdt, parent);
505
506        dn.full_name = name;
507        dn.offset = node;
508
509#if QORIQ_CHIP_IS_T_VARIANT(QORIQ_CHIP_VARIANT)
510        qoriq_clear_ce_portal(&qoriq_qman_portal[0][0],
511            sizeof(qoriq_qman_portal[0]));
512        qoriq_clear_ci_portal(&qoriq_qman_portal[1][0],
513            sizeof(qoriq_qman_portal[1]));
514#endif
515
516        i = 0;
517        while (node >= 0 && i < MAX_QMAN_PORTALS) {
518                if (fdt_node_check_compatible(fdt, node, name) == 0) {
519                        do_init_pcfg(&dn, &qman_configs[i], cpu_count);
520                        ++i;
521                }
522
523                node = fdt_next_subnode(fdt, node);
524                dn.offset = node;
525        }
526
527        if (i < cpu_count)
528                panic("qman: not enough portals in FDT");
529
530        /* all assigned portals are initialized now */
531        qman_init_cgr_all();
532}
533#endif /* __rtems__ */
Note: See TracBrowser for help on using the repository browser.