@@ -218,290 +218,45 @@ static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
218218 return 0 ;
219219}
220220
221- static int loongarch_eiointc_writeb (struct kvm_vcpu * vcpu ,
221+ static int loongarch_eiointc_write (struct kvm_vcpu * vcpu ,
222222 struct loongarch_eiointc * s ,
223- gpa_t addr , const void * val )
224- {
225- int index , irq , bits , ret = 0 ;
226- u8 cpu ;
227- u8 data , old_data ;
228- u8 coreisr , old_coreisr ;
229- gpa_t offset ;
230-
231- data = * (u8 * )val ;
232- offset = addr - EIOINTC_BASE ;
233-
234- switch (offset ) {
235- case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END :
236- index = (offset - EIOINTC_NODETYPE_START );
237- s -> nodetype .reg_u8 [index ] = data ;
238- break ;
239- case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END :
240- /*
241- * ipmap cannot be set at runtime, can be set only at the beginning
242- * of irqchip driver, need not update upper irq level
243- */
244- index = (offset - EIOINTC_IPMAP_START );
245- s -> ipmap .reg_u8 [index ] = data ;
246- break ;
247- case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END :
248- index = (offset - EIOINTC_ENABLE_START );
249- old_data = s -> enable .reg_u8 [index ];
250- s -> enable .reg_u8 [index ] = data ;
251- /*
252- * 1: enable irq.
253- * update irq when isr is set.
254- */
255- data = s -> enable .reg_u8 [index ] & ~old_data & s -> isr .reg_u8 [index ];
256- eiointc_enable_irq (vcpu , s , index , data , 1 );
257- /*
258- * 0: disable irq.
259- * update irq when isr is set.
260- */
261- data = ~s -> enable .reg_u8 [index ] & old_data & s -> isr .reg_u8 [index ];
262- eiointc_enable_irq (vcpu , s , index , data , 0 );
263- break ;
264- case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END :
265- /* do not emulate hw bounced irq routing */
266- index = offset - EIOINTC_BOUNCE_START ;
267- s -> bounce .reg_u8 [index ] = data ;
268- break ;
269- case EIOINTC_COREISR_START ... EIOINTC_COREISR_END :
270- index = (offset - EIOINTC_COREISR_START );
271- /* use attrs to get current cpu index */
272- cpu = vcpu -> vcpu_id ;
273- coreisr = data ;
274- old_coreisr = s -> coreisr .reg_u8 [cpu ][index ];
275- /* write 1 to clear interrupt */
276- s -> coreisr .reg_u8 [cpu ][index ] = old_coreisr & ~coreisr ;
277- coreisr &= old_coreisr ;
278- bits = sizeof (data ) * 8 ;
279- irq = find_first_bit ((void * )& coreisr , bits );
280- while (irq < bits ) {
281- eiointc_update_irq (s , irq + index * bits , 0 );
282- bitmap_clear ((void * )& coreisr , irq , 1 );
283- irq = find_first_bit ((void * )& coreisr , bits );
284- }
285- break ;
286- case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END :
287- irq = offset - EIOINTC_COREMAP_START ;
288- index = irq ;
289- s -> coremap .reg_u8 [index ] = data ;
290- eiointc_update_sw_coremap (s , irq , data , sizeof (data ), true);
291- break ;
292- default :
293- ret = - EINVAL ;
294- break ;
295- }
296-
297- return ret ;
298- }
299-
300- static int loongarch_eiointc_writew (struct kvm_vcpu * vcpu ,
301- struct loongarch_eiointc * s ,
302- gpa_t addr , const void * val )
303- {
304- int i , index , irq , bits , ret = 0 ;
305- u8 cpu ;
306- u16 data , old_data ;
307- u16 coreisr , old_coreisr ;
308- gpa_t offset ;
309-
310- data = * (u16 * )val ;
311- offset = addr - EIOINTC_BASE ;
312-
313- switch (offset ) {
314- case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END :
315- index = (offset - EIOINTC_NODETYPE_START ) >> 1 ;
316- s -> nodetype .reg_u16 [index ] = data ;
317- break ;
318- case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END :
319- /*
320- * ipmap cannot be set at runtime, can be set only at the beginning
321- * of irqchip driver, need not update upper irq level
322- */
323- index = (offset - EIOINTC_IPMAP_START ) >> 1 ;
324- s -> ipmap .reg_u16 [index ] = data ;
325- break ;
326- case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END :
327- index = (offset - EIOINTC_ENABLE_START ) >> 1 ;
328- old_data = s -> enable .reg_u16 [index ];
329- s -> enable .reg_u16 [index ] = data ;
330- /*
331- * 1: enable irq.
332- * update irq when isr is set.
333- */
334- data = s -> enable .reg_u16 [index ] & ~old_data & s -> isr .reg_u16 [index ];
335- for (i = 0 ; i < sizeof (data ); i ++ ) {
336- u8 mask = (data >> (i * 8 )) & 0xff ;
337- eiointc_enable_irq (vcpu , s , index * 2 + i , mask , 1 );
338- }
339- /*
340- * 0: disable irq.
341- * update irq when isr is set.
342- */
343- data = ~s -> enable .reg_u16 [index ] & old_data & s -> isr .reg_u16 [index ];
344- for (i = 0 ; i < sizeof (data ); i ++ ) {
345- u8 mask = (data >> (i * 8 )) & 0xff ;
346- eiointc_enable_irq (vcpu , s , index * 2 + i , mask , 0 );
347- }
348- break ;
349- case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END :
350- /* do not emulate hw bounced irq routing */
351- index = (offset - EIOINTC_BOUNCE_START ) >> 1 ;
352- s -> bounce .reg_u16 [index ] = data ;
353- break ;
354- case EIOINTC_COREISR_START ... EIOINTC_COREISR_END :
355- index = (offset - EIOINTC_COREISR_START ) >> 1 ;
356- /* use attrs to get current cpu index */
357- cpu = vcpu -> vcpu_id ;
358- coreisr = data ;
359- old_coreisr = s -> coreisr .reg_u16 [cpu ][index ];
360- /* write 1 to clear interrupt */
361- s -> coreisr .reg_u16 [cpu ][index ] = old_coreisr & ~coreisr ;
362- coreisr &= old_coreisr ;
363- bits = sizeof (data ) * 8 ;
364- irq = find_first_bit ((void * )& coreisr , bits );
365- while (irq < bits ) {
366- eiointc_update_irq (s , irq + index * bits , 0 );
367- bitmap_clear ((void * )& coreisr , irq , 1 );
368- irq = find_first_bit ((void * )& coreisr , bits );
369- }
370- break ;
371- case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END :
372- irq = offset - EIOINTC_COREMAP_START ;
373- index = irq >> 1 ;
374- s -> coremap .reg_u16 [index ] = data ;
375- eiointc_update_sw_coremap (s , irq , data , sizeof (data ), true);
376- break ;
377- default :
378- ret = - EINVAL ;
379- break ;
380- }
381-
382- return ret ;
383- }
384-
385- static int loongarch_eiointc_writel (struct kvm_vcpu * vcpu ,
386- struct loongarch_eiointc * s ,
387- gpa_t addr , const void * val )
223+ gpa_t addr , u64 value , u64 field_mask )
388224{
389225 int i , index , irq , bits , ret = 0 ;
390226 u8 cpu ;
391- u32 data , old_data ;
392- u32 coreisr , old_coreisr ;
227+ u64 data , old , mask ;
393228 gpa_t offset ;
394229
395- data = * (u32 * )val ;
396- offset = addr - EIOINTC_BASE ;
230+ offset = addr & 7 ;
231+ mask = field_mask << (offset * 8 );
232+ data = (value & field_mask ) << (offset * 8 );
397233
398- switch (offset ) {
399- case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END :
400- index = (offset - EIOINTC_NODETYPE_START ) >> 2 ;
401- s -> nodetype .reg_u32 [index ] = data ;
402- break ;
403- case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END :
404- /*
405- * ipmap cannot be set at runtime, can be set only at the beginning
406- * of irqchip driver, need not update upper irq level
407- */
408- index = (offset - EIOINTC_IPMAP_START ) >> 2 ;
409- s -> ipmap .reg_u32 [index ] = data ;
410- break ;
411- case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END :
412- index = (offset - EIOINTC_ENABLE_START ) >> 2 ;
413- old_data = s -> enable .reg_u32 [index ];
414- s -> enable .reg_u32 [index ] = data ;
415- /*
416- * 1: enable irq.
417- * update irq when isr is set.
418- */
419- data = s -> enable .reg_u32 [index ] & ~old_data & s -> isr .reg_u32 [index ];
420- for (i = 0 ; i < sizeof (data ); i ++ ) {
421- u8 mask = (data >> (i * 8 )) & 0xff ;
422- eiointc_enable_irq (vcpu , s , index * 4 + i , mask , 1 );
423- }
424- /*
425- * 0: disable irq.
426- * update irq when isr is set.
427- */
428- data = ~s -> enable .reg_u32 [index ] & old_data & s -> isr .reg_u32 [index ];
429- for (i = 0 ; i < sizeof (data ); i ++ ) {
430- u8 mask = (data >> (i * 8 )) & 0xff ;
431- eiointc_enable_irq (vcpu , s , index * 4 + i , mask , 0 );
432- }
433- break ;
434- case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END :
435- /* do not emulate hw bounced irq routing */
436- index = (offset - EIOINTC_BOUNCE_START ) >> 2 ;
437- s -> bounce .reg_u32 [index ] = data ;
438- break ;
439- case EIOINTC_COREISR_START ... EIOINTC_COREISR_END :
440- index = (offset - EIOINTC_COREISR_START ) >> 2 ;
441- /* use attrs to get current cpu index */
442- cpu = vcpu -> vcpu_id ;
443- coreisr = data ;
444- old_coreisr = s -> coreisr .reg_u32 [cpu ][index ];
445- /* write 1 to clear interrupt */
446- s -> coreisr .reg_u32 [cpu ][index ] = old_coreisr & ~coreisr ;
447- coreisr &= old_coreisr ;
448- bits = sizeof (data ) * 8 ;
449- irq = find_first_bit ((void * )& coreisr , bits );
450- while (irq < bits ) {
451- eiointc_update_irq (s , irq + index * bits , 0 );
452- bitmap_clear ((void * )& coreisr , irq , 1 );
453- irq = find_first_bit ((void * )& coreisr , bits );
454- }
455- break ;
456- case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END :
457- irq = offset - EIOINTC_COREMAP_START ;
458- index = irq >> 2 ;
459- s -> coremap .reg_u32 [index ] = data ;
460- eiointc_update_sw_coremap (s , irq , data , sizeof (data ), true);
461- break ;
462- default :
463- ret = - EINVAL ;
464- break ;
465- }
466-
467- return ret ;
468- }
469-
470- static int loongarch_eiointc_writeq (struct kvm_vcpu * vcpu ,
471- struct loongarch_eiointc * s ,
472- gpa_t addr , const void * val )
473- {
474- int i , index , irq , bits , ret = 0 ;
475- u8 cpu ;
476- u64 data , old_data ;
477- u64 coreisr , old_coreisr ;
478- gpa_t offset ;
479-
480- data = * (u64 * )val ;
234+ addr -= offset ;
481235 offset = addr - EIOINTC_BASE ;
482236
483237 switch (offset ) {
484238 case EIOINTC_NODETYPE_START ... EIOINTC_NODETYPE_END :
485239 index = (offset - EIOINTC_NODETYPE_START ) >> 3 ;
486- s -> nodetype .reg_u64 [index ] = data ;
240+ old = s -> nodetype .reg_u64 [index ];
241+ s -> nodetype .reg_u64 [index ] = (old & ~mask ) | data ;
487242 break ;
488243 case EIOINTC_IPMAP_START ... EIOINTC_IPMAP_END :
489244 /*
490245 * ipmap cannot be set at runtime, can be set only at the beginning
491246 * of irqchip driver, need not update upper irq level
492247 */
493- index = ( offset - EIOINTC_IPMAP_START ) >> 3 ;
494- s -> ipmap .reg_u64 = data ;
248+ old = s -> ipmap . reg_u64 ;
249+ s -> ipmap .reg_u64 = ( old & ~ mask ) | data ;
495250 break ;
496251 case EIOINTC_ENABLE_START ... EIOINTC_ENABLE_END :
497252 index = (offset - EIOINTC_ENABLE_START ) >> 3 ;
498- old_data = s -> enable .reg_u64 [index ];
499- s -> enable .reg_u64 [index ] = data ;
253+ old = s -> enable .reg_u64 [index ];
254+ s -> enable .reg_u64 [index ] = ( old & ~ mask ) | data ;
500255 /*
501256 * 1: enable irq.
502257 * update irq when isr is set.
503258 */
504- data = s -> enable .reg_u64 [index ] & ~old_data & s -> isr .reg_u64 [index ];
259+ data = s -> enable .reg_u64 [index ] & ~old & s -> isr .reg_u64 [index ];
505260 for (i = 0 ; i < sizeof (data ); i ++ ) {
506261 u8 mask = (data >> (i * 8 )) & 0xff ;
507262 eiointc_enable_irq (vcpu , s , index * 8 + i , mask , 1 );
@@ -510,7 +265,7 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
510265 * 0: disable irq.
511266 * update irq when isr is set.
512267 */
513- data = ~s -> enable .reg_u64 [index ] & old_data & s -> isr .reg_u64 [index ];
268+ data = ~s -> enable .reg_u64 [index ] & old & s -> isr .reg_u64 [index ];
514269 for (i = 0 ; i < sizeof (data ); i ++ ) {
515270 u8 mask = (data >> (i * 8 )) & 0xff ;
516271 eiointc_enable_irq (vcpu , s , index * 8 + i , mask , 0 );
@@ -519,30 +274,31 @@ static int loongarch_eiointc_writeq(struct kvm_vcpu *vcpu,
519274 case EIOINTC_BOUNCE_START ... EIOINTC_BOUNCE_END :
520275 /* do not emulate hw bounced irq routing */
521276 index = (offset - EIOINTC_BOUNCE_START ) >> 3 ;
522- s -> bounce .reg_u64 [index ] = data ;
277+ old = s -> bounce .reg_u64 [index ];
278+ s -> bounce .reg_u64 [index ] = (old & ~mask ) | data ;
523279 break ;
524280 case EIOINTC_COREISR_START ... EIOINTC_COREISR_END :
525281 index = (offset - EIOINTC_COREISR_START ) >> 3 ;
526282 /* use attrs to get current cpu index */
527283 cpu = vcpu -> vcpu_id ;
528- coreisr = data ;
529- old_coreisr = s -> coreisr .reg_u64 [cpu ][index ];
284+ old = s -> coreisr .reg_u64 [cpu ][index ];
530285 /* write 1 to clear interrupt */
531- s -> coreisr .reg_u64 [cpu ][index ] = old_coreisr & ~coreisr ;
532- coreisr &= old_coreisr ;
286+ s -> coreisr .reg_u64 [cpu ][index ] = old & ~data ;
287+ data &= old ;
533288 bits = sizeof (data ) * 8 ;
534- irq = find_first_bit ((void * )& coreisr , bits );
289+ irq = find_first_bit ((void * )& data , bits );
535290 while (irq < bits ) {
536291 eiointc_update_irq (s , irq + index * bits , 0 );
537- bitmap_clear ((void * )& coreisr , irq , 1 );
538- irq = find_first_bit ((void * )& coreisr , bits );
292+ bitmap_clear ((void * )& data , irq , 1 );
293+ irq = find_first_bit ((void * )& data , bits );
539294 }
540295 break ;
541296 case EIOINTC_COREMAP_START ... EIOINTC_COREMAP_END :
542- irq = offset - EIOINTC_COREMAP_START ;
543- index = irq >> 3 ;
544- s -> coremap .reg_u64 [index ] = data ;
545- eiointc_update_sw_coremap (s , irq , data , sizeof (data ), true);
297+ index = (offset - EIOINTC_COREMAP_START ) >> 3 ;
298+ old = s -> coremap .reg_u64 [index ];
299+ s -> coremap .reg_u64 [index ] = (old & ~mask ) | data ;
300+ data = s -> coremap .reg_u64 [index ];
301+ eiointc_update_sw_coremap (s , index * 8 , data , sizeof (data ), true);
546302 break ;
547303 default :
548304 ret = - EINVAL ;
@@ -557,7 +313,7 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
557313 gpa_t addr , int len , const void * val )
558314{
559315 int ret = - EINVAL ;
560- unsigned long flags ;
316+ unsigned long flags , value ;
561317 struct loongarch_eiointc * eiointc = vcpu -> kvm -> arch .eiointc ;
562318
563319 if (!eiointc ) {
@@ -574,16 +330,20 @@ static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
574330 spin_lock_irqsave (& eiointc -> lock , flags );
575331 switch (len ) {
576332 case 1 :
577- ret = loongarch_eiointc_writeb (vcpu , eiointc , addr , val );
333+ value = * (unsigned char * )val ;
334+ ret = loongarch_eiointc_write (vcpu , eiointc , addr , value , 0xFF );
578335 break ;
579336 case 2 :
580- ret = loongarch_eiointc_writew (vcpu , eiointc , addr , val );
337+ value = * (unsigned short * )val ;
338+ ret = loongarch_eiointc_write (vcpu , eiointc , addr , value , USHRT_MAX );
581339 break ;
582340 case 4 :
583- ret = loongarch_eiointc_writel (vcpu , eiointc , addr , val );
341+ value = * (unsigned int * )val ;
342+ ret = loongarch_eiointc_write (vcpu , eiointc , addr , value , UINT_MAX );
584343 break ;
585344 default :
586- ret = loongarch_eiointc_writeq (vcpu , eiointc , addr , val );
345+ value = * (unsigned long * )val ;
346+ ret = loongarch_eiointc_write (vcpu , eiointc , addr , value , ULONG_MAX );
587347 break ;
588348 }
589349 spin_unlock_irqrestore (& eiointc -> lock , flags );
0 commit comments