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

mei: synchronize irq before initiating a reset.

We need to synchronize irqs before issuing reset to make sure that the
clients communication is concluded and doesn't leak to the reset flow
and confusing the state machine.

This issue is happening during suspend/resume stress testing.

Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Tomas Winkler and committed by
Greg Kroah-Hartman
4a8efd4a 8d7cc7ad

+38 -4
+13
drivers/misc/mei/hw-me.c
··· 285 285 } 286 286 287 287 /** 288 + * mei_me_synchronize_irq - wait for pending IRQ handlers 289 + * 290 + * @dev: the device structure 291 + */ 292 + static void mei_me_synchronize_irq(struct mei_device *dev) 293 + { 294 + struct pci_dev *pdev = to_pci_dev(dev->dev); 295 + 296 + synchronize_irq(pdev->irq); 297 + } 298 + 299 + /** 288 300 * mei_me_hw_reset_release - release device from the reset 289 301 * 290 302 * @dev: the device structure ··· 1250 1238 .intr_clear = mei_me_intr_clear, 1251 1239 .intr_enable = mei_me_intr_enable, 1252 1240 .intr_disable = mei_me_intr_disable, 1241 + .synchronize_irq = mei_me_synchronize_irq, 1253 1242 1254 1243 .hbuf_free_slots = mei_me_hbuf_empty_slots, 1255 1244 .hbuf_is_ready = mei_me_hbuf_is_empty,
+14 -1
drivers/misc/mei/hw-txe.c
··· 19 19 #include <linux/ktime.h> 20 20 #include <linux/delay.h> 21 21 #include <linux/kthread.h> 22 - #include <linux/irqreturn.h> 22 + #include <linux/interrupt.h> 23 23 #include <linux/pm_runtime.h> 24 24 25 25 #include <linux/mei.h> ··· 438 438 439 439 mei_txe_br_reg_write(hw, HHIER_REG, IPC_HHIER_MSK); 440 440 mei_txe_br_reg_write(hw, HIER_REG, HIER_INT_EN_MSK); 441 + } 442 + 443 + /** 444 + * mei_txe_synchronize_irq - wait for pending IRQ handlers 445 + * 446 + * @dev: the device structure 447 + */ 448 + static void mei_txe_synchronize_irq(struct mei_device *dev) 449 + { 450 + struct pci_dev *pdev = to_pci_dev(dev->dev); 451 + 452 + synchronize_irq(pdev->irq); 441 453 } 442 454 443 455 /** ··· 1180 1168 .intr_clear = mei_txe_intr_clear, 1181 1169 .intr_enable = mei_txe_intr_enable, 1182 1170 .intr_disable = mei_txe_intr_disable, 1171 + .synchronize_irq = mei_txe_synchronize_irq, 1183 1172 1184 1173 .hbuf_free_slots = mei_txe_hbuf_empty_slots, 1185 1174 .hbuf_is_ready = mei_txe_is_input_ready,
+4 -2
drivers/misc/mei/init.c
··· 122 122 mei_dev_state_str(state), fw_sts_str); 123 123 } 124 124 125 + mei_clear_interrupts(dev); 126 + 127 + mei_synchronize_irq(dev); 128 + 125 129 /* we're already in reset, cancel the init timer 126 130 * if the reset was called due the hbm protocol error 127 131 * we need to call it before hw start ··· 276 272 int err; 277 273 278 274 mutex_lock(&dev->device_lock); 279 - 280 - mei_clear_interrupts(dev); 281 275 282 276 dev->dev_state = MEI_DEV_POWER_UP; 283 277 dev->reset_count = 0;
+7 -1
drivers/misc/mei/mei_dev.h
··· 267 267 * @intr_clear : clear pending interrupts 268 268 * @intr_enable : enable interrupts 269 269 * @intr_disable : disable interrupts 270 + * @synchronize_irq : synchronize irqs 270 271 * 271 272 * @hbuf_free_slots : query for write buffer empty slots 272 273 * @hbuf_is_ready : query if write buffer is empty ··· 289 288 int (*hw_start)(struct mei_device *dev); 290 289 void (*hw_config)(struct mei_device *dev); 291 290 292 - 293 291 int (*fw_status)(struct mei_device *dev, struct mei_fw_status *fw_sts); 294 292 enum mei_pg_state (*pg_state)(struct mei_device *dev); 295 293 bool (*pg_in_transition)(struct mei_device *dev); ··· 297 297 void (*intr_clear)(struct mei_device *dev); 298 298 void (*intr_enable)(struct mei_device *dev); 299 299 void (*intr_disable)(struct mei_device *dev); 300 + void (*synchronize_irq)(struct mei_device *dev); 300 301 301 302 int (*hbuf_free_slots)(struct mei_device *dev); 302 303 bool (*hbuf_is_ready)(struct mei_device *dev); ··· 639 638 static inline void mei_disable_interrupts(struct mei_device *dev) 640 639 { 641 640 dev->ops->intr_disable(dev); 641 + } 642 + 643 + static inline void mei_synchronize_irq(struct mei_device *dev) 644 + { 645 + dev->ops->synchronize_irq(dev); 642 646 } 643 647 644 648 static inline bool mei_host_is_ready(struct mei_device *dev)