Interrupciones de dispositivos externos en un sistema x86. Parte 3. Configuración del enrutamiento de interrupción en el conjunto de chips utilizando el ejemplo coreboot

Continuamos considerando configurar interrupciones desde dispositivos externos en el sistema x86.
En la parte 1 (La evolución de los controladores de interrupción ), examinamos los fundamentos teóricos de los controladores de interrupción y los términos generales; en la parte 2 ( Opciones de arranque del kernel de Linux ), observamos cómo el sistema operativo elige entre los controladores en la práctica. En esta parte, veremos cómo el BIOS configura el enrutamiento IRQ para los controladores de interrupción en el conjunto de chips.

Ninguna empresa moderna de desarrollo de BIOS (AwardBIOS / AMIBIOS / Insyde) divulga el código fuente de sus programas. Pero afortunadamente existe Coreboot , un proyecto para reemplazar el BIOS propietario con software libre. En su código, veremos cómo se configura el enrutamiento de interrupción en el conjunto de chips.




Teoría


Primero, actualizar y complementar nuestro conocimiento teórico. En la Parte 1, identificamos una ruta de interrupción común para el caso de PIC y APIC.

Pic:



APIC:



En estas figuras, el mapeo del dispositivo PCI → PIR se muestra de manera abstracta; de hecho, es algo más complicado. En realidad, cada dispositivo PCI tiene 4 líneas de interrupción (INTA #, INTB #, INTC #, INTD #). Cada dispositivo PCI puede tener hasta 8 funciones y cada función ya tiene una interrupción INTx #. La línea de INTx # que obtendrá cada función del dispositivo está fijada en el hardware o está determinada por la configuración del dispositivo.



En esencia, las funciones son bloques lógicos separados. Por ejemplo, en un dispositivo PCI puede haber una función controlador Smbus, función controlador SATA, función puente LPC. En el lado del sistema operativo, cada función es un dispositivo separado con su propio espacio de configuración PCI Config.

En el caso más simple (y más común) en un dispositivo PCI, solo hay una función, cuya interrupción es a través de la línea INTA #. Pero, en general, el dispositivo puede tener incluso más de 4 funciones (como dijimos antes de 8), entonces algunas de ellas deberán plantarse en una línea INTx # (las interrupciones PCI pueden dividir la línea). Además, para los dispositivos PCI incluidos en el conjunto de chips al escribir en registros especiales, a menudo es posible indicar qué funciones usan qué líneas INTx # (y si se usan en absoluto).

Sistematizando nuestro conocimiento, denotamos la ruta (enrutamiento) de las interrupciones de cualquier función PCI a través de INTx # → PIRQy → IRQz, donde:

  • INTx # - línea INT # (INTA #, INTB #, INTC #, INTD #) del dispositivo PCI que utilizará la función
  • PIRQy: la línea PIRQ (PIRQA, PIRQB, ...) desde el PIR al que está conectada la línea INTx #
  • IRQz: línea IRQ (0, 1, 2, ...) en el controlador de interrupción (APIC / PIC), que está conectado a la línea PIRQy

¿Por qué no puedes conectarte a todas partes INTA # → PIRQA, INTB # → PIRQB, ...?


¿Por qué molestarse en configurar el enrutamiento? Supongamos que decidimos no molestarnos y obtener todas las líneas de interrupción de todos los dispositivos PCI a las mismas líneas PIRQ. Digamos esto:

  • INTA # → PIRQA
  • INTB # → PIRQB
  • INTC # → PIRQC
  • INTD # → PIRQD

Como dijimos anteriormente, el caso más común es cuando un dispositivo PCI tiene una función y su interrupción está conectada a la línea INTA # (porque ¿por qué el desarrollador del dispositivo debe iniciarlo de manera diferente?). Entonces, si de repente decidimos comenzar todas las líneas como escribimos, entonces casi todas las interrupciones de los dispositivos se dividirán en líneas PIRQA. Digamos que terminó en IRQ16. Luego, cada vez que se informa al procesador que se ha producido una interrupción en la línea IRQ16, tendrá que interrogar a los controladores de todos los dispositivos conectados a la línea IRQ16 (PIRQA) si tienen una interrupción. Si hay muchos de estos dispositivos, esto naturalmente no acelerará la respuesta del sistema a la interrupción. Y las líneas PIRQB-PIRQD en este caso estarán inactivas en su mayor parte. Para mayor claridad, la figura que ilustra el problema:



Pero todo se podría hacer así:



La imagen es un poco confusa, pero el punto es que simplemente conectamos las líneas INTx # con PIRQy a round-robin (PIRQA, PIRQB, PIRQC, PIRQD, PIRQA, PIRQB, PIRQC, PIRQD, PIRQA, PIRQB, PIRQC, PIRQD). ..)

Cabe señalar que aquí es necesario tener en cuenta no solo que se carga el mismo número de funciones PCI en cada línea PIRQ. Después de todo, algunas funciones pueden crear interrupciones muy raramente, y algunas permanentemente (controlador Ethernet, por ejemplo). En este caso, incluso la asignación de una línea PIRQ separada para interrupciones con dicha función puede estar bastante justificada.

Con base en lo anterior, el desarrollador del BIOS, entre otras cosas, tiene la tarea de garantizar que las líneas PIRQ estén cargadas uniformemente con interrupciones.

¿Qué debe hacer el BIOS?


Sistematizamos en la figura:



  • 1) Indique qué línea de INTx # extrae cada función de los dispositivos PCI
    Para dispositivos PCI externos, este elemento no se realiza, pero para las funciones de los dispositivos PCI incluidos en el conjunto de chips puede ser.
  • 2) Configure la asignación INTx # → PIRQy para cada dispositivo PCI
    Vale la pena señalar que puede haber más de cuatro señales PIRQy estándar (PIRQA, PIRQB, PIRQC, PIRQD). Por ejemplo 8: PIRQA-PIRQH.

