cregit-Linux how code gets into the kernel

Release 4.14 arch/powerpc/platforms/cell/spu_manage.c

/*
 * spu management operations for of based platforms
 *
 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
 * Copyright 2006 Sony Corp.
 * (C) Copyright 2007 TOSHIBA CORPORATION
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/export.h>
#include <linux/ptrace.h>
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/io.h>
#include <linux/mutex.h>
#include <linux/device.h>

#include <asm/spu.h>
#include <asm/spu_priv1.h>
#include <asm/firmware.h>
#include <asm/prom.h>

#include "spufs/spufs.h"
#include "interrupt.h"


struct device_node *spu_devnode(struct spu *spu) { return spu->devnode; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou17100.00%1100.00%
Total17100.00%1100.00%

EXPORT_SYMBOL_GPL(spu_devnode);
static u64 __init find_spu_unit_number(struct device_node *spe) { const unsigned int *prop; int proplen; /* new device trees should provide the physical-id attribute */ prop = of_get_property(spe, "physical-id", &proplen); if (proplen == 4) return (u64)*prop; /* celleb device tree provides the unit-id */ prop = of_get_property(spe, "unit-id", &proplen); if (proplen == 4) return (u64)*prop; /* legacy device trees provide the id in the reg attribute */ prop = of_get_property(spe, "reg", &proplen); if (proplen == 4) return (u64)*prop; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou7169.61%125.00%
Christian Krafft2928.43%250.00%
Stephen Rothwell21.96%125.00%
Total102100.00%4100.00%


static void spu_unmap(struct spu *spu) { if (!firmware_has_feature(FW_FEATURE_LPAR)) iounmap(spu->priv1); iounmap(spu->priv2); iounmap(spu->problem); iounmap((__force u8 __iomem *)spu->local_store); }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou53100.00%1100.00%
Total53100.00%1100.00%


static int __init spu_map_interrupts_old(struct spu *spu, struct device_node *np) { unsigned int isrc; const u32 *tmp; int nid; /* Get the interrupt source unit from the device-tree */ tmp = of_get_property(np, "isrc", NULL); if (!tmp) return -ENODEV; isrc = tmp[0]; tmp = of_get_property(np->parent->parent, "node-id", NULL); if (!tmp) { printk(KERN_WARNING "%s: can't find node-id\n", __func__); nid = spu->node; } else nid = tmp[0]; /* Add the node number */ isrc |= nid << IIC_IRQ_NODE_SHIFT; /* Now map interrupts of all 3 classes */ spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc); spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); /* Right now, we only fail if class 2 failed */ if (!spu->irqs[2]) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou16594.29%125.00%
Michael Ellerman74.00%125.00%
Stephen Rothwell21.14%125.00%
Harvey Harrison10.57%125.00%
Total175100.00%4100.00%


static void __iomem * __init spu_map_prop_old(struct spu *spu, struct device_node *n, const char *name) { const struct address_prop { unsigned long address; unsigned int len; } __attribute__((packed)) *prop; int proplen; prop = of_get_property(n, name, &proplen); if (prop == NULL || proplen != sizeof (struct address_prop)) return NULL; return ioremap(prop->address, prop->len); }

Contributors

PersonTokensPropCommitsCommitProp
Benjamin Herrenschmidt8998.89%150.00%
Stephen Rothwell11.11%150.00%
Total90100.00%2100.00%


