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