📄 spu_base.c
字号:
if (stat & 4) /* SPU halted */ spu->stop_callback(spu); if (stat & 8) /* DMA tag group complete */ spu->mfc_callback(spu); if (stat & 0x10) /* SPU mailbox threshold */ spu->wbox_callback(spu); spu->stats.class2_intr++; return stat ? IRQ_HANDLED : IRQ_NONE;}static int spu_request_irqs(struct spu *spu){ int ret = 0; if (spu->irqs[0] != NO_IRQ) { snprintf(spu->irq_c0, sizeof (spu->irq_c0), "spe%02d.0", spu->number); ret = request_irq(spu->irqs[0], spu_irq_class_0, IRQF_DISABLED, spu->irq_c0, spu); if (ret) goto bail0; } if (spu->irqs[1] != NO_IRQ) { snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number); ret = request_irq(spu->irqs[1], spu_irq_class_1, IRQF_DISABLED, spu->irq_c1, spu); if (ret) goto bail1; } if (spu->irqs[2] != NO_IRQ) { snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number); ret = request_irq(spu->irqs[2], spu_irq_class_2, IRQF_DISABLED, spu->irq_c2, spu); if (ret) goto bail2; } return 0;bail2: if (spu->irqs[1] != NO_IRQ) free_irq(spu->irqs[1], spu);bail1: if (spu->irqs[0] != NO_IRQ) free_irq(spu->irqs[0], spu);bail0: return ret;}static void spu_free_irqs(struct spu *spu){ if (spu->irqs[0] != NO_IRQ) free_irq(spu->irqs[0], spu); if (spu->irqs[1] != NO_IRQ) free_irq(spu->irqs[1], spu); if (spu->irqs[2] != NO_IRQ) free_irq(spu->irqs[2], spu);}void spu_init_channels(struct spu *spu){ static const struct { unsigned channel; unsigned count; } zero_list[] = { { 0x00, 1, }, { 0x01, 1, }, { 0x03, 1, }, { 0x04, 1, }, { 0x18, 1, }, { 0x19, 1, }, { 0x1b, 1, }, { 0x1d, 1, }, }, count_list[] = { { 0x00, 0, }, { 0x03, 0, }, { 0x04, 0, }, { 0x15, 16, }, { 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, }, { 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, }, }; struct spu_priv2 __iomem *priv2; int i; priv2 = spu->priv2; /* initialize all channel data to zero */ for (i = 0; i < ARRAY_SIZE(zero_list); i++) { int count; out_be64(&priv2->spu_chnlcntptr_RW, zero_list[i].channel); for (count = 0; count < zero_list[i].count; count++) out_be64(&priv2->spu_chnldata_RW, 0); } /* initialize channel counts to meaningful values */ for (i = 0; i < ARRAY_SIZE(count_list); i++) { out_be64(&priv2->spu_chnlcntptr_RW, count_list[i].channel); out_be64(&priv2->spu_chnlcnt_RW, count_list[i].count); }}EXPORT_SYMBOL_GPL(spu_init_channels);static int spu_shutdown(struct sys_device *sysdev){ struct spu *spu = container_of(sysdev, struct spu, sysdev); spu_free_irqs(spu); spu_destroy_spu(spu); return 0;}static struct sysdev_class spu_sysdev_class = { set_kset_name("spu"), .shutdown = spu_shutdown,};int spu_add_sysdev_attr(struct sysdev_attribute *attr){ struct spu *spu; mutex_lock(&spu_full_list_mutex); list_for_each_entry(spu, &spu_full_list, full_list) sysdev_create_file(&spu->sysdev, attr); mutex_unlock(&spu_full_list_mutex); return 0;}EXPORT_SYMBOL_GPL(spu_add_sysdev_attr);int spu_add_sysdev_attr_group(struct attribute_group *attrs){ struct spu *spu; mutex_lock(&spu_full_list_mutex); list_for_each_entry(spu, &spu_full_list, full_list) sysfs_create_group(&spu->sysdev.kobj, attrs); mutex_unlock(&spu_full_list_mutex); return 0;}EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group);void spu_remove_sysdev_attr(struct sysdev_attribute *attr){ struct spu *spu; mutex_lock(&spu_full_list_mutex); list_for_each_entry(spu, &spu_full_list, full_list) sysdev_remove_file(&spu->sysdev, attr); mutex_unlock(&spu_full_list_mutex);}EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr);void spu_remove_sysdev_attr_group(struct attribute_group *attrs){ struct spu *spu; mutex_lock(&spu_full_list_mutex); list_for_each_entry(spu, &spu_full_list, full_list) sysfs_remove_group(&spu->sysdev.kobj, attrs); mutex_unlock(&spu_full_list_mutex);}EXPORT_SYMBOL_GPL(spu_remove_sysdev_attr_group);static int spu_create_sysdev(struct spu *spu){ int ret; spu->sysdev.id = spu->number; spu->sysdev.cls = &spu_sysdev_class; ret = sysdev_register(&spu->sysdev); if (ret) { printk(KERN_ERR "Can't register SPU %d with sysfs\n", spu->number); return ret; } sysfs_add_device_to_node(&spu->sysdev, spu->node); return 0;}static int __init create_spu(void *data){ struct spu *spu; int ret; static int number; unsigned long flags; struct timespec ts; ret = -ENOMEM; spu = kzalloc(sizeof (*spu), GFP_KERNEL); if (!spu) goto out; spu->alloc_state = SPU_FREE; spin_lock_init(&spu->register_lock); spin_lock(&spu_lock); spu->number = number++; spin_unlock(&spu_lock); ret = spu_create_spu(spu, data); if (ret) goto out_free; spu_mfc_sdr_setup(spu); spu_mfc_sr1_set(spu, 0x33); ret = spu_request_irqs(spu); if (ret) goto out_destroy; ret = spu_create_sysdev(spu); if (ret) goto out_free_irqs; mutex_lock(&cbe_spu_info[spu->node].list_mutex); list_add(&spu->cbe_list, &cbe_spu_info[spu->node].spus); cbe_spu_info[spu->node].n_spus++; mutex_unlock(&cbe_spu_info[spu->node].list_mutex); mutex_lock(&spu_full_list_mutex); spin_lock_irqsave(&spu_full_list_lock, flags); list_add(&spu->full_list, &spu_full_list); spin_unlock_irqrestore(&spu_full_list_lock, flags); mutex_unlock(&spu_full_list_mutex); spu->stats.util_state = SPU_UTIL_IDLE_LOADED; ktime_get_ts(&ts); spu->stats.tstamp = timespec_to_ns(&ts); INIT_LIST_HEAD(&spu->aff_list); goto out;out_free_irqs: spu_free_irqs(spu);out_destroy: spu_destroy_spu(spu);out_free: kfree(spu);out: return ret;}static const char *spu_state_names[] = { "user", "system", "iowait", "idle"};static unsigned long long spu_acct_time(struct spu *spu, enum spu_utilization_state state){ struct timespec ts; unsigned long long time = spu->stats.times[state]; /* * If the spu is idle or the context is stopped, utilization * statistics are not updated. Apply the time delta from the * last recorded state of the spu. */ if (spu->stats.util_state == state) { ktime_get_ts(&ts); time += timespec_to_ns(&ts) - spu->stats.tstamp; } return time / NSEC_PER_MSEC;}static ssize_t spu_stat_show(struct sys_device *sysdev, char *buf){ struct spu *spu = container_of(sysdev, struct spu, sysdev); return sprintf(buf, "%s %llu %llu %llu %llu " "%llu %llu %llu %llu %llu %llu %llu %llu\n", spu_state_names[spu->stats.util_state], spu_acct_time(spu, SPU_UTIL_USER), spu_acct_time(spu, SPU_UTIL_SYSTEM), spu_acct_time(spu, SPU_UTIL_IOWAIT), spu_acct_time(spu, SPU_UTIL_IDLE_LOADED), spu->stats.vol_ctx_switch, spu->stats.invol_ctx_switch, spu->stats.slb_flt, spu->stats.hash_flt, spu->stats.min_flt, spu->stats.maj_flt, spu->stats.class2_intr, spu->stats.libassist);}static SYSDEV_ATTR(stat, 0644, spu_stat_show, NULL);static int __init init_spu_base(void){ int i, ret = 0; for (i = 0; i < MAX_NUMNODES; i++) { mutex_init(&cbe_spu_info[i].list_mutex); INIT_LIST_HEAD(&cbe_spu_info[i].spus); } if (!spu_management_ops) goto out; /* create sysdev class for spus */ ret = sysdev_class_register(&spu_sysdev_class); if (ret) goto out; ret = spu_enumerate_spus(create_spu); if (ret < 0) { printk(KERN_WARNING "%s: Error initializing spus\n", __FUNCTION__); goto out_unregister_sysdev_class; } if (ret > 0) { /* * We cannot put the forward declaration in * <linux/linux_logo.h> because of conflicting session type * conflicts for const and __initdata with different compiler * versions */ extern const struct linux_logo logo_spe_clut224; fb_append_extra_logo(&logo_spe_clut224, ret); } mutex_lock(&spu_full_list_mutex); xmon_register_spus(&spu_full_list); crash_register_spus(&spu_full_list); mutex_unlock(&spu_full_list_mutex); spu_add_sysdev_attr(&attr_stat); spu_init_affinity(); return 0; out_unregister_sysdev_class: sysdev_class_unregister(&spu_sysdev_class); out: return ret;}module_init(init_spu_base);MODULE_LICENSE("GPL");MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -