On 06/10/2025 01:07, Damien Zammit wrote:
The above strategy would return the correct 11 IRQ in my case. I'd like
to have coded this suggestion to make clear what I'm describing but I'm
still puzzling over the best method of reading the PCI configuration
space header to determine pci_dev_pin in the code fragment. I don't want
to waste my time if I'm horribly wrong. I've seen that on my machine,
Linux lspci -vvv shows INTB used. There are _PRS mappings that refer to
IRQ 10 in INTA which would be selected first by the existing code.

You may be onto something here: I didn't realise the INTx pins were
predetermined per device.

In this case, yes, you will need to create a acpi_pci_id structure and
call lookup_pci_dev(),
then read out the "#define PCI_INTERRUPT_PIN 0x3d" from the device's
config space and match as you have suggested above, I think.  Well spotted.

That was what I had in mind but I hadn't realised how little code it would require when using the APIs that you mention. Thanks.

I've attached my proposal for this fix. There are some parts that might need revision depending on thoughts:

1) In the event the PCI device's interrupt pin cannot be read at all, -EIO is returned from acpi_get_irq_number(). An alternative interpretation of correctness might be to allow it to operate as it currently does (ie. scanning all pins' table entries)

2) In the event that the PCI config read works but returns 0 (no pin declared), the new code operates like the old one does. An alternative interpretation of correctness might be to return -EIO.

I've no strong opinions on these and will modify according to the prevailing wisdom.

I've only tested this on qemu virtual machine (q35) and my 1 hardware prospect.

In the case of my hardware machine, this alteration permits boot of 32 bit Hurd (with or without linux-groups). It does not boot with APIC configured nor on any configuration with 64 bit. These latter cases are affected by the 2nd issue that I reported in this thread which is my next focus.

It would certainly help if anyone using a 32 bit hardware platform could test this patch.

Best regards,

Mike.
diff -ur libacpica.orig/acpi_init.c libacpica/acpi_init.c
--- libacpica.orig/acpi_init.c	2025-10-06 19:09:14.000000000 +0100
+++ libacpica/acpi_init.c	2025-10-06 19:12:42.163263513 +0100
@@ -486,6 +486,22 @@
   return AE_OK;
 }
 
+#define PCI_INTERRUPT_PIN 0x3d
+
+static int
+acpi_pci_get_device_pin(uint16_t bus, uint16_t dev, uint16_t func)
+{
+  struct acpi_pci_id pci_id = {
+    .segment = 0, .bus = bus, .device = dev, .function = func
+  };
+  u64 pci_pin;
+
+  /* cast to int is safe having read only 8 bits */
+  return (acpi_os_read_pci_configuration(&pci_id, PCI_INTERRUPT_PIN, &pci_pin, 8)
+	  ? -1
+	  : (int)pci_pin);
+}
+
 int
 acpi_get_irq_number(uint16_t bus, uint16_t dev, uint16_t func)
 {
@@ -519,13 +535,20 @@
   if (ACPI_FAILURE(err))
     return -EIO;
 
+  int pci_pin = acpi_pci_get_device_pin(bus, dev, func);
+  if (pci_pin < 0)
+    return -EIO;
+
   entry = ACPI_CAST_PTR(struct acpi_pci_routing_table, ACPI_CAST_PTR(u8, buffer.pointer));
   while (entry && (entry->length > 0))
     {
       /* Already applies to the bus of the device */
       prt_dev = (entry->address >> 16) & 0xffff;
       prt_func = entry->address & 0xffff;
-      if ((prt_dev == dev) && (prt_func == 0xffff))
+      if ((prt_dev == dev) && (prt_func == 0xffff)
+	  /* Check all pins if the device pin used is unknown (0) */
+	  /* PCI config. enumerates pin in use as 1..4 whereas libacpica uses 0..3 */
+	  && (pci_pin == 0 || (entry->pin == (pci_pin - 1))))
         {
           if (entry->source[0])
             {

Reply via email to