vcpu = kvm_get_vcpu_by_cpuid(s->kvm, cpuid); if (!vcpu) continue;
cpu = vcpu->vcpu_id; if (s->sw_coremap[irq + i] == cpu) continue;
if (notify && test_bit(irq + i, (unsignedlong *)s->isr.reg_u8)) { /* lower irq at old cpu and raise irq at new cpu */
eiointc_update_irq(s, irq + i, 0);
s->sw_coremap[irq + i] = cpu;
eiointc_update_irq(s, irq + i, 1);
} else {
s->sw_coremap[irq + i] = cpu;
}
}
}
void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level)
{ unsignedlong flags; unsignedlong *isr = (unsignedlong *)s->isr.reg_u8;
switch (offset) { case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END:
index = (offset - EIOINTC_NODETYPE_START) >> 3;
old = s->nodetype.reg_u64[index];
s->nodetype.reg_u64[index] = (old & ~mask) | data; break; case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END: /* * ipmap cannot be set at runtime, can be set only at the beginning * of irqchip driver, need not update upper irq level
*/
old = s->ipmap.reg_u64;
s->ipmap.reg_u64 = (old & ~mask) | data; break; case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END:
index = (offset - EIOINTC_ENABLE_START) >> 3;
old = s->enable.reg_u64[index];
s->enable.reg_u64[index] = (old & ~mask) | data; /* * 1: enable irq. * update irq when isr is set.
*/
data = s->enable.reg_u64[index] & ~old & s->isr.reg_u64[index]; while (data) {
irq = __ffs(data);
eiointc_update_irq(s, irq + index * 64, 1);
data &= ~BIT_ULL(irq);
} /* * 0: disable irq. * update irq when isr is set.
*/
data = ~s->enable.reg_u64[index] & old & s->isr.reg_u64[index]; while (data) {
irq = __ffs(data);
eiointc_update_irq(s, irq + index * 64, 0);
data &= ~BIT_ULL(irq);
} break; case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END: /* do not emulate hw bounced irq routing */
index = (offset - EIOINTC_BOUNCE_START) >> 3;
old = s->bounce.reg_u64[index];
s->bounce.reg_u64[index] = (old & ~mask) | data; break; case EIOINTC_COREISR_START ... EIOINTC_COREISR_END:
index = (offset - EIOINTC_COREISR_START) >> 3; /* use attrs to get current cpu index */
cpu = vcpu->vcpu_id;
old = s->coreisr.reg_u64[cpu][index]; /* write 1 to clear interrupt */
s->coreisr.reg_u64[cpu][index] = old & ~data;
data &= old; while (data) {
irq = __ffs(data);
eiointc_update_irq(s, irq + index * 64, 0);
data &= ~BIT_ULL(irq);
} break; case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END:
index = (offset - EIOINTC_COREMAP_START) >> 3;
old = s->coremap.reg_u64[index];
s->coremap.reg_u64[index] = (old & ~mask) | data;
data = s->coremap.reg_u64[index];
eiointc_update_sw_coremap(s, index * 8, data, sizeof(data), true); break; default:
ret = -EINVAL; break;
}
return ret;
}
staticint kvm_eiointc_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
gpa_t addr, int len, constvoid *val)
{ int ret = -EINVAL; unsignedlong flags, value; struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
if (!eiointc) {
kvm_err("%s: eiointc irqchip not valid!\n", __func__); return -EINVAL;
}
if (addr & (len - 1)) {
kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len); return -EINVAL;
}
vcpu->stat.eiointc_write_exits++;
spin_lock_irqsave(&eiointc->lock, flags); switch (len) { case 1:
value = *(unsignedchar *)val;
ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, 0xFF); break; case 2:
value = *(unsignedshort *)val;
ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, USHRT_MAX); break; case 4:
value = *(unsignedint *)val;
ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, UINT_MAX); break; default:
value = *(unsignedlong *)val;
ret = loongarch_eiointc_write(vcpu, eiointc, addr, value, ULONG_MAX); break;
}
spin_unlock_irqrestore(&eiointc->lock, flags);
staticint kvm_eiointc_virt_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
gpa_t addr, int len, constvoid *val)
{ int ret = 0; unsignedlong flags;
u32 value = *(u32 *)val; struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
if (!eiointc) {
kvm_err("%s: eiointc irqchip not valid!\n", __func__); return -EINVAL;
}
addr -= EIOINTC_VIRT_BASE;
spin_lock_irqsave(&eiointc->lock, flags); switch (addr) { case EIOINTC_VIRT_FEATURES:
ret = -EPERM; break; case EIOINTC_VIRT_CONFIG: /* * eiointc features can only be set at disabled status
*/ if ((eiointc->status & BIT(EIOINTC_ENABLE)) && value) {
ret = -EPERM; break;
}
eiointc->status = value & eiointc->features; break; default: break;
}
spin_unlock_irqrestore(&eiointc->lock, flags);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.