Las señales PIRQy van en la línea IRQz del controlador de interrupción seleccionado (APIC / PIC). Como queremos admitir todos los métodos de carga posibles (consulte la parte 2 ), debemos completar ambos mapas:

  • 3a) Complete el mapeo PIRQy → IRQz1 para la comunicación PIR → I / O APIC
    Pero generalmente esto no es necesario, ya que las líneas PIRQy están fijas en la línea APIC. La solución común es PIRQA → IRQ16, PIRQB → IRQ17, ... La solución más simple, porque Al colocar líneas PIRQy en líneas de controlador ≥16, no tiene que preocuparse por conflictos con interrupciones inseparables de dispositivos ISA.
  • 3b) Rellene el mapeo PIRQy → IRQz2 para la comunicación PIR → PIC
    Esto debe proporcionarse en caso de que usemos enrutamiento a través del controlador PIC. No existe una solución tan inequívoca como en el caso de APIC, porque en el caso de PIC, uno debe recordar la posibilidad de conflictos con interrupciones inseparables de los dispositivos ISA.

El último cuarto elemento es necesario para ayudar al sistema operativo a determinar el enrutamiento de interrupción. El dispositivo en sí generalmente no utiliza estos registros.

  • 4) Complete los registros de línea de interrupción / pin de interrupción para cada función PCI
    En general, el registro de Pin de interrupción se rellena automáticamente y generalmente es de solo lectura, por lo que lo más probable es que solo sea necesario completar el registro de la línea de interrupción. Esto debe proporcionarse en caso de que utilicemos el enrutamiento a través del controlador PIC sin proporcionar al sistema operativo ninguna tabla sobre las interrupciones de enrutamiento (consulte nuevamente la parte 2 ). Si se proporcionan tablas y esta asignación es coherente con las tablas de enrutamiento ($ PIR / ACPI), el sistema operativo a menudo la abandona.

Cabe señalar que todavía no tocamos las tablas $ PIR / MPtable / ACPI y consideramos cómo configurar los registros del conjunto de chips en términos de interrupciones de enrutamiento antes de transferir el control al cargador del sistema. Las tablas de interrupción son un tema para un artículo separado (posiblemente uno futuro).

Entonces, se estudian los fundamentos teóricos, ¡finalmente comenzamos a practicar!

Practica


Como ejemplo para los artículos de esta serie, uso una placa personalizada con un procesador Intel Haswell i7 y un chipset LynxPoint-LP. En esta placa, lancé coreboot junto con SeaBIOS. Coreboot proporciona inicialización específica de hardware, y la carga útil de SeaBIOS proporciona una interfaz de BIOS para sistemas operativos. En este artículo, no describiré el proceso de configuración de coreboot, sino que trataré de mostrar con un ejemplo qué tipo de configuración de BIOS se debe realizar en el conjunto de chips para enrutar las interrupciones IRQ desde dispositivos externos.

