diff mbox series

[113/120] USB: OHCI: OHCI_INTR_MIE workaround for freeze on the PlayStation 2

Message ID 786e161e0e7f52ca14e635e3f1225e76b5f7833b.1567326213.git.noring@nocrew.org (mailing list archive)
State RFC
Headers show
Series Linux for the PlayStation 2 | expand

Commit Message

Fredrik Noring Sept. 1, 2019, 4:35 p.m. UTC
OHCI_INTR_MIE needs to be disabled, most likely due to a hardware bug.
Without it, reading a large amount of data (> 1 GB) from a mass storage
device results in a freeze.

Signed-off-by: Fredrik Noring <noring@nocrew.org>
---
 drivers/usb/host/ohci-ps2.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
diff mbox series

Patch

diff --git a/drivers/usb/host/ohci-ps2.c b/drivers/usb/host/ohci-ps2.c
index a1d446313c13..cdbcbe5ff34e 100644
--- a/drivers/usb/host/ohci-ps2.c
+++ b/drivers/usb/host/ohci-ps2.c
@@ -35,6 +35,7 @@  struct ps2_hcd {
 };
 
 static struct hc_driver __read_mostly ohci_ps2_hc_driver;
+static irqreturn_t (*ohci_irq)(struct usb_hcd *hcd);
 
 static void ohci_ps2_enable(struct usb_hcd *hcd)
 {
@@ -79,6 +80,21 @@  static int ohci_ps2_reset(struct usb_hcd *hcd)
 	return 0;
 }
 
+static irqreturn_t ohci_ps2_irq(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	struct ohci_regs __iomem *regs = ohci->regs;
+
+	/*
+	 * OHCI_INTR_MIE needs to be disabled, most likely due to a
+	 * hardware bug. Without it, reading a large amount of data
+	 * (> 1 GB) from a mass storage device results in a freeze.
+	 */
+	ohci_writel(ohci, OHCI_INTR_MIE, &regs->intrdisable);
+
+	return ohci_irq(hcd);	/* Call normal IRQ handler. */
+}
+
 static int iopheap_alloc_dma_buffer(struct platform_device *pdev, size_t size)
 {
 	struct device *dev = &pdev->dev;
@@ -228,6 +244,9 @@  static int __init ohci_ps2_init(void)
 
 	ohci_init_driver(&ohci_ps2_hc_driver, &ps2_overrides);
 
+	ohci_irq = ohci_ps2_hc_driver.irq;	/* Save normal IRQ handler. */
+	ohci_ps2_hc_driver.irq = ohci_ps2_irq;	/* Install IRQ workaround. */
+
 	return platform_driver_register(&ohci_hcd_ps2_driver);
 }
 module_init(ohci_ps2_init);