提交 541574a6 编写于 作者: L lixianglai 提交者: Hongchen Zhang

loongarch/kvm: ls7a add iocsrw emulation

LoongArch inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I6MUZX

--------------------------------

The virtual machine has a case where the LS7A registers
 are accessed in length 4 bytes, so the emulation of
4-byte access to LS7A is added.
Signed-off-by: Nlixianglai <lixianglai@loongson.cn>
Change-Id: I46daf63d7a1766080a806adbd3f2d6b77f9657d0
上级 e3874862
......@@ -139,11 +139,13 @@ static int ls7a_ioapic_reg_write(struct ls7a_kvm_ioapic *s,
struct kvm_ls7a_ioapic_state *state;
int64_t offset_tmp;
uint64_t offset;
uint64_t data, old;
uint64_t data, old, himask, lowmask;;
offset = addr & 0xfff;
kvm = s->kvm;
state = &(s->ls7a_ioapic);
lowmask = 0xFFFFFFFFUL;
himask = lowmask << 32;
if (offset & (len - 1)) {
printk("%s(%d):unaligned address access %llx size %d \n",
......@@ -191,6 +193,80 @@ static int ls7a_ioapic_reg_write(struct ls7a_kvm_ioapic *s,
WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
break;
}
} else if (4 == len) {
data = *(uint32_t *)val;
switch (offset) {
case LS7A_INT_MASK_OFFSET:
old = state->int_mask & lowmask;
state->int_mask = (state->int_mask & himask) | data;
if (old & ~data)
kvm_ls7a_ioapic_raise(kvm, old & ~data);
if (~old & data)
kvm_ls7a_ioapic_lower(kvm, ~old & data);
break;
case LS7A_INT_MASK_OFFSET + 4:
data = data << 32;
old = state->int_mask & himask;
state->int_mask = (state->int_mask & lowmask) | data;
if (old & ~data)
kvm_ls7a_ioapic_raise(kvm, old & ~data);
if (~old & data)
kvm_ls7a_ioapic_lower(kvm, ~old & data);
break;
case LS7A_INT_STATUS_OFFSET:
state->intisr = (state->intisr & himask) | data;
break;
case LS7A_INT_STATUS_OFFSET + 4:
data = data << 32;
state->intisr = (state->intisr & lowmask) | data;
break;
case LS7A_INT_EDGE_OFFSET:
state->intedge = (state->intedge & himask) | data;
break;
case LS7A_INT_EDGE_OFFSET + 4:
data = data << 32;
state->intedge = (state->intedge & lowmask) | data;
break;
case LS7A_INT_CLEAR_OFFSET:
/*
* only clear edge triggered irq on writing INTCLR reg
* no effect on level triggered irq
*/
data = data & state->intedge;
state->intirr &= ~data;
kvm_ls7a_ioapic_lower(kvm, data);
state->intisr &= ~data;
break;
case LS7A_INT_CLEAR_OFFSET + 4:
data = data << 32;
data = data & state->intedge;
state->intirr &= ~data;
kvm_ls7a_ioapic_lower(kvm, data);
state->intisr &= ~data;
break;
case LS7A_INT_POL_OFFSET:
state->int_polarity = (state->int_polarity & himask) | data;
break;
case LS7A_INT_POL_OFFSET+4:
data = data << 32;
state->int_polarity = (state->int_polarity & lowmask) | data;
break;
case LS7A_HTMSI_EN_OFFSET:
state->htmsi_en = (state->htmsi_en & himask) | data;
break;
case LS7A_HTMSI_EN_OFFSET+4:
data = data << 32;
state->htmsi_en = (state->htmsi_en & lowmask) | data;
break;
case LS7A_AUTO_CTRL0_OFFSET:
case LS7A_AUTO_CTRL0_OFFSET+4:
case LS7A_AUTO_CTRL1_OFFSET:
case LS7A_AUTO_CTRL1_OFFSET+4:
break;
default:
WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
break;
}
} else if (1 == len) {
data = *(unsigned char *)val;
if (offset >= LS7A_HTMSI_VEC_OFFSET) {
......@@ -240,11 +316,13 @@ static int ls7a_ioapic_reg_read(struct ls7a_kvm_ioapic *s,
uint64_t offset, offset_tmp;
struct kvm *kvm;
struct kvm_ls7a_ioapic_state *state;
uint64_t result = 0;
uint64_t result = 0, lowmask, himask;
state = &(s->ls7a_ioapic);
kvm = s->kvm;
offset = addr & 0xfff;
lowmask = 0xFFFFFFFFUL;
himask = lowmask << 32;
if (offset & (len - 1)) {
printk("%s(%d):unaligned address access %llx size %d \n",
__FUNCTION__, __LINE__, addr, len);
......@@ -281,6 +359,60 @@ static int ls7a_ioapic_reg_read(struct ls7a_kvm_ioapic *s,
}
if (val != NULL)
*(uint64_t *)val = result;
} else if (4 == len) {
switch (offset) {
case LS7A_INT_MASK_OFFSET:
result = state->int_mask & lowmask;
break;
case LS7A_INT_MASK_OFFSET + 4:
result = state->int_mask & himask;
result = result >> 32;
break;
case LS7A_INT_STATUS_OFFSET:
result = state->intisr & (~state->int_mask) & lowmask;
break;
case LS7A_INT_STATUS_OFFSET + 4:
result = state->intisr & (~state->int_mask) & himask;
result = result >> 32;
break;
case LS7A_INT_EDGE_OFFSET:
result = state->intedge & lowmask;
break;
case LS7A_INT_EDGE_OFFSET + 4:
result = state->intedge & himask;
result = result >> 32;
break;
case LS7A_INT_POL_OFFSET:
result = state->int_polarity & lowmask;
break;
case LS7A_INT_POL_OFFSET + 4:
result = state->int_polarity & himask;
result = result >> 32;
break;
case LS7A_HTMSI_EN_OFFSET:
result = state->htmsi_en & lowmask;
break;
case LS7A_HTMSI_EN_OFFSET + 4:
result = state->htmsi_en & himask;
result = result >> 32;
break;
case LS7A_AUTO_CTRL0_OFFSET:
case LS7A_AUTO_CTRL0_OFFSET + 4:
case LS7A_AUTO_CTRL1_OFFSET:
case LS7A_AUTO_CTRL1_OFFSET + 4:
break;
case LS7A_INT_ID_OFFSET:
result = LS7A_INT_ID_VAL;
break;
case LS7A_INT_ID_OFFSET + 4:
result = LS7A_INT_ID_VER;
break;
default:
WARN_ONCE(1, "Abnormal address access:addr 0x%llx,len %d\n", addr, len);
break;
}
if (val != NULL)
*(uint32_t *)val = result;
} else if (1 == len) {
if (offset >= LS7A_HTMSI_VEC_OFFSET) {
offset_tmp = offset - LS7A_HTMSI_VEC_OFFSET;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册