Now the acpi server can know which interrupt controller is in use,
particularly useful on x86 ISA where there are two different ones.

TESTED: With this patch, 1/2 and the gnumach irq device patch,
Hurd i386 boots with apic on Thinkpad W530.
Also still boots on qemu (with different irq numbers detected).

Also-by: Michael Kelly <[email protected]>
---
 debian/patches/acpi-init-files.diff | 96 ++++++++++++++++++++++++++++-
 1 file changed, 95 insertions(+), 1 deletion(-)

diff --git a/debian/patches/acpi-init-files.diff 
b/debian/patches/acpi-init-files.diff
index 3f95537..aad4c95 100644
--- a/debian/patches/acpi-init-files.diff
+++ b/debian/patches/acpi-init-files.diff
@@ -1,6 +1,6 @@
 --- /dev/null
 +++ b/acpi_init.c
-@@ -0,0 +1,736 @@
+@@ -0,0 +1,830 @@
 +// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
 +#include <acpi/acpi.h>
 +
@@ -701,6 +701,96 @@
 +  return -EIO;
 +}
 +
++#define IRQGETPICMODE          0
++# define ACPI_PICMODE_PIC      0
++# define ACPI_PICMODE_APIC     1
++# define ACPI_PICMODE_SAPIC    2
++
++/* Fetch the active interrupt mode from GNU mach */
++static error_t
++acpi_required_pic_mode (int* pic_mode)
++{
++  mach_port_t devices = MACH_PORT_NULL, irq;
++  mach_msg_type_number_t cnt = 0;
++
++  error_t err = get_privileged_ports(NULL, &devices);
++  if (err)
++    return err;
++
++  if (devices == MACH_PORT_NULL)
++    return ENODEV;
++
++  err = device_open(devices, D_READ, "irq", &irq);
++  if (!err)
++    {
++      /* Determine if the IRQGETPICMODE feature is available in the
++       running kernel by specifying a NULL array for 'status'. If
++       the feature is available then MIG_ARRAY_TOO_LARGE is returned
++       as the returned status cannot fit in the result.
++      */
++      if (device_get_status(irq, IRQGETPICMODE, NULL, &cnt)
++       != MIG_ARRAY_TOO_LARGE)
++        err = ENOSYS;
++      else
++        {
++          cnt = 1;
++          err = device_get_status(irq, IRQGETPICMODE, pic_mode, &cnt);
++        }
++
++      device_close(irq);
++    }
++
++  mach_port_deallocate (mach_task_self (), devices);
++  return err;
++}
++
++static error_t
++acpi_set_pic_mode (int pic_mode)
++{
++  struct acpi_object_list arg;
++  union acpi_object obj;
++
++  if (pic_mode < ACPI_PICMODE_PIC || pic_mode > ACPI_PICMODE_SAPIC)
++    return EINVAL;
++
++  obj.type = ACPI_TYPE_INTEGER;
++  obj.integer.value = pic_mode;
++
++  arg.count = 1;
++  arg.pointer = &obj;
++
++  acpi_handle handle = ACPI_ROOT_OBJECT;
++  acpi_status rv = acpi_evaluate_object(handle, "\\_PIC", &arg, NULL);
++
++  /* A failure of AE_NOT_FOUND means the \_PIC method is not supported.
++     The default for the system in this case is ACPI_PICMODE_PIC, so
++     it is only a concern if an attempt is made to set a different mode.
++  */
++  return (ACPI_FAILURE(rv)
++        && (rv != AE_NOT_FOUND || (pic_mode != ACPI_PICMODE_PIC))
++        ? EIO
++        : 0);
++}
++
++static error_t
++acpi_configure_pic_mode (void)
++{
++  int pic_mode = -1;
++  error_t err = acpi_required_pic_mode (&pic_mode);
++
++  if (err)
++    {
++      acpi_os_printf("Cannot determine PIC mode: %s\n", strerror(err));
++      return err;
++    }
++
++  err = acpi_set_pic_mode (pic_mode);
++  if (err)
++    acpi_os_printf("Failed to set ACPI PIC mode: %s\n", strerror(err));
++
++  return err;
++}
++
 +void acpi_init(void)
 +{
 +  acpi_status err;
@@ -724,6 +814,10 @@
 +  if (ACPI_FAILURE (err))
 +    goto die;
 +
++  err = acpi_configure_pic_mode();
++  if (err)
++    goto die;
++
 +  err = acpi_enable_subsystem (ACPI_FULL_INITIALIZATION);
 +  if (ACPI_FAILURE (err))
 +    goto die;
-- 
2.45.2



Reply via email to