0

I'm trying to develop a PCI device and I need to implement a legacy interrupt (not MSI or MSIX). I followed the example of edu.c but the IRQ is still raised when I load my driver.

I tried to look at other devices but no luck. Here is my code :

static void xxx_pci_realize(...)
{
      // ....

    pci_config_set_interrupt_pin(pci_conf, 1);
    pci_set_irq(pdev, 0);

    // ....
}

Does anyone have any idea of what is incorrect ? Thank you !

Lerenn
  • 597
  • 1
  • 5
  • 13

2 Answers2

1

You should not be trying to mess with the state of the PCI lines in your realize method at all. That method is where the device is created, and happens only once at the start of the simulation. Interrupt lines should be raised and lowered in response to things happening while the system is running -- typically the guest writes a register and this causes you to do something that means you then raise an interrupt. Then the guest gets that interrupt, and tells the device "OK, I've dealt with this now", and then the device lowers the interrupt. You can see this pattern in the 'edu.c' device you mention.

Peter Maydell
  • 9,707
  • 1
  • 19
  • 25
  • Thanks ! I understand more why it wasn't working. But I'm still wondering why the device pops up with the interrupt raised: the device won't have one of its "status registers" (registers used to know the reason of the interrupt) set at 1 because there is no cause for the IRQ to be raised. So, it will not acknowledge it and the IRQ will continue to pop indefinitely. So how should I make it low from start ? If I change my driver, it will maybe acknowledge IRQs that are for other devices, am I wrong ? – Lerenn Mar 06 '19 at 10:59
  • I have found that by switching to "pci_config_set_interrupt_pin(pci_conf, 2)", the IRQ is not raised when QEMU is started. I don't quite understand why though... – Lerenn Mar 06 '19 at 11:01
0

It seems that the interrupt was not issued from my device: I have read somewhere that, on legacy IRQs, devices are chained up on the IRQ pins 10 and 11. So the CPU/kernel has no way to say which one issued the IRQ.

If I understood it well, when an IRQ is issued, each device having legacy interrupts has to say if the interrupt originated from him or not. It is done by setting registers that will be read by the driver who will be able to handle the IRQ. And then the device following him in the list will do the same.

As I have adapted my QEMU PCI device to return 0 for registers that indicates if the device has issued the IRQ, the IRQ passes and is disabled after that. So I assume it is because the IRQ was issued by an other device.

If someone thinks it's not the real reason, I would be happy to know if there is another possibility :)

Thanks again @peter-maydell for your help !

Lerenn
  • 597
  • 1
  • 5
  • 13