Dado que el proyecto coreboot se está desarrollando activamente para que el artículo esté siempre actualizado, consideraremos el código utilizando el ejemplo de la última versión fija 4.9 (versión 2018-12-20).

La placa base más cercana a la mía es Google Beltino con variación Panther. La carpeta principal de esta placa base es la carpeta "src \ mainboard \ google \ beltino" . Todas las configuraciones se concentran aquí y el código específico de esta placa.

Entonces, comencemos a ordenar dónde están configurados los elementos anteriores:

1) Indique qué línea de INTx # extrae cada función de los dispositivos PCI


Esta información se define en el archivo "src / mainboard / google / beltino / romstage.c" en la estructura rcba_config a través de los registros DxxIP (Device xx Interrupt Pin Register (IP)). Este registro indica qué pin INTx # (A / B / C / D) cada una de las funciones del dispositivo emite una interrupción.

Opciones posibles (vea el archivo "src / southbridge / intel / lynxpoint / pch.h" ):

0h = No interrupt 1h = INTA# 2h = INTB# 3h = INTC# 4h = INTD# 

Se supone que varias funciones usan el mismo pin.

Se supone que las funciones no pueden usar el pin para las interrupciones (sin interrupción).
Todo lo que vimos en la figura al comienzo del artículo.

El código completo es responsable del artículo designado por nosotros:

 /* Device interrupt pin register (board specific) */ RCBA_SET_REG_32(D31IP, (INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) | (INTB << D31IP_SMIP) | (INTA << D31IP_SIP)), RCBA_SET_REG_32(D29IP, (INTA << D29IP_E1P)), RCBA_SET_REG_32(D28IP, (INTA << D28IP_P1IP) | (INTC << D28IP_P3IP) | (INTB << D28IP_P4IP)), RCBA_SET_REG_32(D27IP, (INTA << D27IP_ZIP)), RCBA_SET_REG_32(D26IP, (INTA << D26IP_E2P)), RCBA_SET_REG_32(D22IP, (NOINT << D22IP_MEI1IP)), RCBA_SET_REG_32(D20IP, (INTA << D20IP_XHCI)), 

Para una mejor comprensión, considere algunos ejemplos:

Ejemplo 1:

El dispositivo 0x1d (29 en decimal) tiene una función (controlador EHCI).

En este caso, asigne una interrupción a INTA #.

00: 1d.0 - INTA #

 RCBA_SET_REG_32(D29IP, (INTA << D29IP_E1P)), 

Ejemplo 2
El dispositivo 0x1f (31 en decimal) tiene las funciones controlador de sensor térmico (00: 1f.6), controlador SATA 2 (00: 1f.2), controlador SMBus (00: 1f.3), controlador SATA 1 (00: 1f .2). Queremos utilizar solo el controlador SMBus, el controlador SATA 1 y el controlador del sensor térmico.

00: 1f.2 - INTA # (controlador SATA 1)
00: 1f.3 - INTB # (controlador SMBus)
00: 1f.2 - Sin interrupción (el controlador SATA 2 no se usa)
00: 1f.6 - INTC # (controlador del sensor térmico)

Para esta configuración, debe escribir:

 RCBA_SET_REG_32(D31IP, (INTC << D31IP_TTIP) | (NOINT << D31IP_SIP2) | (INTB << D31IP_SMIP) | (INTA << D31IP_SIP)), 

Ejemplo 3

En un dispositivo, el número de funciones que necesitamos es más de 4. En el dispositivo 0x1c, cada función es responsable del puerto PCI Express. Para que los puertos 0-5 funcionen, y las interrupciones se distribuyan entre las líneas de manera uniforme, puede configurar esto:

