[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] Re: [PATCH 3/3] piix_pci: optimize set irq path
From: |
Michael S. Tsirkin |
Subject: |
[Qemu-devel] Re: [PATCH 3/3] piix_pci: optimize set irq path |
Date: |
Thu, 17 Mar 2011 16:41:08 +0200 |
User-agent: |
Mutt/1.5.21 (2010-09-15) |
On Thu, Mar 17, 2011 at 10:49:53PM +0900, Isaku Yamahata wrote:
> optimize irq routing in piix_pic.c which has been a TODO.
>
> Cc: Michael S. Tsirkin <address@hidden>
> Signed-off-by: Isaku Yamahata <address@hidden>
Some minor comments, and looks like load has a minor bug -
probably an old one as we didn't use to have a post load.
> ---
> hw/piix_pci.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++-------
> 1 files changed, 90 insertions(+), 13 deletions(-)
>
> diff --git a/hw/piix_pci.c b/hw/piix_pci.c
> index 2d0ad9b..80ce205 100644
> --- a/hw/piix_pci.c
> +++ b/hw/piix_pci.c
> @@ -29,6 +29,7 @@
> #include "isa.h"
> #include "sysbus.h"
> #include "range.h"
> +#include "bitops.h"
still needed?
>
> /*
> * I440FX chipset data sheet.
> @@ -37,8 +38,32 @@
>
> typedef PCIHostState I440FXState;
>
> +#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */
> +#define PIIX_NUM_PIRQS 4 /* PIRQ[A-D] */
> +#define PIIX_PIRQC 0x60
> +
> typedef struct PIIX3State {
> PCIDevice dev;
> +
> + /*
> + * bitmap to track pic levels.
> + * The pic level is the logical OR of all the PCI irqs mapped to it
> + * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
> + *
> + * PIRQ is mapped to PIC pins, we track it by
> + * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
> + * pic_irq * PIIX_NUM_PIRQS + pirq
> + */
> +#define PIIX_PIC_LEVEL_MASK(pic_irq) \
> + (((uint64_t)PIIX_NUM_PIRQS - 1) << ((pic_irq) * PIIX_NUM_PIRQS))
> +#define PIIX_PIC_LEVEL_BIT(pic_irq, pirq) \
> + (1ULL << (((pic_irq) * PIIX_NUM_PIRQS) + (pirq)))
I'll be happier with these open-coded: will be clearer
without all the () that macros need.
And we can make PIIX_NUM_PIRQS ULL so won't need a cast.
But not critical.
> +
> +#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
> +#error "unable to encode pic state in 64bit in pic_levels."
> +#endif
> + uint64_t pic_levels;
> +
> int32_t dummy_for_save_load_compat[4];
> qemu_irq *pic;
> } PIIX3State;
> @@ -252,25 +277,66 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int
> *piix3_devfn, qemu_irq *
> }
>
> /* PIIX3 PCI to ISA bridge */
> +static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
> +{
> + qemu_set_irq(piix3->pic[pic_irq],
> + !!(piix3->pic_levels & PIIX_PIC_LEVEL_MASK(pic_irq)));
> +}
> +
> +static int piix3_set_irq_level(PIIX3State *piix3, int irq_num, int level)
> +{
> + int pic_irq;
> + uint64_t mask;
> +
> + pic_irq = piix3->dev.config[PIIX_PIRQC + irq_num];
> + if (pic_irq >= PIIX_NUM_PIC_IRQS) {
> + return -1;
> + }
> +
> + mask = PIIX_PIC_LEVEL_BIT(pic_irq, irq_num);
> + piix3->pic_levels &= ~mask;
> + piix3->pic_levels |= mask * !!level;
> + return pic_irq;
> +}
>
> static void piix3_set_irq(void *opaque, int irq_num, int level)
I find the split between piix3_set_irq_level
and piix3_set_irq_level unintuitive.
It seems that we can just always call piix3_set_irq
and then piix3_set_irq_level can be inlined:
return instead of pic_irq >= 0 below.
> {
> - int i, pic_irq, pic_level;
> PIIX3State *piix3 = opaque;
> + int pic_irq;
> + pic_irq = piix3_set_irq_level(piix3, irq_num, level);
> + if (pic_irq >= 0) {
> + piix3_set_irq_pic(piix3, pic_irq);
> + }
> +}
>
> - /* now we change the pic irq level according to the piix irq mappings */
> - /* XXX: optimize */
> - pic_irq = piix3->dev.config[0x60 + irq_num];
> - if (pic_irq < 16) {
> - /* The pic level is the logical OR of all the PCI irqs mapped
> - to it */
> - pic_level = 0;
> - for (i = 0; i < 4; i++) {
> - if (pic_irq == piix3->dev.config[0x60 + i]) {
> - pic_level |= pci_bus_get_irq_level(piix3->dev.bus, i);
> - }
> +static void piix3_reset_irq_levels(PIIX3State *piix3)
> +{
> + piix3->pic_levels = 0;
> +}
> +
Going overboard on the abstraction front IMO.
> +/* irq routing is changed. so rebuild bitmap */
> +static void piix3_rebuild_irq_levels(PIIX3State *piix3)
I iked _update_ better than rebuild, but not critical.
> +{
> + int pirq;
> +
> + piix3_reset_irq_levels(piix3);
> + for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
> + piix3_set_irq_level(piix3, pirq,
> + pci_bus_get_irq_level(piix3->dev.bus, pirq));
> + }
> +}
> +
> +static void piix3_write_config(PCIDevice *dev,
> + uint32_t address, uint32_t val, int len)
> +{
> + pci_default_write_config(dev, address, val, len);
> + if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
> + PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev);
> + int pic_irq;
> + piix3_rebuild_irq_levels(piix3);
> + for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
> + piix3_set_irq_pic(piix3, pic_irq);
> }
> - qemu_set_irq(piix3->pic[pic_irq], pic_level);
> }
> }
>
> @@ -310,6 +376,15 @@ static void piix3_reset(void *opaque)
> pci_conf[0xab] = 0x00;
> pci_conf[0xac] = 0x00;
> pci_conf[0xae] = 0x00;
> +
> + piix3_reset_irq_levels(d);
> +}
> +
> +static int piix3_post_load(void *opaque, int version_id)
> +{
> + PIIX3State *piix3 = opaque;
> + piix3_rebuild_irq_levels(piix3);
Don't we need to set_irq_pic here as well?
And in that case, just make the for loop
part of piix3_rebuild_irq_levels.
> + return 0;
> }
>
> static void piix3_pre_save(void *opaque)
> @@ -328,6 +403,7 @@ static const VMStateDescription vmstate_piix3 = {
> .version_id = 3,
> .minimum_version_id = 2,
> .minimum_version_id_old = 2,
> + .post_load = piix3_post_load,
> .pre_save = piix3_pre_save,
> .fields = (VMStateField []) {
> VMSTATE_PCI_DEVICE(dev, PIIX3State),
> @@ -370,6 +446,7 @@ static PCIDeviceInfo i440fx_info[] = {
> .qdev.no_user = 1,
> .no_hotplug = 1,
> .init = piix3_initfn,
> + .config_write = piix3_write_config,
> },{
> /* end of list */
> }
> --
> 1.7.1.1