static int __init spu_map_device_old(struct spu *spu) { struct device_node *node = spu->devnode; const char *prop; int ret; ret = -ENODEV; spu->name = of_get_property(node, "name", NULL); if (!spu->name) goto out; prop = of_get_property(node, "local-store", NULL); if (!prop) goto out; spu->local_store_phys = *(unsigned long *)prop; /* we use local store as ram, not io memory */ spu->local_store = (void __force *) spu_map_prop_old(spu, node, "local-store"); if (!spu->local_store) goto out; prop = of_get_property(node, "problem", NULL); if (!prop) goto out_unmap; spu->problem_phys = *(unsigned long *)prop; spu->problem = spu_map_prop_old(spu, node, "problem"); if (!spu->problem) goto out_unmap; spu->priv2 = spu_map_prop_old(spu, node, "priv2"); if (!spu->priv2) goto out_unmap; if (!firmware_has_feature(FW_FEATURE_LPAR)) { spu->priv1 = spu_map_prop_old(spu, node, "priv1"); if (!spu->priv1) goto out_unmap; } ret = 0; goto out; out_unmap: spu_unmap(spu); out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou23997.15%133.33%
Benjamin Herrenschmidt41.63%133.33%
Stephen Rothwell31.22%133.33%
Total246100.00%3100.00%


static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) { struct of_phandle_args oirq; int ret; int i; for (i=0; i < 3; i++) { ret = of_irq_parse_one(np, i, &oirq); if (ret) { pr_debug("spu_new: failed to get irq %d\n", i); goto err; } ret = -EINVAL; pr_debug(" irq %d no 0x%x on %pOF\n", i, oirq.args[0], oirq.np); spu->irqs[i] = irq_create_of_mapping(&oirq); if (!spu->irqs[i]) { pr_debug("spu_new: failed to map it !\n"); goto err; } } return 0; err: pr_debug("failed to map irq %x for spu %s\n", *oirq.args, spu->name); for (; i >= 0; i--) { if (spu->irqs[i]) irq_dispose_mapping(spu->irqs[i]); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou17195.53%116.67%
Grant C. Likely63.35%350.00%
Rob Herring10.56%116.67%
Michael Ellerman10.56%116.67%
Total179100.00%6100.00%


static int spu_map_resource(struct spu *spu, int nr, void __iomem** virt, unsigned long *phys) { struct device_node *np = spu->devnode; struct resource resource = { }; unsigned long len; int ret; ret = of_address_to_resource(np, nr, &resource); if (ret) return ret; if (phys) *phys = resource.start; len = resource_size(&resource); *virt = ioremap(resource.start, len); if (!*virt) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou10090.91%133.33%
Benjamin Herrenschmidt65.45%133.33%
Joe Perches43.64%133.33%
Total110100.00%3100.00%


static int __init spu_map_device(struct spu *spu) { struct device_node *np = spu->devnode; int ret = -ENODEV; spu->name = of_get_property(np, "name", NULL); if (!spu->name) goto out; ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store, &spu->local_store_phys); if (ret) { pr_debug("spu_new: failed to map %pOF resource 0\n", np); goto out; } ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem, &spu->problem_phys); if (ret) { pr_debug("spu_new: failed to map %pOF resource 1\n", np); goto out_unmap; } ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL); if (ret) { pr_debug("spu_new: failed to map %pOF resource 2\n", np); goto out_unmap; } if (!firmware_has_feature(FW_FEATURE_LPAR)) ret = spu_map_resource(spu, 3, (void __iomem**)&spu->priv1, NULL); if (ret) { pr_debug("spu_new: failed to map %pOF resource 3\n", np); goto out_unmap; } pr_debug("spu_new: %pOF maps:\n", np); pr_debug(" local store : 0x%016lx -> 0x%p\n", spu->local_store_phys, spu->local_store); pr_debug(" problem state : 0x%016lx -> 0x%p\n", spu->problem_phys, spu->problem); pr_debug(" priv2 : 0x%p\n", spu->priv2); pr_debug(" priv1 : 0x%p\n", spu->priv1); return 0; out_unmap: spu_unmap(spu); out: pr_debug("failed to map spe %s: %d\n", spu->name, ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou28797.95%133.33%
Rob Herring51.71%133.33%
Stephen Rothwell10.34%133.33%
Total293100.00%3100.00%


static int __init of_enumerate_spus(int (*fn)(void *data)) { int ret; struct device_node *node; unsigned int n = 0; ret = -ENODEV; for (node = of_find_node_by_type(NULL, "spe"); node; node = of_find_node_by_type(node, "spe")) { ret = fn(node); if (ret) { printk(KERN_WARNING "%s: Error initializing %s\n", __func__, node->name); break; } n++; } return ret ? ret : n; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou8385.57%133.33%
Geert Uytterhoeven1313.40%133.33%
Harvey Harrison11.03%133.33%
Total97100.00%3100.00%


static int __init of_create_spu(struct spu *spu, void *data) { int ret; struct device_node *spe = (struct device_node *)data; static int legacy_map = 0, legacy_irq = 0; spu->devnode = of_node_get(spe); spu->spe_id = find_spu_unit_number(spe); spu->node = of_node_to_nid(spe); if (spu->node >= MAX_NUMNODES) { printk(KERN_WARNING "SPE %pOF on node %d ignored," " node number too big\n", spe, spu->node); printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n"); ret = -ENODEV; goto out; } ret = spu_map_device(spu); if (ret) { if (!legacy_map) { legacy_map = 1; printk(KERN_WARNING "%s: Legacy device tree found, " "trying to map old style\n", __func__); } ret = spu_map_device_old(spu); if (ret) { printk(KERN_ERR "Unable to map %s\n", spu->name); goto out; } } ret = spu_map_interrupts(spu, spe); if (ret) { if (!legacy_irq) { legacy_irq = 1; printk(KERN_WARNING "%s: Legacy device tree found, " "trying old style irq\n", __func__); } ret = spu_map_interrupts_old(spu, spe); if (ret) { printk(KERN_ERR "%s: could not map interrupts\n", spu->name); goto out_unmap; } } pr_debug("Using SPE %s %p %p %p %p %d\n", spu->name, spu->local_store, spu->problem, spu->priv1, spu->priv2, spu->number); goto out; out_unmap: spu_unmap(spu); out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou26898.89%250.00%
Harvey Harrison20.74%125.00%
Rob Herring10.37%125.00%
Total271100.00%4100.00%


static int of_destroy_spu(struct spu *spu) { spu_unmap(spu); of_node_put(spu->devnode); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou26100.00%1100.00%
Total26100.00%1100.00%


static void enable_spu_by_master_run(struct spu_context *ctx) { ctx->ops->master_start(ctx); }

Contributors

PersonTokensPropCommitsCommitProp
Masato Noguchi20100.00%1100.00%
Total20100.00%1100.00%


static void disable_spu_by_master_run(struct spu_context *ctx) { ctx->ops->master_stop(ctx); }

Contributors

PersonTokensPropCommitsCommitProp
Masato Noguchi20100.00%1100.00%
Total20100.00%1100.00%

/* Hardcoded affinity idxs for qs20 */ #define QS20_SPES_PER_BE 8 static int qs20_reg_idxs[QS20_SPES_PER_BE] = { 0, 2, 4, 6, 7, 5, 3, 1 }; static int qs20_reg_memory[QS20_SPES_PER_BE] = { 1, 1, 0, 0, 0, 0, 0, 0 };
static struct spu *spu_lookup_reg(int node, u32 reg) { struct spu *spu; const u32 *spu_reg; list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) { spu_reg = of_get_property(spu_devnode(spu), "reg", NULL); if (*spu_reg == reg) return spu; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Andre Detsch6098.36%150.00%
Jeremy Kerr11.64%150.00%
Total61100.00%2100.00%


static void init_affinity_qs20_harcoded(void) { int node, i; struct spu *last_spu, *spu; u32 reg; for (node = 0; node < MAX_NUMNODES; node++) { last_spu = NULL; for (i = 0; i < QS20_SPES_PER_BE; i++) { reg = qs20_reg_idxs[i]; spu = spu_lookup_reg(node, reg); if (!spu) continue; spu->has_mem_affinity = qs20_reg_memory[reg]; if (last_spu) list_add_tail(&spu->aff_list, &last_spu->aff_list); last_spu = spu; } } }

Contributors

PersonTokensPropCommitsCommitProp
Andre Detsch110100.00%1100.00%
Total110100.00%1100.00%


static int of_has_vicinity(void) { struct device_node *dn; for_each_node_by_type(dn, "spe") { if (of_find_property(dn, "vicinity", NULL)) { of_node_put(dn); return 1; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andre Detsch45100.00%2100.00%
Total45100.00%2100.00%


static struct spu *devnode_spu(int cbe, struct device_node *dn) { struct spu *spu; list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list) if (spu_devnode(spu) == dn) return spu; return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Andre Detsch44100.00%1100.00%
Total44100.00%1100.00%


static struct spu * neighbour_spu(int cbe, struct device_node *target, struct device_node *avoid) { struct spu *spu; struct device_node *spu_dn; const phandle *vic_handles; int lenp, i; list_for_each_entry(spu, &cbe_spu_info[cbe].spus, cbe_list) { spu_dn = spu_devnode(spu); if (spu_dn == avoid) continue; vic_handles = of_get_property(spu_dn, "vicinity", &lenp); for (i=0; i < (lenp / sizeof(phandle)); i++) { if (vic_handles[i] == target->phandle) return spu; } } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Andre Detsch11599.14%150.00%
Grant C. Likely10.86%150.00%
Total116100.00%2100.00%


static void init_affinity_node(int cbe) { struct spu *spu, *last_spu; struct device_node *vic_dn, *last_spu_dn; phandle avoid_ph; const phandle *vic_handles; const char *name; int lenp, i, added; last_spu = list_first_entry(&cbe_spu_info[cbe].spus, struct spu, cbe_list); avoid_ph = 0; for (added = 1; added < cbe_spu_info[cbe].n_spus; added++) { last_spu_dn = spu_devnode(last_spu); vic_handles = of_get_property(last_spu_dn, "vicinity", &lenp); /* * Walk through each phandle in vicinity property of the spu * (tipically two vicinity phandles per spe node) */ for (i = 0; i < (lenp / sizeof(phandle)); i++) { if (vic_handles[i] == avoid_ph) continue; vic_dn = of_find_node_by_phandle(vic_handles[i]); if (!vic_dn) continue; /* a neighbour might be spe, mic-tm, or bif0 */ name = of_get_property(vic_dn, "name", NULL); if (!name) continue; if (strcmp(name, "spe") == 0) { spu = devnode_spu(cbe, vic_dn); avoid_ph = last_spu_dn->phandle; } else { /* * "mic-tm" and "bif0" nodes do not have * vicinity property. So we need to find the * spe which has vic_dn as neighbour, but * skipping the one we came from (last_spu_dn) */ spu = neighbour_spu(cbe, vic_dn, last_spu_dn); if (!spu) continue; if (!strcmp(name, "mic-tm")) { last_spu->has_mem_affinity = 1; spu->has_mem_affinity = 1; } avoid_ph = vic_dn->phandle; } list_add_tail(&spu->aff_list, &last_spu->aff_list); last_spu = spu; break; } } }

Contributors

PersonTokensPropCommitsCommitProp
Andre Detsch26899.26%150.00%
Grant C. Likely20.74%150.00%
Total270100.00%2100.00%


static void init_affinity_fw(void) { int cbe; for (cbe = 0; cbe < MAX_NUMNODES; cbe++) init_affinity_node(cbe); }

Contributors

PersonTokensPropCommitsCommitProp
Andre Detsch29100.00%1100.00%
Total29100.00%1100.00%


static int __init init_affinity(void) { if (of_has_vicinity()) { init_affinity_fw(); } else { if (of_machine_is_compatible("IBM,CPBW-1.0")) init_affinity_qs20_harcoded(); else printk("No affinity configuration found\n"); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Andre Detsch3995.12%133.33%
Ishizaki Kou12.44%133.33%
Benjamin Herrenschmidt12.44%133.33%
Total41100.00%3100.00%

const struct spu_management_ops spu_management_of_ops = { .enumerate_spus = of_enumerate_spus, .create_spu = of_create_spu, .destroy_spu = of_destroy_spu, .enable_spu = enable_spu_by_master_run, .disable_spu = disable_spu_by_master_run, .init_affinity = init_affinity, };

Overall Contributors

PersonTokensPropCommitsCommitProp
Ishizaki Kou155060.59%29.52%
Andre Detsch77030.10%29.52%
Benjamin Herrenschmidt1003.91%29.52%
Masato Noguchi532.07%14.76%
Christian Krafft291.13%29.52%
Geert Uytterhoeven130.51%14.76%
Grant C. Likely90.35%419.05%
Stephen Rothwell90.35%14.76%
Michael Ellerman80.31%14.76%
Rob Herring70.27%14.76%
Harvey Harrison40.16%14.76%
Joe Perches40.16%14.76%
Paul Gortmaker10.04%14.76%
Jeremy Kerr10.04%14.76%
Total2558100.00%21100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.