00: 1c.0 - INTA # (puerto PCI Express 0)
00.1c.1 - INTB # (puerto PCI Express 1)
00.1c.2 - INTC # (puerto PCI Express 2)
00.1c.3 - INTD # (puerto PCI Express 3)
00.1c.4 - INTA # (puerto PCI Express 4)
00.1c.5 - INTB # (puerto PCI Express 5)
00.1c.6 - Sin interrupción (puerto no utilizado)
00.1c.7 - Sin interrupción (puerto no utilizado)

 RCBA_SET_REG_32(D28IP, (INTA << D28IP_P1IP) | (INTB << D28IP_P2IP) | (INTC << D28IP_P3IP) | (INTD << D28IP_P4IP) | (INTA << D28IP_P5IP) | (INTB << D28IP_P6IP) | (NOINT << D28IP_P7IP) | (NOINT << D28IP_P8IP)), 

2) Configure la asignación INTx # → PIRQy para cada dispositivo PCI


Esta información también se define en el archivo "src \ mainboard \ google \ beltino \ romstage.c"
en la estructura rcba_config, pero ya a través de los registros DxxIR (Device xx Interrupt Route Register).

La información en este registro muestra a qué línea PIRQx (A / B / C / D / E / F / G / H) está conectada cada línea de interrupción INTx #.

 /* Device interrupt route registers */ RCBA_SET_REG_32(D31IR, DIR_ROUTE(PIRQG, PIRQC, PIRQB, PIRQA)),/* LPC */ RCBA_SET_REG_32(D29IR, DIR_ROUTE(PIRQD, PIRQD, PIRQD, PIRQD)),/* EHCI */ RCBA_SET_REG_32(D28IR, DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD)),/* PCIE */ RCBA_SET_REG_32(D27IR, DIR_ROUTE(PIRQG, PIRQG, PIRQG, PIRQG)),/* HDA */ RCBA_SET_REG_32(D22IR, DIR_ROUTE(PIRQA, PIRQA, PIRQA, PIRQA)),/* ME */ RCBA_SET_REG_32(D21IR, DIR_ROUTE(PIRQE, PIRQF, PIRQF, PIRQF)),/* SIO */ RCBA_SET_REG_32(D20IR, DIR_ROUTE(PIRQC, PIRQC, PIRQC, PIRQC)),/* XHCI */ RCBA_SET_REG_32(D23IR, DIR_ROUTE(PIRQH, PIRQH, PIRQH, PIRQH)),/* SDIO */ 

Ejemplo 1:

El dispositivo 0x1c (28 en el sistema decimal) son los puertos PCIe como ya descubrimos.

Hacemos una conexión "directa":

  • INTA # → PIRQA
  • INTB # → PIRQB
  • INTC # → PIRQC
  • INTD # → PIRQD

 RCBA_SET_REG_32(D28IR, DIR_ROUTE(PIRQA, PIRQB, PIRQC, PIRQD)) 

Ejemplo 2

Dispositivo 0x1d (29 en decimal): una función (controlador EHCI) en INTA #, no se utilizan otras líneas.

Conecte la línea INTA # a PIRQD:

 RCBA_SET_REG_32(D29IR, DIR_ROUTE(PIRQD, PIRQD, PIRQD, PIRQD)) 

En este caso, solo el primer registro PIRQD (para INTA #) tiene sentido, el resto no tiene sentido.

3a) Rellene el mapeo PIRQy → IRQz1 (PIR → APIC)


Como ya hemos dicho, el mapeo a menudo se arregla aquí, y este caso no es una excepción.

  • PIRQA → IRQ16
  • PIRQB → IRQ17
  • ...
  • PIRQH → IRQ23

3b) Rellene el mapeo PIRQy → IRQz2 (PIR → PIC)


En coreboot, el contenido para llenar estos registros se define en el archivo devicetree.cb en la carpeta de la placa base "src \ mainboard \ google \ beltino \".

devicetree.cb (el nombre devicetree para la comunicación con un concepto similar en el kernel de Linux, y "cb" es la abreviatura de coreboot) es un archivo especial que refleja la configuración de esta placa base: qué procesador, qué chipset se utilizan, qué dispositivos se incluyen en ellos, qué apagado, etc. Además, se puede especificar información especial para la configuración del conjunto de chips en este archivo. Este es solo el caso que necesitamos:

 register "pirqa_routing" = "0x8b" register "pirqb_routing" = "0x8a" register "pirqc_routing" = "0x8b" register "pirqd_routing" = "0x8b" register "pirqe_routing" = "0x80" register "pirqf_routing" = "0x80" register "pirqg_routing" = "0x80" register "pirqh_routing" = "0x80" 

