diff options
author | Alan <alan@lxorguk.ukuu.org.uk> | 2006-11-22 12:26:06 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-12-01 22:46:44 -0500 |
commit | 34d8dfb1e6b51dbd6eefcb449b531c7ee773664c (patch) | |
tree | afc35f1f602340be69c6c66f10b0133a8624580f | |
parent | d39ca896fb9a25f80465d3e52872cf5c510762a8 (diff) |
[PATCH] pata_ali: suspend/resume support
Various chipset functions must be reprogrammed on a resume from RAM,
without this things like ATAPI DMA stop working on resume with some
chipset variants. Split the chipset programming and init time method selection into two functions.
Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r-- | drivers/ata/pata_ali.c | 135 |
1 files changed, 84 insertions, 51 deletions
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index e6d2b840e870..ae6d573574cd 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #include <linux/dmi.h> | 34 | #include <linux/dmi.h> |
35 | 35 | ||
36 | #define DRV_NAME "pata_ali" | 36 | #define DRV_NAME "pata_ali" |
37 | #define DRV_VERSION "0.6.6" | 37 | #define DRV_VERSION "0.7.1" |
38 | 38 | ||
39 | /* | 39 | /* |
40 | * Cable special cases | 40 | * Cable special cases |
@@ -348,6 +348,8 @@ static struct scsi_host_template ali_sht = { | |||
348 | .slave_configure = ata_scsi_slave_config, | 348 | .slave_configure = ata_scsi_slave_config, |
349 | .slave_destroy = ata_scsi_slave_destroy, | 349 | .slave_destroy = ata_scsi_slave_destroy, |
350 | .bios_param = ata_std_bios_param, | 350 | .bios_param = ata_std_bios_param, |
351 | .resume = ata_scsi_device_resume, | ||
352 | .suspend = ata_scsi_device_suspend, | ||
351 | }; | 353 | }; |
352 | 354 | ||
353 | /* | 355 | /* |
@@ -497,6 +499,69 @@ static struct ata_port_operations ali_c5_port_ops = { | |||
497 | .host_stop = ata_host_stop | 499 | .host_stop = ata_host_stop |
498 | }; | 500 | }; |
499 | 501 | ||
502 | |||
503 | /** | ||
504 | * ali_init_chipset - chip setup function | ||
505 | * @pdev: PCI device of ATA controller | ||
506 | * | ||
507 | * Perform the setup on the device that must be done both at boot | ||
508 | * and at resume time. | ||
509 | */ | ||
510 | |||
511 | static void ali_init_chipset(struct pci_dev *pdev) | ||
512 | { | ||
513 | u8 rev, tmp; | ||
514 | struct pci_dev *north, *isa_bridge; | ||
515 | |||
516 | pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); | ||
517 | |||
518 | /* | ||
519 | * The chipset revision selects the driver operations and | ||
520 | * mode data. | ||
521 | */ | ||
522 | |||
523 | if (rev >= 0x20 && rev < 0xC2) { | ||
524 | /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ | ||
525 | pci_read_config_byte(pdev, 0x4B, &tmp); | ||
526 | /* Clear CD-ROM DMA write bit */ | ||
527 | tmp &= 0x7F; | ||
528 | pci_write_config_byte(pdev, 0x4B, tmp); | ||
529 | } else if (rev >= 0xC2) { | ||
530 | /* Enable cable detection logic */ | ||
531 | pci_read_config_byte(pdev, 0x4B, &tmp); | ||
532 | pci_write_config_byte(pdev, 0x4B, tmp | 0x08); | ||
533 | } | ||
534 | north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0)); | ||
535 | isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); | ||
536 | |||
537 | if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) { | ||
538 | /* Configure the ALi bridge logic. For non ALi rely on BIOS. | ||
539 | Set the south bridge enable bit */ | ||
540 | pci_read_config_byte(isa_bridge, 0x79, &tmp); | ||
541 | if (rev == 0xC2) | ||
542 | pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); | ||
543 | else if (rev > 0xC2) | ||
544 | pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); | ||
545 | } | ||
546 | if (rev >= 0x20) { | ||
547 | /* | ||
548 | * CD_ROM DMA on (0x53 bit 0). Enable this even if we want | ||
549 | * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control | ||
550 | * via 0x54/55. | ||
551 | */ | ||
552 | pci_read_config_byte(pdev, 0x53, &tmp); | ||
553 | if (rev <= 0x20) | ||
554 | tmp &= ~0x02; | ||
555 | if (rev >= 0xc7) | ||
556 | tmp |= 0x03; | ||
557 | else | ||
558 | tmp |= 0x01; /* CD_ROM enable for DMA */ | ||
559 | pci_write_config_byte(pdev, 0x53, tmp); | ||
560 | } | ||
561 | pci_dev_put(isa_bridge); | ||
562 | pci_dev_put(north); | ||
563 | ata_pci_clear_simplex(pdev); | ||
564 | } | ||
500 | /** | 565 | /** |
501 | * ali_init_one - discovery callback | 566 | * ali_init_one - discovery callback |
502 | * @pdev: PCI device ID | 567 | * @pdev: PCI device ID |
@@ -570,7 +635,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
570 | 635 | ||
571 | static struct ata_port_info *port_info[2]; | 636 | static struct ata_port_info *port_info[2]; |
572 | u8 rev, tmp; | 637 | u8 rev, tmp; |
573 | struct pci_dev *north, *isa_bridge; | 638 | struct pci_dev *isa_bridge; |
574 | 639 | ||
575 | pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); | 640 | pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); |
576 | 641 | ||
@@ -582,11 +647,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
582 | if (rev < 0x20) { | 647 | if (rev < 0x20) { |
583 | port_info[0] = port_info[1] = &info_early; | 648 | port_info[0] = port_info[1] = &info_early; |
584 | } else if (rev < 0xC2) { | 649 | } else if (rev < 0xC2) { |
585 | /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ | ||
586 | pci_read_config_byte(pdev, 0x4B, &tmp); | ||
587 | /* Clear CD-ROM DMA write bit */ | ||
588 | tmp &= 0x7F; | ||
589 | pci_write_config_byte(pdev, 0x4B, tmp); | ||
590 | port_info[0] = port_info[1] = &info_20; | 650 | port_info[0] = port_info[1] = &info_20; |
591 | } else if (rev == 0xC2) { | 651 | } else if (rev == 0xC2) { |
592 | port_info[0] = port_info[1] = &info_c2; | 652 | port_info[0] = port_info[1] = &info_c2; |
@@ -597,54 +657,25 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
597 | } else | 657 | } else |
598 | port_info[0] = port_info[1] = &info_c5; | 658 | port_info[0] = port_info[1] = &info_c5; |
599 | 659 | ||
600 | if (rev >= 0xC2) { | 660 | ali_init_chipset(pdev); |
601 | /* Enable cable detection logic */ | 661 | |
602 | pci_read_config_byte(pdev, 0x4B, &tmp); | ||
603 | pci_write_config_byte(pdev, 0x4B, tmp | 0x08); | ||
604 | } | ||
605 | |||
606 | north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0)); | ||
607 | isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); | 662 | isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); |
608 | 663 | if (isa_bridge && rev >= 0x20 && rev < 0xC2) { | |
609 | if (north && north->vendor == PCI_VENDOR_ID_AL) { | 664 | /* Are we paired with a UDMA capable chip */ |
610 | /* Configure the ALi bridge logic. For non ALi rely on BIOS. | 665 | pci_read_config_byte(isa_bridge, 0x5E, &tmp); |
611 | Set the south bridge enable bit */ | 666 | if ((tmp & 0x1E) == 0x12) |
612 | pci_read_config_byte(isa_bridge, 0x79, &tmp); | 667 | port_info[0] = port_info[1] = &info_20_udma; |
613 | if (rev == 0xC2) | 668 | pci_dev_put(isa_bridge); |
614 | pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); | ||
615 | else if (rev > 0xC2) | ||
616 | pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); | ||
617 | } | 669 | } |
618 | |||
619 | if (rev >= 0x20) { | ||
620 | if (rev < 0xC2) { | ||
621 | /* Are we paired with a UDMA capable chip */ | ||
622 | pci_read_config_byte(isa_bridge, 0x5E, &tmp); | ||
623 | if ((tmp & 0x1E) == 0x12) | ||
624 | port_info[0] = port_info[1] = &info_20_udma; | ||
625 | } | ||
626 | /* | ||
627 | * CD_ROM DMA on (0x53 bit 0). Enable this even if we want | ||
628 | * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control | ||
629 | * via 0x54/55. | ||
630 | */ | ||
631 | pci_read_config_byte(pdev, 0x53, &tmp); | ||
632 | if (rev <= 0x20) | ||
633 | tmp &= ~0x02; | ||
634 | if (rev >= 0xc7) | ||
635 | tmp |= 0x03; | ||
636 | else | ||
637 | tmp |= 0x01; /* CD_ROM enable for DMA */ | ||
638 | pci_write_config_byte(pdev, 0x53, tmp); | ||
639 | } | ||
640 | |||
641 | pci_dev_put(isa_bridge); | ||
642 | pci_dev_put(north); | ||
643 | |||
644 | ata_pci_clear_simplex(pdev); | ||
645 | return ata_pci_init_one(pdev, port_info, 2); | 670 | return ata_pci_init_one(pdev, port_info, 2); |
646 | } | 671 | } |
647 | 672 | ||
673 | static int ali_reinit_one(struct pci_dev *pdev) | ||
674 | { | ||
675 | ali_init_chipset(pdev); | ||
676 | return ata_pci_device_resume(pdev); | ||
677 | } | ||
678 | |||
648 | static const struct pci_device_id ali[] = { | 679 | static const struct pci_device_id ali[] = { |
649 | { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), }, | 680 | { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), }, |
650 | { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), }, | 681 | { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), }, |
@@ -656,7 +687,9 @@ static struct pci_driver ali_pci_driver = { | |||
656 | .name = DRV_NAME, | 687 | .name = DRV_NAME, |
657 | .id_table = ali, | 688 | .id_table = ali, |
658 | .probe = ali_init_one, | 689 | .probe = ali_init_one, |
659 | .remove = ata_pci_remove_one | 690 | .remove = ata_pci_remove_one, |
691 | .suspend = ata_pci_device_suspend, | ||
692 | .resume = ali_reinit_one, | ||
660 | }; | 693 | }; |
661 | 694 | ||
662 | static int __init ali_init(void) | 695 | static int __init ali_init(void) |