spu_base.c

来自「linux2.6.16版本」· C语言 代码 · 共 712 行 · 第 1/2 页

C
712
字号
		{ 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);	}}struct spu *spu_alloc(void){	struct spu *spu;	down(&spu_mutex);	if (!list_empty(&spu_list)) {		spu = list_entry(spu_list.next, struct spu, list);		list_del_init(&spu->list);		pr_debug("Got SPU %x %d\n", spu->isrc, spu->number);	} else {		pr_debug("No SPU left\n");		spu = NULL;	}	up(&spu_mutex);	if (spu)		spu_init_channels(spu);	return spu;}EXPORT_SYMBOL_GPL(spu_alloc);void spu_free(struct spu *spu){	down(&spu_mutex);	list_add_tail(&spu->list, &spu_list);	up(&spu_mutex);}EXPORT_SYMBOL_GPL(spu_free);static int spu_handle_mm_fault(struct spu *spu){	struct mm_struct *mm = spu->mm;	struct vm_area_struct *vma;	u64 ea, dsisr, is_write;	int ret;	ea = spu->dar;	dsisr = spu->dsisr;#if 0	if (!IS_VALID_EA(ea)) {		return -EFAULT;	}#endif /* XXX */	if (mm == NULL) {		return -EFAULT;	}	if (mm->pgd == NULL) {		return -EFAULT;	}	down_read(&mm->mmap_sem);	vma = find_vma(mm, ea);	if (!vma)		goto bad_area;	if (vma->vm_start <= ea)		goto good_area;	if (!(vma->vm_flags & VM_GROWSDOWN))		goto bad_area;#if 0	if (expand_stack(vma, ea))		goto bad_area;#endif /* XXX */good_area:	is_write = dsisr & MFC_DSISR_ACCESS_PUT;	if (is_write) {		if (!(vma->vm_flags & VM_WRITE))			goto bad_area;	} else {		if (dsisr & MFC_DSISR_ACCESS_DENIED)			goto bad_area;		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))			goto bad_area;	}	ret = 0;	switch (handle_mm_fault(mm, vma, ea, is_write)) {	case VM_FAULT_MINOR:		current->min_flt++;		break;	case VM_FAULT_MAJOR:		current->maj_flt++;		break;	case VM_FAULT_SIGBUS:		ret = -EFAULT;		goto bad_area;	case VM_FAULT_OOM:		ret = -ENOMEM;		goto bad_area;	default:		BUG();	}	up_read(&mm->mmap_sem);	return ret;bad_area:	up_read(&mm->mmap_sem);	return -EFAULT;}int spu_irq_class_1_bottom(struct spu *spu){	u64 ea, dsisr, access, error = 0UL;	int ret = 0;	ea = spu->dar;	dsisr = spu->dsisr;	if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {		access = (_PAGE_PRESENT | _PAGE_USER);		access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;		if (hash_page(ea, access, 0x300) != 0)			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;	}	if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) ||	    (dsisr & MFC_DSISR_ACCESS_DENIED)) {		if ((ret = spu_handle_mm_fault(spu)) != 0)			error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;		else			error &= ~CLASS1_ENABLE_STORAGE_FAULT_INTR;	}	spu->dar = 0UL;	spu->dsisr = 0UL;	if (!error) {		spu_restart_dma(spu);	} else {		__spu_trap_invalid_dma(spu);	}	return ret;}void spu_irq_setaffinity(struct spu *spu, int cpu){	u64 target = iic_get_target_id(cpu);	u64 route = target << 48 | target << 32 | target << 16;	spu_int_route_set(spu, route);}EXPORT_SYMBOL_GPL(spu_irq_setaffinity);static void __iomem * __init map_spe_prop(struct device_node *n,						 const char *name){	struct address_prop {		unsigned long address;		unsigned int len;	} __attribute__((packed)) *prop;	void *p;	int proplen;	p = get_property(n, name, &proplen);	if (proplen != sizeof (struct address_prop))		return NULL;	prop = p;	return ioremap(prop->address, prop->len);}static void spu_unmap(struct spu *spu){	iounmap(spu->priv2);	iounmap(spu->priv1);	iounmap(spu->problem);	iounmap((u8 __iomem *)spu->local_store);}static int __init spu_map_device(struct spu *spu, struct device_node *spe){	char *prop;	int ret;	ret = -ENODEV;	prop = get_property(spe, "isrc", NULL);	if (!prop)		goto out;	spu->isrc = *(unsigned int *)prop;	spu->name = get_property(spe, "name", NULL);	if (!spu->name)		goto out;	prop = get_property(spe, "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 *)map_spe_prop(spe, "local-store");	if (!spu->local_store)		goto out;	spu->problem= map_spe_prop(spe, "problem");	if (!spu->problem)		goto out_unmap;	spu->priv1= map_spe_prop(spe, "priv1");	/* priv1 is not available on a hypervisor */	spu->priv2= map_spe_prop(spe, "priv2");	if (!spu->priv2)		goto out_unmap;	ret = 0;	goto out;out_unmap:	spu_unmap(spu);out:	return ret;}static int __init find_spu_node_id(struct device_node *spe){	unsigned int *id;	struct device_node *cpu;	cpu = spe->parent->parent;	id = (unsigned int *)get_property(cpu, "node-id", NULL);	return id ? *id : 0;}static int __init create_spu(struct device_node *spe){	struct spu *spu;	int ret;	static int number;	ret = -ENOMEM;	spu = kmalloc(sizeof (*spu), GFP_KERNEL);	if (!spu)		goto out;	ret = spu_map_device(spu, spe);	if (ret)		goto out_free;	spu->node = find_spu_node_id(spe);	spu->stop_code = 0;	spu->slb_replace = 0;	spu->mm = NULL;	spu->ctx = NULL;	spu->rq = NULL;	spu->pid = 0;	spu->class_0_pending = 0;	spu->flags = 0UL;	spu->dar = 0UL;	spu->dsisr = 0UL;	spin_lock_init(&spu->register_lock);	spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));	spu_mfc_sr1_set(spu, 0x33);	spu->ibox_callback = NULL;	spu->wbox_callback = NULL;	spu->stop_callback = NULL;	down(&spu_mutex);	spu->number = number++;	ret = spu_request_irqs(spu);	if (ret)		goto out_unmap;	list_add(&spu->list, &spu_list);	up(&spu_mutex);	pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",		spu->name, spu->isrc, spu->local_store,		spu->problem, spu->priv1, spu->priv2, spu->number);	goto out;out_unmap:	up(&spu_mutex);	spu_unmap(spu);out_free:	kfree(spu);out:	return ret;}static void destroy_spu(struct spu *spu){	list_del_init(&spu->list);	spu_free_irqs(spu);	spu_unmap(spu);	kfree(spu);}static void cleanup_spu_base(void){	struct spu *spu, *tmp;	down(&spu_mutex);	list_for_each_entry_safe(spu, tmp, &spu_list, list)		destroy_spu(spu);	up(&spu_mutex);}module_exit(cleanup_spu_base);static int __init init_spu_base(void){	struct device_node *node;	int ret;	ret = -ENODEV;	for (node = of_find_node_by_type(NULL, "spe");			node; node = of_find_node_by_type(node, "spe")) {		ret = create_spu(node);		if (ret) {			printk(KERN_WARNING "%s: Error initializing %s\n",				__FUNCTION__, node->name);			cleanup_spu_base();			break;		}	}	/* in some old firmware versions, the spe is called 'spc', so we	   look for that as well */	for (node = of_find_node_by_type(NULL, "spc");			node; node = of_find_node_by_type(node, "spc")) {		ret = create_spu(node);		if (ret) {			printk(KERN_WARNING "%s: Error initializing %s\n",				__FUNCTION__, node->name);			cleanup_spu_base();			break;		}	}	return ret;}module_init(init_spu_base);MODULE_LICENSE("GPL");MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?