Skip to content

Commit f851fdd

Browse files
bibo-maochenhuacai
authored andcommitted
LoongArch: KVM: Add different length support in loongarch_pch_pic_write()
With function loongarch_pch_pic_write(), currently there is only four bytes register write support. But in theory, all length 1/2/4/8 should be supported for all the registers, here add different length support about register write emulation in function loongarch_pch_pic_write(). Signed-off-by: Bibo Mao <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent f8a73df commit f851fdd

1 file changed

Lines changed: 52 additions & 103 deletions

File tree

arch/loongarch/kvm/intc/pch_pic.c

Lines changed: 52 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -77,45 +77,6 @@ void pch_msi_set_irq(struct kvm *kvm, int irq, int level)
7777
eiointc_set_irq(kvm->arch.eiointc, irq, level);
7878
}
7979

80-
/*
81-
* pch pic register is 64-bit, but it is accessed by 32-bit,
82-
* so we use high to get whether low or high 32 bits we want
83-
* to read.
84-
*/
85-
static u32 pch_pic_read_reg(u64 *s, int high)
86-
{
87-
u64 val = *s;
88-
89-
/* read the high 32 bits when high is 1 */
90-
return high ? (u32)(val >> 32) : (u32)val;
91-
}
92-
93-
/*
94-
* pch pic register is 64-bit, but it is accessed by 32-bit,
95-
* so we use high to get whether low or high 32 bits we want
96-
* to write.
97-
*/
98-
static u32 pch_pic_write_reg(u64 *s, int high, u32 v)
99-
{
100-
u64 val = *s, data = v;
101-
102-
if (high) {
103-
/*
104-
* Clear val high 32 bits
105-
* Write the high 32 bits when the high is 1
106-
*/
107-
*s = (val << 32 >> 32) | (data << 32);
108-
val >>= 32;
109-
} else
110-
/*
111-
* Clear val low 32 bits
112-
* Write the low 32 bits when the high is 0
113-
*/
114-
*s = (val >> 32 << 32) | v;
115-
116-
return (u32)val;
117-
}
118-
11980
static int loongarch_pch_pic_read(struct loongarch_pch_pic *s, gpa_t addr, int len, void *val)
12081
{
12182
int ret = 0, offset;
@@ -205,81 +166,69 @@ static int kvm_pch_pic_read(struct kvm_vcpu *vcpu,
205166
static int loongarch_pch_pic_write(struct loongarch_pch_pic *s, gpa_t addr,
206167
int len, const void *val)
207168
{
208-
int ret;
209-
u32 old, data, offset, index;
210-
u64 irq;
169+
int ret = 0, offset;
170+
u64 old, data, mask;
171+
void *ptemp;
211172

212-
ret = 0;
213-
data = *(u32 *)val;
214-
offset = addr - s->pch_pic_base;
173+
switch (len) {
174+
case 1:
175+
data = *(u8 *)val;
176+
mask = 0xFF;
177+
break;
178+
case 2:
179+
data = *(u16 *)val;
180+
mask = USHRT_MAX;
181+
break;
182+
case 4:
183+
data = *(u32 *)val;
184+
mask = UINT_MAX;
185+
break;
186+
case 8:
187+
default:
188+
data = *(u64 *)val;
189+
mask = ULONG_MAX;
190+
break;
191+
}
192+
193+
offset = (addr - s->pch_pic_base) & 7;
194+
mask = mask << (offset * 8);
195+
data = data << (offset * 8);
196+
offset = (addr - s->pch_pic_base) - offset;
215197

216198
spin_lock(&s->lock);
217199
switch (offset) {
218-
case PCH_PIC_MASK_START ... PCH_PIC_MASK_END:
219-
offset -= PCH_PIC_MASK_START;
220-
/* get whether high or low 32 bits we want to write */
221-
index = offset >> 2;
222-
old = pch_pic_write_reg(&s->mask, index, data);
223-
/* enable irq when mask value change to 0 */
224-
irq = (old & ~data) << (32 * index);
225-
pch_pic_update_batch_irqs(s, irq, 1);
226-
/* disable irq when mask value change to 1 */
227-
irq = (~old & data) << (32 * index);
228-
pch_pic_update_batch_irqs(s, irq, 0);
229-
break;
230-
case PCH_PIC_HTMSI_EN_START ... PCH_PIC_HTMSI_EN_END:
231-
offset -= PCH_PIC_HTMSI_EN_START;
232-
index = offset >> 2;
233-
pch_pic_write_reg(&s->htmsi_en, index, data);
200+
case PCH_PIC_MASK_START:
201+
old = s->mask;
202+
s->mask = (old & ~mask) | data;
203+
if (old & ~data)
204+
pch_pic_update_batch_irqs(s, old & ~data, 1);
205+
if (~old & data)
206+
pch_pic_update_batch_irqs(s, ~old & data, 0);
234207
break;
235-
case PCH_PIC_EDGE_START ... PCH_PIC_EDGE_END:
236-
offset -= PCH_PIC_EDGE_START;
237-
index = offset >> 2;
238-
/* 1: edge triggered, 0: level triggered */
239-
pch_pic_write_reg(&s->edge, index, data);
240-
break;
241-
case PCH_PIC_CLEAR_START ... PCH_PIC_CLEAR_END:
242-
offset -= PCH_PIC_CLEAR_START;
243-
index = offset >> 2;
244-
/* write 1 to clear edge irq */
245-
old = pch_pic_read_reg(&s->irr, index);
246-
/*
247-
* get the irq bitmap which is edge triggered and
248-
* already set and to be cleared
249-
*/
250-
irq = old & pch_pic_read_reg(&s->edge, index) & data;
251-
/* write irr to the new state where irqs have been cleared */
252-
pch_pic_write_reg(&s->irr, index, old & ~irq);
253-
/* update cleared irqs */
254-
pch_pic_update_batch_irqs(s, irq, 0);
208+
case PCH_PIC_HTMSI_EN_START:
209+
s->htmsi_en = (s->htmsi_en & ~mask) | data;
255210
break;
256-
case PCH_PIC_AUTO_CTRL0_START ... PCH_PIC_AUTO_CTRL0_END:
257-
offset -= PCH_PIC_AUTO_CTRL0_START;
258-
index = offset >> 2;
259-
/* we only use default mode: fixed interrupt distribution mode */
260-
pch_pic_write_reg(&s->auto_ctrl0, index, 0);
211+
case PCH_PIC_EDGE_START:
212+
s->edge = (s->edge & ~mask) | data;
261213
break;
262-
case PCH_PIC_AUTO_CTRL1_START ... PCH_PIC_AUTO_CTRL1_END:
263-
offset -= PCH_PIC_AUTO_CTRL1_START;
264-
index = offset >> 2;
265-
/* we only use default mode: fixed interrupt distribution mode */
266-
pch_pic_write_reg(&s->auto_ctrl1, index, 0);
214+
case PCH_PIC_POLARITY_START:
215+
s->polarity = (s->polarity & ~mask) | data;
267216
break;
268-
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
269-
offset -= PCH_PIC_ROUTE_ENTRY_START;
270-
/* only route to int0: eiointc */
271-
s->route_entry[offset] = 1;
217+
case PCH_PIC_CLEAR_START:
218+
old = s->irr & s->edge & data;
219+
if (old) {
220+
s->irr &= ~old;
221+
pch_pic_update_batch_irqs(s, old, 0);
222+
}
272223
break;
273224
case PCH_PIC_HTMSI_VEC_START ... PCH_PIC_HTMSI_VEC_END:
274-
/* route table to eiointc */
275-
offset -= PCH_PIC_HTMSI_VEC_START;
276-
s->htmsi_vector[offset] = (u8)data;
225+
ptemp = s->htmsi_vector + (offset - PCH_PIC_HTMSI_VEC_START);
226+
*(u64 *)ptemp = (*(u64 *)ptemp & ~mask) | data;
277227
break;
278-
case PCH_PIC_POLARITY_START ... PCH_PIC_POLARITY_END:
279-
offset -= PCH_PIC_POLARITY_START;
280-
index = offset >> 2;
281-
/* we only use defalut value 0: high level triggered */
282-
pch_pic_write_reg(&s->polarity, index, 0);
228+
/* Not implemented */
229+
case PCH_PIC_AUTO_CTRL0_START:
230+
case PCH_PIC_AUTO_CTRL1_START:
231+
case PCH_PIC_ROUTE_ENTRY_START ... PCH_PIC_ROUTE_ENTRY_END:
283232
break;
284233
default:
285234
ret = -EINVAL;

0 commit comments

Comments
 (0)