Linux IRQ: снятие маски с IRQ в ISR
У меня есть IRQ, который использует handle_level_irq()
, Большую часть времени ISR требует, чтобы нижняя половина была запланирована, но иногда она может определить, что она ложная, и не хочет планировать нижнюю половину (по соображениям производительности). Проблема в том, что в последнем случае возникает условие гонки. Если ISR определит, что он является ложным, он разоблачит прерывание и подготовится к выходу (примечание - ISR не защищен desc->lock
с этой точки зрения). Но затем прерывание срабатывает на втором процессоре, который, согласно handle_level_irq()
, хватает desc->lock
, маскирует IRQ, определяет, что ISR выполняется на первом процессоре, поэтому он разблокируется desc->lock
и выходит. Исходный ISR на первом процессоре также затем завершится, оставив прерывание замаскированным на все время.
Я хотел бы иметь возможность НЕ планировать нижнюю половину, если мне не нужно, так есть ли какой-нибудь способ для ISR разоблачить себя, избегая вышеуказанного состояния гонки?
1 ответ
Проблема в том, что IRQ является триггером уровня, и у вас есть ложное значение. Как значение уровня должно разрешаться, если оно получает ложное прерывание? Т.е. по природе ложного, прерывание в настоящее время находится на активном уровне. Вот почему Linux маскирует прерывания, чтобы предотвратить тупик процессора с ложными прерываниями.
Вы можете изменить уровень прерывания на инициируемый фронт, а на следующем переходе - обратно на уровень, инициированный. Это позволит отклонить ложный уровень до тех пор, пока аппаратное обеспечение не подтвердит его. Когда аппаратное обеспечение повторно устанавливает прерывание, возникает перегрузка, и на этом уровне запуска триггера может быть установлено заново.
По этой причине большинство периферийных устройств запускаются по фронту, если линия прерывания не используется совместно. Эта проблема может быть в вашем контроллере прерываний, а не в handle_level_irq()
код. Вы не указали версию или драйвер, который используете.
Если линия не является общей и ваш контроллер поддерживает запуск по краю, я бы преобразовал ваш код в использование края. Смотрите больше в Википедии.