Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

media: cec-pin: improve interrupt handling

The CEC pin framework needs a bit more control over the interrupt
handling: make sure that the disable_irq op is called even if the
device node is unregistered, log the state of the interrupt in
debugfs, and disable the interrupt when the kernel thread is stopped.

Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>

authored by

Hans Verkuil and committed by
Mauro Carvalho Chehab
9b79d776 3b7dab49

+21 -8
+1
drivers/media/cec/core/cec-pin-priv.h
··· 183 183 u16 la_mask; 184 184 bool monitor_all; 185 185 bool rx_eom; 186 + bool enabled_irq; 186 187 bool enable_irq_failed; 187 188 enum cec_pin_state state; 188 189 struct cec_msg tx_msg;
+20 -8
drivers/media/cec/core/cec-pin.c
··· 1033 1033 { 1034 1034 struct cec_adapter *adap = _adap; 1035 1035 struct cec_pin *pin = adap->pin; 1036 - bool irq_enabled = false; 1037 1036 1037 + pin->enabled_irq = false; 1038 + pin->enable_irq_failed = false; 1038 1039 for (;;) { 1039 1040 wait_event_interruptible(pin->kthread_waitq, 1040 1041 kthread_should_stop() || ··· 1089 1088 switch (atomic_xchg(&pin->work_irq_change, 1090 1089 CEC_PIN_IRQ_UNCHANGED)) { 1091 1090 case CEC_PIN_IRQ_DISABLE: 1092 - if (irq_enabled) { 1093 - call_void_pin_op(pin, disable_irq); 1094 - irq_enabled = false; 1091 + if (pin->enabled_irq) { 1092 + pin->ops->disable_irq(adap); 1093 + pin->enabled_irq = false; 1094 + pin->enable_irq_failed = false; 1095 1095 } 1096 1096 cec_pin_high(pin); 1097 1097 if (pin->state == CEC_ST_OFF) ··· 1102 1100 HRTIMER_MODE_REL); 1103 1101 break; 1104 1102 case CEC_PIN_IRQ_ENABLE: 1105 - if (irq_enabled) 1103 + if (pin->enabled_irq || !pin->ops->enable_irq || 1104 + pin->adap->devnode.unregistered) 1106 1105 break; 1107 - pin->enable_irq_failed = !call_pin_op(pin, enable_irq); 1106 + pin->enable_irq_failed = !pin->ops->enable_irq(adap); 1108 1107 if (pin->enable_irq_failed) { 1109 1108 cec_pin_to_idle(pin); 1110 1109 hrtimer_start(&pin->timer, ns_to_ktime(0), 1111 1110 HRTIMER_MODE_REL); 1112 1111 } else { 1113 - irq_enabled = true; 1112 + pin->enabled_irq = true; 1114 1113 } 1115 1114 break; 1116 1115 default: 1117 1116 break; 1118 1117 } 1118 + } 1119 + 1120 + if (pin->enabled_irq) { 1121 + pin->ops->disable_irq(pin->adap); 1122 + pin->enabled_irq = false; 1123 + pin->enable_irq_failed = false; 1124 + cec_pin_high(pin); 1119 1125 } 1120 1126 return 0; 1121 1127 } ··· 1225 1215 seq_printf(file, "cec pin: %d\n", call_pin_op(pin, read)); 1226 1216 seq_printf(file, "cec pin events dropped: %u\n", 1227 1217 pin->work_pin_events_dropped_cnt); 1228 - seq_printf(file, "irq failed: %d\n", pin->enable_irq_failed); 1218 + if (pin->ops->enable_irq) 1219 + seq_printf(file, "irq %s\n", pin->enabled_irq ? "enabled" : 1220 + (pin->enable_irq_failed ? "failed" : "disabled")); 1229 1221 if (pin->timer_100us_overruns) { 1230 1222 seq_printf(file, "timer overruns > 100us: %u of %u\n", 1231 1223 pin->timer_100us_overruns, pin->timer_cnt);