int ia64_itr_entry()

in mm/tlb.c [454:546]


int ia64_itr_entry(u64 target_mask, u64 va, u64 pte, u64 log_size)
{
	int i, r;
	unsigned long psr;
	struct ia64_tr_entry *p;
	int cpu = smp_processor_id();

	if (!ia64_idtrs[cpu]) {
		ia64_idtrs[cpu] = kmalloc_array(2 * IA64_TR_ALLOC_MAX,
						sizeof(struct ia64_tr_entry),
						GFP_KERNEL);
		if (!ia64_idtrs[cpu])
			return -ENOMEM;
	}
	r = -EINVAL;
	/*Check overlap with existing TR entries*/
	if (target_mask & 0x1) {
		p = ia64_idtrs[cpu];
		for (i = IA64_TR_ALLOC_BASE; i <= per_cpu(ia64_tr_used, cpu);
								i++, p++) {
			if (p->pte & 0x1)
				if (is_tr_overlap(p, va, log_size)) {
					printk(KERN_DEBUG "Overlapped Entry"
						"Inserted for TR Register!!\n");
					goto out;
			}
		}
	}
	if (target_mask & 0x2) {
		p = ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX;
		for (i = IA64_TR_ALLOC_BASE; i <= per_cpu(ia64_tr_used, cpu);
								i++, p++) {
			if (p->pte & 0x1)
				if (is_tr_overlap(p, va, log_size)) {
					printk(KERN_DEBUG "Overlapped Entry"
						"Inserted for TR Register!!\n");
					goto out;
				}
		}
	}

	for (i = IA64_TR_ALLOC_BASE; i < per_cpu(ia64_tr_num, cpu); i++) {
		switch (target_mask & 0x3) {
		case 1:
			if (!((ia64_idtrs[cpu] + i)->pte & 0x1))
				goto found;
			continue;
		case 2:
			if (!((ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX + i)->pte & 0x1))
				goto found;
			continue;
		case 3:
			if (!((ia64_idtrs[cpu] + i)->pte & 0x1) &&
			    !((ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX + i)->pte & 0x1))
				goto found;
			continue;
		default:
			r = -EINVAL;
			goto out;
		}
	}
found:
	if (i >= per_cpu(ia64_tr_num, cpu))
		return -EBUSY;

	/*Record tr info for mca hander use!*/
	if (i > per_cpu(ia64_tr_used, cpu))
		per_cpu(ia64_tr_used, cpu) = i;

	psr = ia64_clear_ic();
	if (target_mask & 0x1) {
		ia64_itr(0x1, i, va, pte, log_size);
		ia64_srlz_i();
		p = ia64_idtrs[cpu] + i;
		p->ifa = va;
		p->pte = pte;
		p->itir = log_size << 2;
		p->rr = ia64_get_rr(va);
	}
	if (target_mask & 0x2) {
		ia64_itr(0x2, i, va, pte, log_size);
		ia64_srlz_i();
		p = ia64_idtrs[cpu] + IA64_TR_ALLOC_MAX + i;
		p->ifa = va;
		p->pte = pte;
		p->itir = log_size << 2;
		p->rr = ia64_get_rr(va);
	}
	ia64_set_psr(psr);
	r = i;
out:
	return r;
}