[PATCH] mac_esp: fix for quadras with two esp chips

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Finn Thain <fthain@xxxxxxxxxxxxxxxxxxx>

On the Quadra 900 and 950 there are two ESP chips sharing one IRQ. Because 
the shared IRQ is edge-triggered, we must make sure that an IRQ transition 
from one chip doesn't go unnoticed when the shared IRQ is already active 
due to the other. This patch prevents interrupts getting lost so that both 
SCSI busses may be used simultaneously.

Signed-off-by: Finn Thain <fthain@xxxxxxxxxxxxxxxxxxx>
Signed-off-by: Geert Uytterhoeven <geert@xxxxxxxxxxxxxx>
---
Can I queue it in the m68k tree for 2.6.29, or do you want it to go in through
the SCSI tree?

 drivers/scsi/mac_esp.c |   83 ++++++++++++++++++++++++++++++++++---------------
 1 file changed, 59 insertions(+), 24 deletions(-)

--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -53,7 +53,8 @@ struct mac_esp_priv {
 	void __iomem *pdma_io;
 	int error;
 };
-static struct platform_device *internal_esp, *external_esp;
+static struct platform_device *internal_pdev, *external_pdev;
+static struct esp *esp_chips[2];
 
 #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \
 			       platform_get_drvdata((struct platform_device *) \
@@ -443,6 +444,32 @@ static u32 mac_esp_dma_length_limit(stru
 	return dma_len > 0xFFFF ? 0xFFFF : dma_len;
 }
 
+static irqreturn_t mac_scsi_esp_intr(int irq, void *dev_id)
+{
+	int got_intr;
+
+	/*
+	 * This is an edge triggered IRQ, so we have to be careful to
+	 * avoid missing a transition when it is shared by two ESP devices.
+	 */
+
+	do {
+		got_intr = 0;
+		if (esp_chips[0] &&
+		    (mac_esp_read8(esp_chips[0], ESP_STATUS) & ESP_STAT_INTR)) {
+			(void)scsi_esp_intr(irq, esp_chips[0]);
+			got_intr = 1;
+		}
+		if (esp_chips[1] &&
+		    (mac_esp_read8(esp_chips[1], ESP_STATUS) & ESP_STAT_INTR)) {
+			(void)scsi_esp_intr(irq, esp_chips[1]);
+			got_intr = 1;
+		}
+	} while (got_intr);
+
+	return IRQ_HANDLED;
+}
+
 static struct esp_driver_ops mac_esp_ops = {
 	.esp_write8       = mac_esp_write8,
 	.esp_read8        = mac_esp_read8,
@@ -557,10 +584,16 @@ static int __devinit esp_mac_probe(struc
 	}
 
 	host->irq = IRQ_MAC_SCSI;
-	err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "Mac ESP",
-			  esp);
-	if (err < 0)
-		goto fail_free_priv;
+	esp_chips[dev->id] = esp;
+	mb();
+	if (esp_chips[!dev->id] == NULL) {
+		err = request_irq(host->irq, mac_scsi_esp_intr, 0,
+		                  "Mac ESP", NULL);
+		if (err < 0) {
+			esp_chips[dev->id] = NULL;
+			goto fail_free_priv;
+		}
+	}
 
 	err = scsi_esp_register(esp, &dev->dev);
 	if (err)
@@ -569,7 +602,8 @@ static int __devinit esp_mac_probe(struc
 	return 0;
 
 fail_free_irq:
-	free_irq(host->irq, esp);
+	if (esp_chips[!dev->id] == NULL)
+		free_irq(host->irq, esp);
 fail_free_priv:
 	kfree(mep);
 fail_free_command_block:
@@ -588,7 +622,9 @@ static int __devexit esp_mac_remove(stru
 
 	scsi_esp_unregister(esp);
 
-	free_irq(irq, esp);
+	esp_chips[dev->id] = NULL;
+	if (!(esp_chips[0] || esp_chips[1]))
+		free_irq(irq, NULL);
 
 	kfree(mep);
 
@@ -615,19 +651,18 @@ static int __init mac_esp_init(void)
 	if (err)
 		return err;
 
-	internal_esp = platform_device_alloc(DRV_MODULE_NAME, 0);
-	if (internal_esp && platform_device_add(internal_esp)) {
-		platform_device_put(internal_esp);
-		internal_esp = NULL;
+	internal_pdev = platform_device_alloc(DRV_MODULE_NAME, 0);
+	if (internal_pdev && platform_device_add(internal_pdev)) {
+		platform_device_put(internal_pdev);
+		internal_pdev = NULL;
 	}
-
-	external_esp = platform_device_alloc(DRV_MODULE_NAME, 1);
-	if (external_esp && platform_device_add(external_esp)) {
-		platform_device_put(external_esp);
-		external_esp = NULL;
+	external_pdev = platform_device_alloc(DRV_MODULE_NAME, 1);
+	if (external_pdev && platform_device_add(external_pdev)) {
+		platform_device_put(external_pdev);
+		external_pdev = NULL;
 	}
 
-	if (internal_esp || external_esp) {
+	if (internal_pdev || external_pdev) {
 		return 0;
 	} else {
 		platform_driver_unregister(&esp_mac_driver);
@@ -639,13 +674,13 @@ static void __exit mac_esp_exit(void)
 {
 	platform_driver_unregister(&esp_mac_driver);
 
-	if (internal_esp) {
-		platform_device_unregister(internal_esp);
-		internal_esp = NULL;
-	}
-	if (external_esp) {
-		platform_device_unregister(external_esp);
-		external_esp = NULL;
+	if (internal_pdev) {
+		platform_device_unregister(internal_pdev);
+		internal_pdev = NULL;
+	}
+	if (external_pdev) {
+		platform_device_unregister(external_pdev);
+		external_pdev = NULL;
 	}
 }
 

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux