linux-kernel linux-device-driver interrupt irq

linux kernel - La forma en que una operación de lectura y escritura I2c en "función de manejador" de request_threaded_irq afecta al controlador en su conjunto.



linux-kernel linux-device-driver (1)

Tengo un código de controlador con función de controlador y función de subproceso de request_threaded_irq similar a esto:

irq-handler fn() { /*disable device interrupt*/ i2c read from register; set disable bit to client-device-interrupt i2c write back; return IRQ_WAKe_THREAD; } irq-thread fn() { i2c read from register; .... .... /*enable device interrupt*/ i2c read from register; set enable bit to client-device-interrupt i2c write back; /*Rest of the operation*/ .......... .......... return IRQ_HANDLED; }

Tengo pocas preguntas con respecto a la implementación anterior.

  1. ¿El funcionamiento de 2 i2c en "handler fn" requiere una cantidad considerable de tiempo?

  2. ¿Debería hacer una manipulación de bits en "handler fn" atomic?

  3. ¿Debería mover la operación realizada hasta "habilitar la interrupción del dispositivo" de "thread fn" a "handler fn" (esto me costaría 4 operaciones más de i2c y una manipulación de un bit exactamente)? - razón por la que hay posibilidades de que pueda omitir la interrupción según la implementación del código anterior.

  4. Si lo hago (según la pregunta 3). ¿Cómo afecta a las otras interrupciones del dispositivo ( ya que tengo una duda básica de si "handler fn" en el contexto de IRQ duro opera con interrupciones deshabilitadas )

Por favor, bríndenme una solución buena y óptima para el escenario anterior.

Gracias por adelantado.


Las transferencias de lectura / escritura I2C NO son deterministas.

El protocolo permite que los IC esclavos periféricos realicen alarmas de reloj, lo que les permite "retener" el maestro hasta que estén listos. Sin embargo, este NO es un escenario común y, por lo tanto, cada transferencia de I2C generalmente se completa en un intervalo predeterminado la mayor parte del tiempo. Sin embargo, NO es una garantía, y por lo tanto NO es una buena idea realizar varias transferencias I2C dentro de un ISR.

Este enlace contiene una buena explicación sobre los fundamentos de los IRQs roscados y su uso adecuado.

Diseño óptimo para el escenario anterior

El uso del enfoque del manejador de interrupción con subprocesos no tendrá muchos beneficios, ya que intentar habilitar / deshabilitar las interrupciones en el dispositivo aumentará la latencia.

En su escenario actual (interrupción simple desde un solo dispositivo), uno puede apegarse al request_irq() regular para registrar una rutina de servicio de interrupción (ISR).

Código ISR :
1. En el ISR, llame a disable_irq() para evitar más interrupciones.
2. Programe una función de manejador de mitad inferior (la cola de trabajo es una buena opción).
3. Devuelve IRQ_HANDLED del ISR.

Código del controlador de la mitad inferior :
4. Realice transferencias I2C.
5. Llamar enable_irq() y salir.

NOTA :
Otra forma de implementar el mismo diseño sería usar un threaded-irq sin un ISR . Esto logra lo mismo que el diseño anterior y elimina la necesidad de definir / inicializar / limpiar el manejador de fondo inferior por separado en su código.

En este enfoque, uno pondría todo el código de lectura / escritura de I2C dentro de la función de subprocesos de IRQ y lo pasaría a request_threaded_irq() along-with handler = NULL es decir, un ISR vacío.