提交 34d8dfb1 编写于 作者: A Alan 提交者: Jeff Garzik

[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: NAlan Cox <alan@redhat.com>
Signed-off-by: NJeff Garzik <jeff@garzik.org>
上级 d39ca896
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#define DRV_NAME "pata_ali" #define DRV_NAME "pata_ali"
#define DRV_VERSION "0.6.6" #define DRV_VERSION "0.7.1"
/* /*
* Cable special cases * Cable special cases
...@@ -348,6 +348,8 @@ static struct scsi_host_template ali_sht = { ...@@ -348,6 +348,8 @@ static struct scsi_host_template ali_sht = {
.slave_configure = ata_scsi_slave_config, .slave_configure = ata_scsi_slave_config,
.slave_destroy = ata_scsi_slave_destroy, .slave_destroy = ata_scsi_slave_destroy,
.bios_param = ata_std_bios_param, .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 = { ...@@ -497,6 +499,69 @@ static struct ata_port_operations ali_c5_port_ops = {
.host_stop = ata_host_stop .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 * ali_init_one - discovery callback
* @pdev: PCI device ID * @pdev: PCI device ID
...@@ -570,7 +635,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *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]; static struct ata_port_info *port_info[2];
u8 rev, tmp; u8 rev, tmp;
struct pci_dev *north, *isa_bridge; struct pci_dev *isa_bridge;
pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); 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) ...@@ -582,11 +647,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
if (rev < 0x20) { if (rev < 0x20) {
port_info[0] = port_info[1] = &info_early; port_info[0] = port_info[1] = &info_early;
} else if (rev < 0xC2) { } 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; port_info[0] = port_info[1] = &info_20;
} else if (rev == 0xC2) { } else if (rev == 0xC2) {
port_info[0] = port_info[1] = &info_c2; 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,54 +657,25 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
} else } else
port_info[0] = port_info[1] = &info_c5; port_info[0] = port_info[1] = &info_c5;
if (rev >= 0xC2) { ali_init_chipset(pdev);
/* 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); isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
if (isa_bridge && rev >= 0x20 && rev < 0xC2) {
if (north && north->vendor == PCI_VENDOR_ID_AL) { /* Are we paired with a UDMA capable chip */
/* Configure the ALi bridge logic. For non ALi rely on BIOS. pci_read_config_byte(isa_bridge, 0x5E, &tmp);
Set the south bridge enable bit */ if ((tmp & 0x1E) == 0x12)
pci_read_config_byte(isa_bridge, 0x79, &tmp); port_info[0] = port_info[1] = &info_20_udma;
if (rev == 0xC2) pci_dev_put(isa_bridge);
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) {
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); 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[] = { static const struct pci_device_id ali[] = {
{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), }, { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), },
{ PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), }, { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), },
...@@ -656,7 +687,9 @@ static struct pci_driver ali_pci_driver = { ...@@ -656,7 +687,9 @@ static struct pci_driver ali_pci_driver = {
.name = DRV_NAME, .name = DRV_NAME,
.id_table = ali, .id_table = ali,
.probe = ali_init_one, .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) static int __init ali_init(void)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册