Estas líneas especifican la asignación PIRQy → IRQz2. En el código, después de analizar el archivo devicetree.cb, se transforman en las variables "config-> pirqX_routing".

La variable "config-> pirqa_routing = 0x8b" significará que el PIRQA está conectado a la línea de interrupción IRIC11 (0x0b = 11) del controlador PIC, sin embargo, el bit más alto (que es 0x80) significa que no se realiza el enrutamiento de interrupción. Honestamente, en mi experiencia, esto es un error, por defecto vale la pena activar el enrutamiento PIC, el sistema operativo en sí mismo podrá cambiar a I / O APIC configurando este bit a 1 si es necesario.

Es decir, en este caso sería más correcto escribir:

 register "pirqa_routing" = "0x0b" register "pirqb_routing" = "0x0a" register "pirqc_routing" = "0x0b" register "pirqd_routing" = "0x0b" register "pirqe_routing" = "0x80" # not used register "pirqf_routing" = "0x80" # not used register "pirqg_routing" = "0x80" # not used register "pirqh_routing" = "0x80" # not used 

No habilitamos las últimas 4 interrupciones, porque La interrupción IRQ0 siempre se usa bajo el temporizador del sistema y claramente no está disponible (consulte Información general de interrupción compatible con IBM-PC )

Pero si miramos más de cerca el punto 2), veremos que algunos dispositivos PCI usan las líneas PIRQE-PIRQH, por lo que dejarlos desconectados es la forma correcta de dispositivos rotos.

Entonces es mejor escribir algo como esto:
 register "pirqa_routing" = "0x03" register "pirqb_routing" = "0x04" register "pirqc_routing" = "0x05" register "pirqd_routing" = "0x06" register "pirqe_routing" = "0x0a" register "pirqf_routing" = "0x0b" register "pirqg_routing" = "0x0e" register "pirqh_routing" = "0x0f" 


El llenado real de los registros correspondientes se produce en el archivo src \ southbridge \ intel \ lynxpoint \ lpc.c en la función pch_pirq_init.

Fragmento de código responsable del llenado del registro:

 /* Get the chip configuration */ config_t *config = dev->chip_info; pci_write_config8(dev, PIRQA_ROUT, config->pirqa_routing); pci_write_config8(dev, PIRQB_ROUT, config->pirqb_routing); pci_write_config8(dev, PIRQC_ROUT, config->pirqc_routing); pci_write_config8(dev, PIRQD_ROUT, config->pirqd_routing); pci_write_config8(dev, PIRQE_ROUT, config->pirqe_routing); pci_write_config8(dev, PIRQF_ROUT, config->pirqf_routing); pci_write_config8(dev, PIRQG_ROUT, config->pirqg_routing); pci_write_config8(dev, PIRQH_ROUT, config->pirqh_routing); 

Las constantes de dirección de registro se describen en el mismo archivo pch.h

 #define PIRQA_ROUT 0x60 #define PIRQB_ROUT 0x61 #define PIRQC_ROUT 0x62 #define PIRQD_ROUT 0x63 #define PIRQE_ROUT 0x68 #define PIRQF_ROUT 0x69 #define PIRQG_ROUT 0x6A #define PIRQH_ROUT 0x6B 

El mapeo PIRQy → IRQz2 para este chipset se escribe en el dispositivo PCI LPC (dirección 00: 1f.0) en los registros PIRQy_ROUT. Cabe señalar que a menudo no se permiten el uso de todas las 15 líneas IRQz2 por PIC, sino solo una parte (por ejemplo, 3,4,5,6,7,9,10,11,12,14,15). La descripción de estos registros debe contener información sobre qué IRQ están disponibles para asignarles interrupciones de líneas PIRQ. Entonces, el mapeo propuesto por nosotros arriba solo es posible si la asignación de PIRQ en la línea IRQ3, IRQ4, IRQ5, IRQ6, IRQ10, IRQ11, IRQ14, IRQ15 está disponible. Pero si miramos cuidadosamente el comentario antes de la función pch_pirq_init, veremos que es:

 /* PIRQ[n]_ROUT[3:0] - PIRQ Routing Control * 0x00 - 0000 = Reserved * 0x01 - 0001 = Reserved * 0x02 - 0010 = Reserved * 0x03 - 0011 = IRQ3 * 0x04 - 0100 = IRQ4 * 0x05 - 0101 = IRQ5 * 0x06 - 0110 = IRQ6 * 0x07 - 0111 = IRQ7 * 0x08 - 1000 = Reserved * 0x09 - 1001 = IRQ9 * 0x0A - 1010 = IRQ10 * 0x0B - 1011 = IRQ11 * 0x0C - 1100 = IRQ12 * 0x0D - 1101 = Reserved * 0x0E - 1110 = IRQ14 * 0x0F - 1111 = IRQ15 * PIRQ[n]_ROUT[7] - PIRQ Routing Control * 0x80 - The PIRQ is not routed. */ 

