From 34d8dfb1e6b51dbd6eefcb449b531c7ee773664c Mon Sep 17 00:00:00 2001 From: Alan Date: Wed, 22 Nov 2006 17:26:06 +0000 Subject: [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 Signed-off-by: Jeff Garzik --- drivers/ata/pata_ali.c | 135 ++++++++++++++++++++++++++++++------------------- 1 file 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 @@ #include #define DRV_NAME "pata_ali" -#define DRV_VERSION "0.6.6" +#define DRV_VERSION "0.7.1" /* * Cable special cases @@ -348,6 +348,8 @@ static struct scsi_host_template ali_sht = { .slave_configure = ata_scsi_slave_config, .slave_destroy = ata_scsi_slave_destroy, .bios_param = ata_std_bios_param, + .resume = ata_scsi_device_resume, + .suspend = ata_scsi_device_suspend, }; /* @@ -497,6 +499,69 @@ static struct ata_port_operations ali_c5_port_ops = { .host_stop = ata_host_stop }; + +/** + * ali_init_chipset - chip setup function + * @pdev: PCI device of ATA controller + * + * Perform the setup on the device that must be done both at boot + * and at resume time. + */ + +static void ali_init_chipset(struct pci_dev *pdev) +{ + u8 rev, tmp; + struct pci_dev *north, *isa_bridge; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + + /* + * The chipset revision selects the driver operations and + * mode data. + */ + + if (rev >= 0x20 && rev < 0xC2) { + /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ + pci_read_config_byte(pdev, 0x4B, &tmp); + /* Clear CD-ROM DMA write bit */ + tmp &= 0x7F; + pci_write_config_byte(pdev, 0x4B, tmp); + } else if (rev >= 0xC2) { + /* Enable cable detection logic */ + pci_read_config_byte(pdev, 0x4B, &tmp); + pci_write_config_byte(pdev, 0x4B, tmp | 0x08); + } + north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0)); + isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); + + if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) { + /* Configure the ALi bridge logic. For non ALi rely on BIOS. + Set the south bridge enable bit */ + pci_read_config_byte(isa_bridge, 0x79, &tmp); + if (rev == 0xC2) + pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); + else if (rev > 0xC2) + pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); + } + if (rev >= 0x20) { + /* + * CD_ROM DMA on (0x53 bit 0). Enable this even if we want + * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control + * via 0x54/55. + */ + pci_read_config_byte(pdev, 0x53, &tmp); + if (rev <= 0x20) + tmp &= ~0x02; + if (rev >= 0xc7) + tmp |= 0x03; + else + tmp |= 0x01; /* CD_ROM enable for DMA */ + pci_write_config_byte(pdev, 0x53, tmp); + } + pci_dev_put(isa_bridge); + pci_dev_put(north); + ata_pci_clear_simplex(pdev); +} /** * ali_init_one - discovery callback * @pdev: PCI device ID @@ -570,7 +635,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) static struct ata_port_info *port_info[2]; u8 rev, tmp; - struct pci_dev *north, *isa_bridge; + struct pci_dev *isa_bridge; pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); @@ -582,11 +647,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (rev < 0x20) { port_info[0] = port_info[1] = &info_early; } else if (rev < 0xC2) { - /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ - pci_read_config_byte(pdev, 0x4B, &tmp); - /* Clear CD-ROM DMA write bit */ - tmp &= 0x7F; - pci_write_config_byte(pdev, 0x4B, tmp); port_info[0] = port_info[1] = &info_20; } else if (rev == 0xC2) { 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) } else port_info[0] = port_info[1] = &info_c5; - if (rev >= 0xC2) { - /* Enable cable detection logic */ - pci_read_config_byte(pdev, 0x4B, &tmp); - pci_write_config_byte(pdev, 0x4B, tmp | 0x08); - } - - north = pci_get_slot(pdev->bus, PCI_DEVFN(0,0)); + ali_init_chipset(pdev); + isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - - if (north && north->vendor == PCI_VENDOR_ID_AL) { - /* Configure the ALi bridge logic. For non ALi rely on BIOS. - Set the south bridge enable bit */ - pci_read_config_byte(isa_bridge, 0x79, &tmp); - if (rev == 0xC2) - pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); - else if (rev > 0xC2) - pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); + if (isa_bridge && rev >= 0x20 && rev < 0xC2) { + /* Are we paired with a UDMA capable chip */ + pci_read_config_byte(isa_bridge, 0x5E, &tmp); + if ((tmp & 0x1E) == 0x12) + port_info[0] = port_info[1] = &info_20_udma; + pci_dev_put(isa_bridge); } - - if (rev >= 0x20) { - if (rev < 0xC2) { - /* Are we paired with a UDMA capable chip */ - pci_read_config_byte(isa_bridge, 0x5E, &tmp); - if ((tmp & 0x1E) == 0x12) - port_info[0] = port_info[1] = &info_20_udma; - } - /* - * CD_ROM DMA on (0x53 bit 0). Enable this even if we want - * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control - * via 0x54/55. - */ - pci_read_config_byte(pdev, 0x53, &tmp); - if (rev <= 0x20) - tmp &= ~0x02; - if (rev >= 0xc7) - tmp |= 0x03; - else - tmp |= 0x01; /* CD_ROM enable for DMA */ - pci_write_config_byte(pdev, 0x53, tmp); - } - - pci_dev_put(isa_bridge); - pci_dev_put(north); - - ata_pci_clear_simplex(pdev); return ata_pci_init_one(pdev, port_info, 2); } +static int ali_reinit_one(struct pci_dev *pdev) +{ + ali_init_chipset(pdev); + return ata_pci_device_resume(pdev); +} + static const struct pci_device_id ali[] = { { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), }, { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), }, @@ -656,7 +687,9 @@ static struct pci_driver ali_pci_driver = { .name = DRV_NAME, .id_table = ali, .probe = ali_init_one, - .remove = ata_pci_remove_one + .remove = ata_pci_remove_one, + .suspend = ata_pci_device_suspend, + .resume = ali_reinit_one, }; static int __init ali_init(void) -- cgit v1.2.2