* [Qemu-devel] [PATCH 0/4] pci: interrupt status/interrupt disable support @ 2009-11-25 16:58 Michael S. Tsirkin 2009-11-26 3:21 ` [Qemu-devel] " Isaku Yamahata 0 siblings, 1 reply; 9+ messages in thread From: Michael S. Tsirkin @ 2009-11-25 16:58 UTC (permalink / raw) To: qemu-devel, anthony, yamahata This patchset adds support for mandatory interupt status and interrupt disable bits to all PCI devices. This is required for PCI compliancy. These patches are on top of my pci tree, including Isaku Yamahata's fixes. If this is a problem, let me know and I will rebase. This works fine for me, but since this touches all PCI devices, please review carefully. Michael S. Tsirkin (4): pci: rearrange code for interrupts pci: track IRQ status pci: interrupt status bit implementation pci: interrupt disable bit support hw/pci.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- hw/pci.h | 8 ++++++ 2 files changed, 79 insertions(+), 12 deletions(-) ^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] Re: [PATCH 0/4] pci: interrupt status/interrupt disable support 2009-11-25 16:58 [Qemu-devel] [PATCH 0/4] pci: interrupt status/interrupt disable support Michael S. Tsirkin @ 2009-11-26 3:21 ` Isaku Yamahata 2009-11-26 9:48 ` Michael S. Tsirkin 2009-11-26 10:38 ` Michael S. Tsirkin 0 siblings, 2 replies; 9+ messages in thread From: Isaku Yamahata @ 2009-11-26 3:21 UTC (permalink / raw) To: Michael S. Tsirkin; +Cc: qemu-devel On Wed, Nov 25, 2009 at 06:58:34PM +0200, Michael S. Tsirkin wrote: > This patchset adds support for mandatory interupt > status and interrupt disable bits to all > PCI devices. This is required for PCI compliancy. > > These patches are on top of my pci tree, > including Isaku Yamahata's fixes. > If this is a problem, let me know and > I will rebase. > > This works fine for me, but since this touches > all PCI devices, please review carefully. Just a curiosity, what OS do you have in your mind? You introduced new members, irq_status and irq_disabled and maintain them according configuration space write. Another approach is to use irq_state[PCI_NUM_PINS] and interrupt disabled bit in command register. At least I think irq_disable can be removed by moving !change check from pci_set_irq() into pci_change_irq_level(). As for irq_status, only user of irq_status is pci_update_irq_status() so if (irq_statue) can be open coded. On the other hand, PCIBus already has irq_count member for same purpose. So probably open coding or introducing irq_count instead of irq_status would be reasonable. > > Michael S. Tsirkin (4): > pci: rearrange code for interrupts > pci: track IRQ status > pci: interrupt status bit implementation > pci: interrupt disable bit support > > hw/pci.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- > hw/pci.h | 8 ++++++ > 2 files changed, 79 insertions(+), 12 deletions(-) > -- yamahata ^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] Re: [PATCH 0/4] pci: interrupt status/interrupt disable support 2009-11-26 3:21 ` [Qemu-devel] " Isaku Yamahata @ 2009-11-26 9:48 ` Michael S. Tsirkin 2009-11-26 12:41 ` Paul Brook 2009-11-26 10:38 ` Michael S. Tsirkin 1 sibling, 1 reply; 9+ messages in thread From: Michael S. Tsirkin @ 2009-11-26 9:48 UTC (permalink / raw) To: Isaku Yamahata; +Cc: qemu-devel On Thu, Nov 26, 2009 at 12:21:46PM +0900, Isaku Yamahata wrote: > On Wed, Nov 25, 2009 at 06:58:34PM +0200, Michael S. Tsirkin wrote: > > This patchset adds support for mandatory interupt > > status and interrupt disable bits to all > > PCI devices. This is required for PCI compliancy. > > > > These patches are on top of my pci tree, > > including Isaku Yamahata's fixes. > > If this is a problem, let me know and > > I will rebase. > > > > This works fine for me, but since this touches > > all PCI devices, please review carefully. > > Just a curiosity, what OS do you have in your mind? windows and linux :) > You introduced new members, irq_status and irq_disabled > and maintain them according configuration space write. > Another approach is to use irq_state[PCI_NUM_PINS] and interrupt disabled > bit in command register. I will explain. irq_status is an optimization: it is a sum of all irq_state values. Since interrupts is a fast-path operation, we do not want to add another loop there. > At least I think irq_disable can be removed by moving !change check > from pci_set_irq() into pci_change_irq_level(). I don't see how is pci_set_irq relevant here: the reason I added irq_disabled is because we need to re-trigger interrupts when interrupts are enabled, either by load or config cycle. So it is there simply to detect change. Another approach would be to make irq_disabled a local variable in pci_default_write_config and in pci_device_load, and pass old value to pci_update_irq_disabled. I tried and it seems more code, and routines become less self-contained. As it is, I think it's cleaner because we have an idem-potent routine that is always safe it call, just like pci_update_mappings. > As for irq_status, only user of irq_status is pci_update_irq_status() > so if (irq_statue) can be open coded. On the other hand, > PCIBus already has irq_count member for same purpose. > So probably open coding or introducing irq_count instead of irq_status > would be reasonable. No, this would slow us down because these are per-pin. We need a sum of interrupts so that config space can be updated by a single command. Interrupts are a fastpath, extra loops there should be avoided. > > > > > Michael S. Tsirkin (4): > > pci: rearrange code for interrupts > > pci: track IRQ status > > pci: interrupt status bit implementation > > pci: interrupt disable bit support > > > > hw/pci.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- > > hw/pci.h | 8 ++++++ > > 2 files changed, 79 insertions(+), 12 deletions(-) > > > > -- > yamahata ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] Re: [PATCH 0/4] pci: interrupt status/interrupt disable support 2009-11-26 9:48 ` Michael S. Tsirkin @ 2009-11-26 12:41 ` Paul Brook 2009-11-26 12:59 ` Michael S. Tsirkin 0 siblings, 1 reply; 9+ messages in thread From: Paul Brook @ 2009-11-26 12:41 UTC (permalink / raw) To: qemu-devel; +Cc: Isaku Yamahata, Michael S. Tsirkin > No, this would slow us down because these are per-pin. > We need a sum of interrupts so that config space > can be updated by a single command. > Interrupts are a fastpath, extra loops there should be avoided. It's really not that much of a fast path. Unless you're doing something particularly obscure then even under heavy load you're unlikely to exceed a few kHz. Compared to the average PIC implementation, and the overhead of the actual CPU interrupt, I find it hard to believe that looping over precisely 4 entries has any real performance hit. Paul ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] Re: [PATCH 0/4] pci: interrupt status/interrupt disable support 2009-11-26 12:41 ` Paul Brook @ 2009-11-26 12:59 ` Michael S. Tsirkin 2009-11-26 13:21 ` Paul Brook 0 siblings, 1 reply; 9+ messages in thread From: Michael S. Tsirkin @ 2009-11-26 12:59 UTC (permalink / raw) To: Paul Brook; +Cc: Isaku Yamahata, qemu-devel On Thu, Nov 26, 2009 at 12:41:03PM +0000, Paul Brook wrote: > > No, this would slow us down because these are per-pin. > > We need a sum of interrupts so that config space > > can be updated by a single command. > > Interrupts are a fastpath, extra loops there should be avoided. > > It's really not that much of a fast path. Unless you're doing something > particularly obscure then even under heavy load you're unlikely to exceed a > few kHz. I think with kvm, heavy disk stressing benchmark can get higher. > Compared to the average PIC implementation, and the overhead of the > actual CPU interrupt, I find it hard to believe that looping over precisely 4 > entries has any real performance hit. > > Paul I don't think it is major, but I definitely have seen, in the past, that extra branches and memory accesses have small but measureable effect when taken in interrupt handler routines in drivers, and same should apply here. OTOH keeping the sum around is trivial. It might not be easily measureable now, but IMO that's just because the whole interrupt delivery is so complex. E.g. we currently have there a loop re-computing interrupt routing on each access, this is just silly and I intend to fix it. I would rather not introduce more code that will have to be cleaned up later. -- MST ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] Re: [PATCH 0/4] pci: interrupt status/interrupt disable support 2009-11-26 12:59 ` Michael S. Tsirkin @ 2009-11-26 13:21 ` Paul Brook 2009-11-26 13:34 ` Michael S. Tsirkin 0 siblings, 1 reply; 9+ messages in thread From: Paul Brook @ 2009-11-26 13:21 UTC (permalink / raw) To: Michael S. Tsirkin; +Cc: Isaku Yamahata, qemu-devel >> It's really not that much of a fast path. Unless you're doing something >> particularly obscure then even under heavy load you're unlikely to exceed >> a few kHz. > >I think with kvm, heavy disk stressing benchmark can get higher. I'd still expect this to be the least of your problems. If nothing else you've at least one host signal delivery and/or thread context switch in there. Not to mention the overhead to forwarding the interrupt to the guest CPU. > > Compared to the average PIC implementation, and the overhead of the > > actual CPU interrupt, I find it hard to believe that looping over > > precisely 4 entries has any real performance hit. > > I don't think it is major, but I definitely have seen, in the past, > that extra branches and memory accesses have small but measureable effect > when taken in interrupt handler routines in drivers, and same should > apply here. > > OTOH keeping the sum around is trivial. Not entirely. You now have two different bits of information that you have to keep consistent. Unless you can show that this is performance critical code I strongly recommend keeping it as simple as possible. Paul ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] Re: [PATCH 0/4] pci: interrupt status/interrupt disable support 2009-11-26 13:21 ` Paul Brook @ 2009-11-26 13:34 ` Michael S. Tsirkin 0 siblings, 0 replies; 9+ messages in thread From: Michael S. Tsirkin @ 2009-11-26 13:34 UTC (permalink / raw) To: Paul Brook; +Cc: Isaku Yamahata, qemu-devel On Thu, Nov 26, 2009 at 01:21:39PM +0000, Paul Brook wrote: > >> It's really not that much of a fast path. Unless you're doing something > >> particularly obscure then even under heavy load you're unlikely to exceed > >> a few kHz. > > > >I think with kvm, heavy disk stressing benchmark can get higher. > > I'd still expect this to be the least of your problems. > > If nothing else you've at least one host signal delivery and/or thread context > switch in there. iotread which does the signalling might be running in parallel with the guest CPU. > Not to mention the overhead to forwarding the interrupt to > the guest CPU. This is often mitigated as KVM knows to inject the interrupt on the next vmexit. > > > Compared to the average PIC implementation, and the overhead of the > > > actual CPU interrupt, I find it hard to believe that looping over > > > precisely 4 entries has any real performance hit. > > > > I don't think it is major, but I definitely have seen, in the past, > > that extra branches and memory accesses have small but measureable effect > > when taken in interrupt handler routines in drivers, and same should > > apply here. > > > > OTOH keeping the sum around is trivial. > > Not entirely. You now have two different bits of information that you have to > keep consistent. This is inherent in pci spec definition: interrupt status bit in config space duplicates interrupt state. > Unless you can show that this is performance critical code I strongly > recommend keeping it as simple as possible. > > Paul I don't see there is anything left show: interrupt delivery is *obviously* performance critical: people are running *latency benchmarks* measuring how fast a packet can get from an external interface into guest, in microseconds. We definitely want to remove obvious waste there. -- MST ^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] Re: [PATCH 0/4] pci: interrupt status/interrupt disable support 2009-11-26 3:21 ` [Qemu-devel] " Isaku Yamahata 2009-11-26 9:48 ` Michael S. Tsirkin @ 2009-11-26 10:38 ` Michael S. Tsirkin 2009-11-26 13:11 ` Michael S. Tsirkin 1 sibling, 1 reply; 9+ messages in thread From: Michael S. Tsirkin @ 2009-11-26 10:38 UTC (permalink / raw) To: Isaku Yamahata; +Cc: qemu-devel On Thu, Nov 26, 2009 at 12:21:46PM +0900, Isaku Yamahata wrote: > At least I think irq_disable can be removed The following patch on top of mine removes irq_disabled field in PCIDevice. I am of two minds whether this makes the code better. What is your opinion? diff --git a/hw/pci.c b/hw/pci.c index 3daae46..75f97df 100644 --- a/hw/pci.c +++ b/hw/pci.c @@ -128,15 +128,18 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); } -/* Update irq disabled field after config space change, - * assert/deassert interrupts if necessary. */ -static void pci_update_irq_disabled(PCIDevice *d) +static inline int pci_irq_disabled(PCIDevice *d) { - int i; - int disabled = !!(pci_get_word(d->config + PCI_COMMAND) & - PCI_COMMAND_INTX_DISABLE); - if (disabled == d->irq_disabled) + return !!(pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE); +} + +/* Called after interrupt disabled field update in config space, + * assert/deassert interrupts if necessary. + * Gets original interrupt disable bit value (before update). */ +static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled) +{ + int i, disabled = pci_irq_disabled(d); + if (disabled == was_irq_disabled) return; - d->irq_disabled = disabled; for (i = 0; i < ARRAY_SIZE(d->irq_state); ++i) { int state = d->irq_state[i]; @@ -150,7 +153,6 @@ static void pci_device_reset(PCIDevice *dev) memset(dev->irq_state, 0, sizeof dev->irq_state); dev->irq_status = 0; - dev->irq_disabled = 0; pci_update_irq_status(dev); dev->config[PCI_COMMAND] &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); @@ -369,14 +371,14 @@ void pci_device_save(PCIDevice *s, QEMUFile *f) int pci_device_load(PCIDevice *s, QEMUFile *f) { - int ret, i; + int ret, i, was_irq_disabled = pci_irq_disabled(d); ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); for (i = 0; i < ARRAY_SIZE(s->irq_state); ++i) { s->irq_status += s->irq_state[i]; } /* Restore the interrupt status bit. */ pci_update_irq_status(s); - pci_update_irq_disabled(s); + pci_update_irq_disabled(s, was_irq_disabled); return ret; } @@ -924,7 +926,7 @@ uint32_t pci_default_read_config(PCIDevice *d, void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) { - int i; + int i, was_irq_disabled = pci_irq_disabled(d); uint32_t config_size = pci_config_size(d); for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) { @@ -938,7 +940,7 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) pci_update_mappings(d); if (range_covers_byte(addr, l, PCI_COMMAND)) - pci_update_irq_disabled(d); + pci_update_irq_disabled(d, was_irq_disabled); } /***********************************************************/ @@ -957,7 +959,7 @@ static void pci_set_irq(void *opaque, int irq_num, int level) pci_dev->irq_state[irq_num] = level; pci_dev->irq_status += change; pci_update_irq_status(pci_dev); - if (pci_dev->irq_disabled) + if (pci_irq_disabled(pci_dev)) return; pci_change_irq_level(pci_dev, irq_num, change); } diff --git a/hw/pci.h b/hw/pci.h index 994b8bc..25ad114 100644 --- a/hw/pci.h +++ b/hw/pci.h @@ -227,9 +227,6 @@ struct PCIDevice { /* Sum of all irq levels. Used to implement irq status register. */ int irq_status; - /* Whether interrupts are disabled by command bit. */ - int irq_disabled; - /* Capability bits */ uint32_t cap_present; ^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] Re: [PATCH 0/4] pci: interrupt status/interrupt disable support 2009-11-26 10:38 ` Michael S. Tsirkin @ 2009-11-26 13:11 ` Michael S. Tsirkin 0 siblings, 0 replies; 9+ messages in thread From: Michael S. Tsirkin @ 2009-11-26 13:11 UTC (permalink / raw) To: Isaku Yamahata; +Cc: qemu-devel On Thu, Nov 26, 2009 at 12:38:20PM +0200, Michael S. Tsirkin wrote: > On Thu, Nov 26, 2009 at 12:21:46PM +0900, Isaku Yamahata wrote: > > At least I think irq_disable can be removed > > The following patch on top of mine removes irq_disabled field in > PCIDevice. I am of two minds whether this makes the code better. > What is your opinion? Thinking about this some more, I really like the original approach better, mostly because it helps keep the fastpath streamlined. On thing to note is that irq_disabled field was in the same or adjacent cache line with irq_state, and it is accessed on fast path. Reading config space instead will access an extra cache line which would be cold otherwise (config space is normally not accessed on fast path), and also needs an extra memory access (it is allocated on heap separately). As I said separately, the whole of interrupt delivery is far from optimal, but we have to start somewhere. > diff --git a/hw/pci.c b/hw/pci.c > index 3daae46..75f97df 100644 > --- a/hw/pci.c > +++ b/hw/pci.c > @@ -128,15 +128,18 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change) > bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0); > } > > -/* Update irq disabled field after config space change, > - * assert/deassert interrupts if necessary. */ > -static void pci_update_irq_disabled(PCIDevice *d) > +static inline int pci_irq_disabled(PCIDevice *d) > { > - int i; > - int disabled = !!(pci_get_word(d->config + PCI_COMMAND) & > - PCI_COMMAND_INTX_DISABLE); > - if (disabled == d->irq_disabled) > + return !!(pci_get_word(d->config + PCI_COMMAND) & PCI_COMMAND_INTX_DISABLE); > +} > + > +/* Called after interrupt disabled field update in config space, > + * assert/deassert interrupts if necessary. > + * Gets original interrupt disable bit value (before update). */ > +static void pci_update_irq_disabled(PCIDevice *d, int was_irq_disabled) > +{ > + int i, disabled = pci_irq_disabled(d); > + if (disabled == was_irq_disabled) > return; > - d->irq_disabled = disabled; > for (i = 0; i < ARRAY_SIZE(d->irq_state); ++i) { > int state = d->irq_state[i]; > @@ -150,7 +153,6 @@ static void pci_device_reset(PCIDevice *dev) > > memset(dev->irq_state, 0, sizeof dev->irq_state); > dev->irq_status = 0; > - dev->irq_disabled = 0; > pci_update_irq_status(dev); > dev->config[PCI_COMMAND] &= ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | > PCI_COMMAND_MASTER); > @@ -369,14 +371,14 @@ void pci_device_save(PCIDevice *s, QEMUFile *f) > > int pci_device_load(PCIDevice *s, QEMUFile *f) > { > - int ret, i; > + int ret, i, was_irq_disabled = pci_irq_disabled(d); > ret = vmstate_load_state(f, pci_get_vmstate(s), s, s->version_id); > for (i = 0; i < ARRAY_SIZE(s->irq_state); ++i) { > s->irq_status += s->irq_state[i]; > } > /* Restore the interrupt status bit. */ > pci_update_irq_status(s); > - pci_update_irq_disabled(s); > + pci_update_irq_disabled(s, was_irq_disabled); > return ret; > } > > @@ -924,7 +926,7 @@ uint32_t pci_default_read_config(PCIDevice *d, > > void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > { > - int i; > + int i, was_irq_disabled = pci_irq_disabled(d); > uint32_t config_size = pci_config_size(d); > > for (i = 0; i < l && addr + i < config_size; val >>= 8, ++i) { > @@ -938,7 +940,7 @@ void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l) > pci_update_mappings(d); > > if (range_covers_byte(addr, l, PCI_COMMAND)) > - pci_update_irq_disabled(d); > + pci_update_irq_disabled(d, was_irq_disabled); > } > > /***********************************************************/ > @@ -957,7 +959,7 @@ static void pci_set_irq(void *opaque, int irq_num, int level) > pci_dev->irq_state[irq_num] = level; > pci_dev->irq_status += change; > pci_update_irq_status(pci_dev); > - if (pci_dev->irq_disabled) > + if (pci_irq_disabled(pci_dev)) > return; > pci_change_irq_level(pci_dev, irq_num, change); > } > diff --git a/hw/pci.h b/hw/pci.h > index 994b8bc..25ad114 100644 > --- a/hw/pci.h > +++ b/hw/pci.h > @@ -227,9 +227,6 @@ struct PCIDevice { > /* Sum of all irq levels. Used to implement irq status register. */ > int irq_status; > > - /* Whether interrupts are disabled by command bit. */ > - int irq_disabled; > - > /* Capability bits */ > uint32_t cap_present; > ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2009-11-26 13:37 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-11-25 16:58 [Qemu-devel] [PATCH 0/4] pci: interrupt status/interrupt disable support Michael S. Tsirkin 2009-11-26 3:21 ` [Qemu-devel] " Isaku Yamahata 2009-11-26 9:48 ` Michael S. Tsirkin 2009-11-26 12:41 ` Paul Brook 2009-11-26 12:59 ` Michael S. Tsirkin 2009-11-26 13:21 ` Paul Brook 2009-11-26 13:34 ` Michael S. Tsirkin 2009-11-26 10:38 ` Michael S. Tsirkin 2009-11-26 13:11 ` Michael S. Tsirkin
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).