diff options
Diffstat (limited to 'drivers/scsi/mac_esp.c')
-rw-r--r-- | drivers/scsi/mac_esp.c | 100 |
1 files changed, 68 insertions, 32 deletions
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 887682a24e36..c24e86f07804 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c | |||
@@ -53,7 +53,8 @@ struct mac_esp_priv { | |||
53 | void __iomem *pdma_io; | 53 | void __iomem *pdma_io; |
54 | int error; | 54 | int error; |
55 | }; | 55 | }; |
56 | static struct platform_device *internal_esp, *external_esp; | 56 | static struct platform_device *internal_pdev, *external_pdev; |
57 | static struct esp *esp_chips[2]; | ||
57 | 58 | ||
58 | #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ | 59 | #define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ |
59 | platform_get_drvdata((struct platform_device *) \ | 60 | platform_get_drvdata((struct platform_device *) \ |
@@ -170,7 +171,7 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp) | |||
170 | 171 | ||
171 | #define MAC_ESP_PDMA_LOOP(operands) \ | 172 | #define MAC_ESP_PDMA_LOOP(operands) \ |
172 | asm volatile ( \ | 173 | asm volatile ( \ |
173 | " tstw %2 \n" \ | 174 | " tstw %1 \n" \ |
174 | " jbeq 20f \n" \ | 175 | " jbeq 20f \n" \ |
175 | "1: movew " operands " \n" \ | 176 | "1: movew " operands " \n" \ |
176 | "2: movew " operands " \n" \ | 177 | "2: movew " operands " \n" \ |
@@ -188,14 +189,14 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp) | |||
188 | "14: movew " operands " \n" \ | 189 | "14: movew " operands " \n" \ |
189 | "15: movew " operands " \n" \ | 190 | "15: movew " operands " \n" \ |
190 | "16: movew " operands " \n" \ | 191 | "16: movew " operands " \n" \ |
191 | " subqw #1,%2 \n" \ | 192 | " subqw #1,%1 \n" \ |
192 | " jbne 1b \n" \ | 193 | " jbne 1b \n" \ |
193 | "20: tstw %3 \n" \ | 194 | "20: tstw %2 \n" \ |
194 | " jbeq 30f \n" \ | 195 | " jbeq 30f \n" \ |
195 | "21: movew " operands " \n" \ | 196 | "21: movew " operands " \n" \ |
196 | " subqw #1,%3 \n" \ | 197 | " subqw #1,%2 \n" \ |
197 | " jbne 21b \n" \ | 198 | " jbne 21b \n" \ |
198 | "30: tstw %4 \n" \ | 199 | "30: tstw %3 \n" \ |
199 | " jbeq 40f \n" \ | 200 | " jbeq 40f \n" \ |
200 | "31: moveb " operands " \n" \ | 201 | "31: moveb " operands " \n" \ |
201 | "32: nop \n" \ | 202 | "32: nop \n" \ |
@@ -223,8 +224,8 @@ static inline int mac_esp_wait_for_dreq(struct esp *esp) | |||
223 | " .long 31b,40b \n" \ | 224 | " .long 31b,40b \n" \ |
224 | " .long 32b,40b \n" \ | 225 | " .long 32b,40b \n" \ |
225 | " .previous \n" \ | 226 | " .previous \n" \ |
226 | : "+a" (addr) \ | 227 | : "+a" (addr), "+r" (count32), "+r" (count2) \ |
227 | : "a" (mep->pdma_io), "r" (count32), "r" (count2), "g" (esp_count)) | 228 | : "g" (count1), "a" (mep->pdma_io)) |
228 | 229 | ||
229 | static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, | 230 | static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, |
230 | u32 dma_count, int write, u8 cmd) | 231 | u32 dma_count, int write, u8 cmd) |
@@ -247,19 +248,20 @@ static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, | |||
247 | do { | 248 | do { |
248 | unsigned int count32 = esp_count >> 5; | 249 | unsigned int count32 = esp_count >> 5; |
249 | unsigned int count2 = (esp_count & 0x1F) >> 1; | 250 | unsigned int count2 = (esp_count & 0x1F) >> 1; |
251 | unsigned int count1 = esp_count & 1; | ||
250 | unsigned int start_addr = addr; | 252 | unsigned int start_addr = addr; |
251 | 253 | ||
252 | if (mac_esp_wait_for_dreq(esp)) | 254 | if (mac_esp_wait_for_dreq(esp)) |
253 | break; | 255 | break; |
254 | 256 | ||
255 | if (write) { | 257 | if (write) { |
256 | MAC_ESP_PDMA_LOOP("%1@,%0@+"); | 258 | MAC_ESP_PDMA_LOOP("%4@,%0@+"); |
257 | 259 | ||
258 | esp_count -= addr - start_addr; | 260 | esp_count -= addr - start_addr; |
259 | } else { | 261 | } else { |
260 | unsigned int n; | 262 | unsigned int n; |
261 | 263 | ||
262 | MAC_ESP_PDMA_LOOP("%0@+,%1@"); | 264 | MAC_ESP_PDMA_LOOP("%0@+,%4@"); |
263 | 265 | ||
264 | if (mac_esp_wait_for_empty_fifo(esp)) | 266 | if (mac_esp_wait_for_empty_fifo(esp)) |
265 | break; | 267 | break; |
@@ -442,6 +444,32 @@ static u32 mac_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) | |||
442 | return dma_len > 0xFFFF ? 0xFFFF : dma_len; | 444 | return dma_len > 0xFFFF ? 0xFFFF : dma_len; |
443 | } | 445 | } |
444 | 446 | ||
447 | static irqreturn_t mac_scsi_esp_intr(int irq, void *dev_id) | ||
448 | { | ||
449 | int got_intr; | ||
450 | |||
451 | /* | ||
452 | * This is an edge triggered IRQ, so we have to be careful to | ||
453 | * avoid missing a transition when it is shared by two ESP devices. | ||
454 | */ | ||
455 | |||
456 | do { | ||
457 | got_intr = 0; | ||
458 | if (esp_chips[0] && | ||
459 | (mac_esp_read8(esp_chips[0], ESP_STATUS) & ESP_STAT_INTR)) { | ||
460 | (void)scsi_esp_intr(irq, esp_chips[0]); | ||
461 | got_intr = 1; | ||
462 | } | ||
463 | if (esp_chips[1] && | ||
464 | (mac_esp_read8(esp_chips[1], ESP_STATUS) & ESP_STAT_INTR)) { | ||
465 | (void)scsi_esp_intr(irq, esp_chips[1]); | ||
466 | got_intr = 1; | ||
467 | } | ||
468 | } while (got_intr); | ||
469 | |||
470 | return IRQ_HANDLED; | ||
471 | } | ||
472 | |||
445 | static struct esp_driver_ops mac_esp_ops = { | 473 | static struct esp_driver_ops mac_esp_ops = { |
446 | .esp_write8 = mac_esp_write8, | 474 | .esp_write8 = mac_esp_write8, |
447 | .esp_read8 = mac_esp_read8, | 475 | .esp_read8 = mac_esp_read8, |
@@ -556,10 +584,16 @@ static int __devinit esp_mac_probe(struct platform_device *dev) | |||
556 | } | 584 | } |
557 | 585 | ||
558 | host->irq = IRQ_MAC_SCSI; | 586 | host->irq = IRQ_MAC_SCSI; |
559 | err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "Mac ESP", | 587 | esp_chips[dev->id] = esp; |
560 | esp); | 588 | mb(); |
561 | if (err < 0) | 589 | if (esp_chips[!dev->id] == NULL) { |
562 | goto fail_free_priv; | 590 | err = request_irq(host->irq, mac_scsi_esp_intr, 0, |
591 | "Mac ESP", NULL); | ||
592 | if (err < 0) { | ||
593 | esp_chips[dev->id] = NULL; | ||
594 | goto fail_free_priv; | ||
595 | } | ||
596 | } | ||
563 | 597 | ||
564 | err = scsi_esp_register(esp, &dev->dev); | 598 | err = scsi_esp_register(esp, &dev->dev); |
565 | if (err) | 599 | if (err) |
@@ -568,7 +602,8 @@ static int __devinit esp_mac_probe(struct platform_device *dev) | |||
568 | return 0; | 602 | return 0; |
569 | 603 | ||
570 | fail_free_irq: | 604 | fail_free_irq: |
571 | free_irq(host->irq, esp); | 605 | if (esp_chips[!dev->id] == NULL) |
606 | free_irq(host->irq, esp); | ||
572 | fail_free_priv: | 607 | fail_free_priv: |
573 | kfree(mep); | 608 | kfree(mep); |
574 | fail_free_command_block: | 609 | fail_free_command_block: |
@@ -587,7 +622,9 @@ static int __devexit esp_mac_remove(struct platform_device *dev) | |||
587 | 622 | ||
588 | scsi_esp_unregister(esp); | 623 | scsi_esp_unregister(esp); |
589 | 624 | ||
590 | free_irq(irq, esp); | 625 | esp_chips[dev->id] = NULL; |
626 | if (!(esp_chips[0] || esp_chips[1])) | ||
627 | free_irq(irq, NULL); | ||
591 | 628 | ||
592 | kfree(mep); | 629 | kfree(mep); |
593 | 630 | ||
@@ -614,19 +651,18 @@ static int __init mac_esp_init(void) | |||
614 | if (err) | 651 | if (err) |
615 | return err; | 652 | return err; |
616 | 653 | ||
617 | internal_esp = platform_device_alloc(DRV_MODULE_NAME, 0); | 654 | internal_pdev = platform_device_alloc(DRV_MODULE_NAME, 0); |
618 | if (internal_esp && platform_device_add(internal_esp)) { | 655 | if (internal_pdev && platform_device_add(internal_pdev)) { |
619 | platform_device_put(internal_esp); | 656 | platform_device_put(internal_pdev); |
620 | internal_esp = NULL; | 657 | internal_pdev = NULL; |
621 | } | 658 | } |
622 | 659 | external_pdev = platform_device_alloc(DRV_MODULE_NAME, 1); | |
623 | external_esp = platform_device_alloc(DRV_MODULE_NAME, 1); | 660 | if (external_pdev && platform_device_add(external_pdev)) { |
624 | if (external_esp && platform_device_add(external_esp)) { | 661 | platform_device_put(external_pdev); |
625 | platform_device_put(external_esp); | 662 | external_pdev = NULL; |
626 | external_esp = NULL; | ||
627 | } | 663 | } |
628 | 664 | ||
629 | if (internal_esp || external_esp) { | 665 | if (internal_pdev || external_pdev) { |
630 | return 0; | 666 | return 0; |
631 | } else { | 667 | } else { |
632 | platform_driver_unregister(&esp_mac_driver); | 668 | platform_driver_unregister(&esp_mac_driver); |
@@ -638,13 +674,13 @@ static void __exit mac_esp_exit(void) | |||
638 | { | 674 | { |
639 | platform_driver_unregister(&esp_mac_driver); | 675 | platform_driver_unregister(&esp_mac_driver); |
640 | 676 | ||
641 | if (internal_esp) { | 677 | if (internal_pdev) { |
642 | platform_device_unregister(internal_esp); | 678 | platform_device_unregister(internal_pdev); |
643 | internal_esp = NULL; | 679 | internal_pdev = NULL; |
644 | } | 680 | } |
645 | if (external_esp) { | 681 | if (external_pdev) { |
646 | platform_device_unregister(external_esp); | 682 | platform_device_unregister(external_pdev); |
647 | external_esp = NULL; | 683 | external_pdev = NULL; |
648 | } | 684 | } |
649 | } | 685 | } |
650 | 686 | ||