4) Complete los registros de línea de interrupción / pin de interrupción para cada función PCI


En el espacio de configuración de PCI (cada PCI tiene funciones de acuerdo con el estándar) hay 2 registros de interés para nosotros:

  • 3Ch: Línea de interrupción: aquí debe escribir el número IRQz2 (un número del 0 al 15), el número de interrupción que la función finalmente obtiene al usar el controlador PIC
  • 3Dh: Pin de interrupción: muestra qué línea INTx # (A / B / C / D) usa la función

Comencemos con el último. El registro de Pin de interrupción se completará automáticamente en función de la configuración del conjunto de chips (registros DxxIP) realizada por nosotros en el párrafo 1 y será de solo lectura.

Entonces, todo lo que queda es llenar el registro de la línea de interrupción con una interrupción IRQz2 para cada función PCI.

Conociendo el mapeo PIRQy → IRQz2 (elemento 3b) y el mapeo INTx # → PIRQy (elemento 2), puede completar fácilmente el registro de la línea de interrupción para cada función, sabiendo qué interrupción INTx # utiliza (elemento 1).

En coreboot, los registros de la línea de interrupción también se rellenan en el archivo src \ southbridge \ intel \ lynxpoint \ lpc.c en la función pch_pirq_init:

 /* Eric Biederman once said we should let the OS do this. * I am not so sure anymore he was right. */ for (irq_dev = all_devices; irq_dev; irq_dev = irq_dev->next) { u8 int_pin=0, int_line=0; if (!irq_dev->enabled || irq_dev->path.type != DEVICE_PATH_PCI) continue; int_pin = pci_read_config8(irq_dev, PCI_INTERRUPT_PIN); switch (int_pin) { case 1: /* INTA# */ int_line = config->pirqa_routing; break; case 2: /* INTB# */ int_line = config->pirqb_routing; break; case 3: /* INTC# */ int_line = config->pirqc_routing; break; case 4: /* INTD# */ int_line = config->pirqd_routing; break; } if (!int_line) continue; pci_write_config8(irq_dev, PCI_INTERRUPT_LINE, int_line); } 

Por alguna razón, este código implica que la asignación es en cualquier caso INTA # → PIRQA, INTB # → PIRQB, INTC # → PIRQC, INTD # → PIRQD. Aunque en la práctica vimos que puede ser diferente (ver párrafo 2).

En general, "Eric Biederman dijo una vez", y lo copiamos en cualquier lugar:

 $ grep "Eric Biederman once said" -r src/ src/southbridge/intel/fsp_bd82x6x/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/i82801gx/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/i82801ix/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/lynxpoint/lpc.c: /* Eric Biederman once said we should let the OS do this. src/southbridge/intel/sch/lpc.c: /* Eric Biederman once said we should let the OS do this. 

En general, coreboot realmente no se preocupa por el soporte de interrupción heredado. Mucho de sorprenderse por este error no vale la pena. Al cargar un sistema operativo moderno, esto no le molestará, pero si de repente necesita cargar Linux con las opciones "acpi = off nolapic", entonces esto es casi imposible.

Conclusión


En conclusión, repetiremos la información típica que debe configurarse en el conjunto de chips para enrutar las interrupciones PCI:

  1. Indique qué línea INTx # extrae cada función PCI
  2. Configure la asignación INTx # → PIRQy para cada dispositivo PCI
  3. Mapeo de relleno PIRQy → IRQz1 (PIR → APIC) y mapeo PIRQy → IRQz2 (PIR → PIC)
  4. Complete los registros de Línea de interrupción / Pin de interrupción del espacio de configuración PCI para cada función PCI.

Source: https://habr.com/ru/post/440304/


All Articles