Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * spu management operations for of based platforms
0004  *
0005  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
0006  * Copyright 2006 Sony Corp.
0007  * (C) Copyright 2007 TOSHIBA CORPORATION
0008  */
0009 
0010 #include <linux/interrupt.h>
0011 #include <linux/list.h>
0012 #include <linux/export.h>
0013 #include <linux/ptrace.h>
0014 #include <linux/wait.h>
0015 #include <linux/mm.h>
0016 #include <linux/io.h>
0017 #include <linux/mutex.h>
0018 #include <linux/device.h>
0019 #include <linux/of_address.h>
0020 #include <linux/of_irq.h>
0021 
0022 #include <asm/spu.h>
0023 #include <asm/spu_priv1.h>
0024 #include <asm/firmware.h>
0025 
0026 #include "spufs/spufs.h"
0027 #include "interrupt.h"
0028 
0029 struct device_node *spu_devnode(struct spu *spu)
0030 {
0031     return spu->devnode;
0032 }
0033 
0034 EXPORT_SYMBOL_GPL(spu_devnode);
0035 
0036 static u64 __init find_spu_unit_number(struct device_node *spe)
0037 {
0038     const unsigned int *prop;
0039     int proplen;
0040 
0041     /* new device trees should provide the physical-id attribute */
0042     prop = of_get_property(spe, "physical-id", &proplen);
0043     if (proplen == 4)
0044         return (u64)*prop;
0045 
0046     /* celleb device tree provides the unit-id */
0047     prop = of_get_property(spe, "unit-id", &proplen);
0048     if (proplen == 4)
0049         return (u64)*prop;
0050 
0051     /* legacy device trees provide the id in the reg attribute */
0052     prop = of_get_property(spe, "reg", &proplen);
0053     if (proplen == 4)
0054         return (u64)*prop;
0055 
0056     return 0;
0057 }
0058 
0059 static void spu_unmap(struct spu *spu)
0060 {
0061     if (!firmware_has_feature(FW_FEATURE_LPAR))
0062         iounmap(spu->priv1);
0063     iounmap(spu->priv2);
0064     iounmap(spu->problem);
0065     iounmap((__force u8 __iomem *)spu->local_store);
0066 }
0067 
0068 static int __init spu_map_interrupts_old(struct spu *spu,
0069     struct device_node *np)
0070 {
0071     unsigned int isrc;
0072     const u32 *tmp;
0073     int nid;
0074 
0075     /* Get the interrupt source unit from the device-tree */
0076     tmp = of_get_property(np, "isrc", NULL);
0077     if (!tmp)
0078         return -ENODEV;
0079     isrc = tmp[0];
0080 
0081     tmp = of_get_property(np->parent->parent, "node-id", NULL);
0082     if (!tmp) {
0083         printk(KERN_WARNING "%s: can't find node-id\n", __func__);
0084         nid = spu->node;
0085     } else
0086         nid = tmp[0];
0087 
0088     /* Add the node number */
0089     isrc |= nid << IIC_IRQ_NODE_SHIFT;
0090 
0091     /* Now map interrupts of all 3 classes */
0092     spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
0093     spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
0094     spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
0095 
0096     /* Right now, we only fail if class 2 failed */
0097     if (!spu->irqs[2])
0098         return -EINVAL;
0099 
0100     return 0;
0101 }
0102 
0103 static void __iomem * __init spu_map_prop_old(struct spu *spu,
0104                           struct device_node *n,
0105                           const char *name)
0106 {
0107     const struct address_prop {
0108         unsigned long address;
0109         unsigned int len;
0110     } __attribute__((packed)) *prop;
0111     int proplen;
0112 
0113     prop = of_get_property(n, name, &proplen);
0114     if (prop == NULL || proplen != sizeof (struct address_prop))
0115         return NULL;
0116 
0117     return ioremap(prop->address, prop->len);
0118 }
0119 
0120 static int __init spu_map_device_old(struct spu *spu)
0121 {
0122     struct device_node *node = spu->devnode;
0123     const char *prop;
0124     int ret;
0125 
0126     ret = -ENODEV;
0127     spu->name = of_get_property(node, "name", NULL);
0128     if (!spu->name)
0129         goto out;
0130 
0131     prop = of_get_property(node, "local-store", NULL);
0132     if (!prop)
0133         goto out;
0134     spu->local_store_phys = *(unsigned long *)prop;
0135 
0136     /* we use local store as ram, not io memory */
0137     spu->local_store = (void __force *)
0138         spu_map_prop_old(spu, node, "local-store");
0139     if (!spu->local_store)
0140         goto out;
0141 
0142     prop = of_get_property(node, "problem", NULL);
0143     if (!prop)
0144         goto out_unmap;
0145     spu->problem_phys = *(unsigned long *)prop;
0146 
0147     spu->problem = spu_map_prop_old(spu, node, "problem");
0148     if (!spu->problem)
0149         goto out_unmap;
0150 
0151     spu->priv2 = spu_map_prop_old(spu, node, "priv2");
0152     if (!spu->priv2)
0153         goto out_unmap;
0154 
0155     if (!firmware_has_feature(FW_FEATURE_LPAR)) {
0156         spu->priv1 = spu_map_prop_old(spu, node, "priv1");
0157         if (!spu->priv1)
0158             goto out_unmap;
0159     }
0160 
0161     ret = 0;
0162     goto out;
0163 
0164 out_unmap:
0165     spu_unmap(spu);
0166 out:
0167     return ret;
0168 }
0169 
0170 static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
0171 {
0172     int i;
0173 
0174     for (i=0; i < 3; i++) {
0175         spu->irqs[i] = irq_of_parse_and_map(np, i);
0176         if (!spu->irqs[i])
0177             goto err;
0178     }
0179     return 0;
0180 
0181 err:
0182     pr_debug("failed to map irq %x for spu %s\n", i, spu->name);
0183     for (; i >= 0; i--) {
0184         if (spu->irqs[i])
0185             irq_dispose_mapping(spu->irqs[i]);
0186     }
0187     return -EINVAL;
0188 }
0189 
0190 static int __init spu_map_resource(struct spu *spu, int nr,
0191                 void __iomem** virt, unsigned long *phys)
0192 {
0193     struct device_node *np = spu->devnode;
0194     struct resource resource = { };
0195     unsigned long len;
0196     int ret;
0197 
0198     ret = of_address_to_resource(np, nr, &resource);
0199     if (ret)
0200         return ret;
0201     if (phys)
0202         *phys = resource.start;
0203     len = resource_size(&resource);
0204     *virt = ioremap(resource.start, len);
0205     if (!*virt)
0206         return -EINVAL;
0207     return 0;
0208 }
0209 
0210 static int __init spu_map_device(struct spu *spu)
0211 {
0212     struct device_node *np = spu->devnode;
0213     int ret = -ENODEV;
0214 
0215     spu->name = of_get_property(np, "name", NULL);
0216     if (!spu->name)
0217         goto out;
0218 
0219     ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store,
0220                    &spu->local_store_phys);
0221     if (ret) {
0222         pr_debug("spu_new: failed to map %pOF resource 0\n",
0223              np);
0224         goto out;
0225     }
0226     ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem,
0227                    &spu->problem_phys);
0228     if (ret) {
0229         pr_debug("spu_new: failed to map %pOF resource 1\n",
0230              np);
0231         goto out_unmap;
0232     }
0233     ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL);
0234     if (ret) {
0235         pr_debug("spu_new: failed to map %pOF resource 2\n",
0236              np);
0237         goto out_unmap;
0238     }
0239     if (!firmware_has_feature(FW_FEATURE_LPAR))
0240         ret = spu_map_resource(spu, 3,
0241                    (void __iomem**)&spu->priv1, NULL);
0242     if (ret) {
0243         pr_debug("spu_new: failed to map %pOF resource 3\n",
0244              np);
0245         goto out_unmap;
0246     }
0247     pr_debug("spu_new: %pOF maps:\n", np);
0248     pr_debug("  local store   : 0x%016lx -> 0x%p\n",
0249          spu->local_store_phys, spu->local_store);
0250     pr_debug("  problem state : 0x%016lx -> 0x%p\n",
0251          spu->problem_phys, spu->problem);
0252     pr_debug("  priv2         :                       0x%p\n", spu->priv2);
0253     pr_debug("  priv1         :                       0x%p\n", spu->priv1);
0254 
0255     return 0;
0256 
0257 out_unmap:
0258     spu_unmap(spu);
0259 out:
0260     pr_debug("failed to map spe %s: %d\n", spu->name, ret);
0261     return ret;
0262 }
0263 
0264 static int __init of_enumerate_spus(int (*fn)(void *data))
0265 {
0266     int ret;
0267     struct device_node *node;
0268     unsigned int n = 0;
0269 
0270     ret = -ENODEV;
0271     for_each_node_by_type(node, "spe") {
0272         ret = fn(node);
0273         if (ret) {
0274             printk(KERN_WARNING "%s: Error initializing %pOFn\n",
0275                 __func__, node);
0276             of_node_put(node);
0277             break;
0278         }
0279         n++;
0280     }
0281     return ret ? ret : n;
0282 }
0283 
0284 static int __init of_create_spu(struct spu *spu, void *data)
0285 {
0286     int ret;
0287     struct device_node *spe = (struct device_node *)data;
0288     static int legacy_map = 0, legacy_irq = 0;
0289 
0290     spu->devnode = of_node_get(spe);
0291     spu->spe_id = find_spu_unit_number(spe);
0292 
0293     spu->node = of_node_to_nid(spe);
0294     if (spu->node >= MAX_NUMNODES) {
0295         printk(KERN_WARNING "SPE %pOF on node %d ignored,"
0296                " node number too big\n", spe, spu->node);
0297         printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
0298         ret = -ENODEV;
0299         goto out;
0300     }
0301 
0302     ret = spu_map_device(spu);
0303     if (ret) {
0304         if (!legacy_map) {
0305             legacy_map = 1;
0306             printk(KERN_WARNING "%s: Legacy device tree found, "
0307                 "trying to map old style\n", __func__);
0308         }
0309         ret = spu_map_device_old(spu);
0310         if (ret) {
0311             printk(KERN_ERR "Unable to map %s\n",
0312                 spu->name);
0313             goto out;
0314         }
0315     }
0316 
0317     ret = spu_map_interrupts(spu, spe);
0318     if (ret) {
0319         if (!legacy_irq) {
0320             legacy_irq = 1;
0321             printk(KERN_WARNING "%s: Legacy device tree found, "
0322                 "trying old style irq\n", __func__);
0323         }
0324         ret = spu_map_interrupts_old(spu, spe);
0325         if (ret) {
0326             printk(KERN_ERR "%s: could not map interrupts\n",
0327                 spu->name);
0328             goto out_unmap;
0329         }
0330     }
0331 
0332     pr_debug("Using SPE %s %p %p %p %p %d\n", spu->name,
0333         spu->local_store, spu->problem, spu->priv1,
0334         spu->priv2, spu->number);
0335     goto out;
0336 
0337 out_unmap:
0338     spu_unmap(spu);
0339 out:
0340     return ret;
0341 }
0342 
0343 static int of_destroy_spu(struct spu *spu)
0344 {
0345     spu_unmap(spu);
0346     of_node_put(spu->devnode);
0347     return 0;
0348 }
0349 
0350 static void enable_spu_by_master_run(struct spu_context *ctx)
0351 {
0352     ctx->ops->master_start(ctx);
0353 }
0354 
0355 static void disable_spu_by_master_run(struct spu_context *ctx)
0356 {
0357     ctx->ops->master_stop(ctx);
0358 }
0359 
0360 /* Hardcoded affinity idxs for qs20 */
0361 #define QS20_SPES_PER_BE 8
0362 static int qs20_reg_idxs[QS20_SPES_PER_BE] =   { 0, 2, 4, 6, 7, 5, 3, 1 };
0363 static int qs20_reg_memory[QS20_SPES_PER_BE] = { 1, 1, 0, 0, 0, 0, 0, 0 };
0364 
0365 static struct spu *__init spu_lookup_reg(int node, u32 reg)
0366 {
0367     struct spu *spu;
0368     const u32 *spu_reg;
0369 
0370     list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
0371         spu_reg = of_get_property(spu_devnode(spu), "reg", NULL);
0372         if (*spu_reg == reg)
0373             return spu;
0374     }
0375     return NULL;
0376 }
0377 
0378 static void __init init_affinity_qs20_harcoded(void)
0379 {
0380     int node, i;
0381     struct spu *last_spu, *spu;
0382     u32 reg;
0383 
0384     for (node = 0; node < MAX_NUMNODES; node++) {
0385         last_spu = NULL;
0386         for (i = 0; i < QS20_SPES_PER_BE; i++) {
0387             reg = qs20_reg_idxs[i];
0388             spu = spu_lookup_reg(node, reg);
0389             if (!spu)
0390                 continue;
0391             spu->has_mem_affinity = qs20_reg_memory[reg];
0392             if (last_spu)
0393                 list_add_tail(&spu->aff_list,
0394                         &last_spu->aff_list);
0395             last_spu = spu;
0396         }
0397     }
0398 }
0399 
0400 static int __init of_has_vicinity(void)
0401 {
0402     struct device_node *dn;
0403 
0404     for_each_node_by_type(dn, "spe") {
0405         if (of_find_property(dn, "vicinity", NULL))  {
0406             of_node_put(dn);
0407             return 1;
0408         }
0409     }
0410     return 0;
0411 }
0412 
0413 static struct spu *__init devnode_spu(int cbe, struct device_node *dn)
0414 {
0415     struct spu *spu;
0416 
0417     list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list)
0418         if (spu_devnode(spu) == dn)
0419             return spu;
0420     return NULL;
0421 }
0422 
0423 static struct spu * __init
0424 neighbour_spu(int cbe, struct device_node *target, struct device_node *avoid)
0425 {
0426     struct spu *spu;
0427     struct device_node *spu_dn;
0428     const phandle *vic_handles;
0429     int lenp, i;
0430 
0431     list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list) {
0432         spu_dn = spu_devnode(spu);
0433         if (spu_dn == avoid)
0434             continue;
0435         vic_handles = of_get_property(spu_dn, "vicinity", &lenp);
0436         for (i=0; i < (lenp / sizeof(phandle)); i++) {
0437             if (vic_handles[i] == target->phandle)
0438                 return spu;
0439         }
0440     }
0441     return NULL;
0442 }
0443 
0444 static void __init init_affinity_node(int cbe)
0445 {
0446     struct spu *spu, *last_spu;
0447     struct device_node *vic_dn, *last_spu_dn;
0448     phandle avoid_ph;
0449     const phandle *vic_handles;
0450     int lenp, i, added;
0451 
0452     last_spu = list_first_entry(&cbe_spu_info[cbe].spus, struct spu,
0453                                 cbe_list);
0454     avoid_ph = 0;
0455     for (added = 1; added < cbe_spu_info[cbe].n_spus; added++) {
0456         last_spu_dn = spu_devnode(last_spu);
0457         vic_handles = of_get_property(last_spu_dn, "vicinity", &lenp);
0458 
0459         /*
0460          * Walk through each phandle in vicinity property of the spu
0461          * (typically two vicinity phandles per spe node)
0462          */
0463         for (i = 0; i < (lenp / sizeof(phandle)); i++) {
0464             if (vic_handles[i] == avoid_ph)
0465                 continue;
0466 
0467             vic_dn = of_find_node_by_phandle(vic_handles[i]);
0468             if (!vic_dn)
0469                 continue;
0470 
0471             if (of_node_name_eq(vic_dn, "spe") ) {
0472                 spu = devnode_spu(cbe, vic_dn);
0473                 avoid_ph = last_spu_dn->phandle;
0474             } else {
0475                 /*
0476                  * "mic-tm" and "bif0" nodes do not have
0477                  * vicinity property. So we need to find the
0478                  * spe which has vic_dn as neighbour, but
0479                  * skipping the one we came from (last_spu_dn)
0480                  */
0481                 spu = neighbour_spu(cbe, vic_dn, last_spu_dn);
0482                 if (!spu)
0483                     continue;
0484                 if (of_node_name_eq(vic_dn, "mic-tm")) {
0485                     last_spu->has_mem_affinity = 1;
0486                     spu->has_mem_affinity = 1;
0487                 }
0488                 avoid_ph = vic_dn->phandle;
0489             }
0490 
0491             list_add_tail(&spu->aff_list, &last_spu->aff_list);
0492             last_spu = spu;
0493             break;
0494         }
0495     }
0496 }
0497 
0498 static void __init init_affinity_fw(void)
0499 {
0500     int cbe;
0501 
0502     for (cbe = 0; cbe < MAX_NUMNODES; cbe++)
0503         init_affinity_node(cbe);
0504 }
0505 
0506 static int __init init_affinity(void)
0507 {
0508     if (of_has_vicinity()) {
0509         init_affinity_fw();
0510     } else {
0511         if (of_machine_is_compatible("IBM,CPBW-1.0"))
0512             init_affinity_qs20_harcoded();
0513         else
0514             printk("No affinity configuration found\n");
0515     }
0516 
0517     return 0;
0518 }
0519 
0520 const struct spu_management_ops spu_management_of_ops = {
0521     .enumerate_spus = of_enumerate_spus,
0522     .create_spu = of_create_spu,
0523     .destroy_spu = of_destroy_spu,
0524     .enable_spu = enable_spu_by_master_run,
0525     .disable_spu = disable_spu_by_master_run,
0526     .init_affinity = init_affinity,
0527 };