diff options
Diffstat (limited to 'drivers/ata/pata_amd.c')
-rw-r--r-- | drivers/ata/pata_amd.c | 146 |
1 files changed, 94 insertions, 52 deletions
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 63719ab9ea4..33a74f11171 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -24,7 +24,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_amd" -#define DRV_VERSION "0.3.11" +#define DRV_VERSION "0.4.1" /** * timing_setup - shared timing computation and load @@ -145,6 +145,13 @@ static int amd_pre_reset(struct ata_link *link, unsigned long deadline) return ata_sff_prereset(link, deadline); } +/** + * amd_cable_detect - report cable type + * @ap: port + * + * AMD controller/BIOS setups record the cable type in word 0x42 + */ + static int amd_cable_detect(struct ata_port *ap) { static const u32 bitmask[2] = {0x03, 0x0C}; @@ -158,6 +165,40 @@ static int amd_cable_detect(struct ata_port *ap) } /** + * amd_fifo_setup - set the PIO FIFO for ATA/ATAPI + * @ap: ATA interface + * @adev: ATA device + * + * Set the PCI fifo for this device according to the devices present + * on the bus at this point in time. We need to turn the post write buffer + * off for ATAPI devices as we may need to issue a word sized write to the + * device as the final I/O + */ + +static void amd_fifo_setup(struct ata_port *ap) +{ + struct ata_device *adev; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + static const u8 fifobit[2] = { 0xC0, 0x30}; + u8 fifo = fifobit[ap->port_no]; + u8 r; + + + ata_for_each_dev(adev, &ap->link, ENABLED) { + if (adev->class == ATA_DEV_ATAPI) + fifo = 0; + } + if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411) /* FIFO is broken */ + fifo = 0; + + /* On the later chips the read prefetch bits become no-op bits */ + pci_read_config_byte(pdev, 0x41, &r); + r &= ~fifobit[ap->port_no]; + r |= fifo; + pci_write_config_byte(pdev, 0x41, r); +} + +/** * amd33_set_piomode - set initial PIO mode data * @ap: ATA interface * @adev: ATA device @@ -167,21 +208,25 @@ static int amd_cable_detect(struct ata_port *ap) static void amd33_set_piomode(struct ata_port *ap, struct ata_device *adev) { + amd_fifo_setup(ap); timing_setup(ap, adev, 0x40, adev->pio_mode, 1); } static void amd66_set_piomode(struct ata_port *ap, struct ata_device *adev) { + amd_fifo_setup(ap); timing_setup(ap, adev, 0x40, adev->pio_mode, 2); } static void amd100_set_piomode(struct ata_port *ap, struct ata_device *adev) { + amd_fifo_setup(ap); timing_setup(ap, adev, 0x40, adev->pio_mode, 3); } static void amd133_set_piomode(struct ata_port *ap, struct ata_device *adev) { + amd_fifo_setup(ap); timing_setup(ap, adev, 0x40, adev->pio_mode, 4); } @@ -397,77 +442,87 @@ static struct ata_port_operations nv133_port_ops = { .set_dmamode = nv133_set_dmamode, }; +static void amd_clear_fifo(struct pci_dev *pdev) +{ + u8 fifo; + /* Disable the FIFO, the FIFO logic will re-enable it as + appropriate */ + pci_read_config_byte(pdev, 0x41, &fifo); + fifo &= 0x0F; + pci_write_config_byte(pdev, 0x41, fifo); +} + static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) { static const struct ata_port_info info[10] = { - { /* 0: AMD 7401 */ + { /* 0: AMD 7401 - no swdma */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, /* No SWDMA */ - .udma_mask = 0x07, /* UDMA 33 */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, .port_ops = &amd33_port_ops }, { /* 1: Early AMD7409 - no swdma */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = ATA_UDMA4, /* UDMA 66 */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA4, .port_ops = &amd66_port_ops }, - { /* 2: AMD 7409, no swdma errata */ + { /* 2: AMD 7409 */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = ATA_UDMA4, /* UDMA 66 */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA4, .port_ops = &amd66_port_ops }, { /* 3: AMD 7411 */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = ATA_UDMA5, /* UDMA 100 */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, .port_ops = &amd100_port_ops }, { /* 4: AMD 7441 */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = ATA_UDMA5, /* UDMA 100 */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, .port_ops = &amd100_port_ops }, - { /* 5: AMD 8111*/ + { /* 5: AMD 8111 - no swdma */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = ATA_UDMA6, /* UDMA 133, no swdma */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, .port_ops = &amd133_port_ops }, - { /* 6: AMD 8111 UDMA 100 (Serenade) */ + { /* 6: AMD 8111 UDMA 100 (Serenade) - no swdma */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = ATA_UDMA5, /* UDMA 100, no swdma */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, .port_ops = &amd133_port_ops }, { /* 7: Nvidia Nforce */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = ATA_UDMA5, /* UDMA 100 */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, .port_ops = &nv100_port_ops }, - { /* 8: Nvidia Nforce2 and later */ + { /* 8: Nvidia Nforce2 and later - no swdma */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = ATA_UDMA6, /* UDMA 133, no swdma */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA6, .port_ops = &nv133_port_ops }, { /* 9: AMD CS5536 (Geode companion) */ .flags = ATA_FLAG_SLAVE_POSS, - .pio_mask = 0x1f, - .mwdma_mask = 0x07, - .udma_mask = ATA_UDMA5, /* UDMA 100 */ + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, .port_ops = &amd100_port_ops } }; @@ -503,14 +558,8 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id) if (type < 3) ata_pci_bmdma_clear_simplex(pdev); - - /* Check for AMD7411 */ - if (type == 3) - /* FIFO is broken */ - pci_write_config_byte(pdev, 0x41, fifo & 0x0F); - else - pci_write_config_byte(pdev, 0x41, fifo | 0xF0); - + if (pdev->vendor == PCI_VENDOR_ID_AMD) + amd_clear_fifo(pdev); /* Cable detection on Nvidia chips doesn't work too well, * cache BIOS programmed UDMA mode. */ @@ -536,18 +585,11 @@ static int amd_reinit_one(struct pci_dev *pdev) return rc; if (pdev->vendor == PCI_VENDOR_ID_AMD) { - u8 fifo; - pci_read_config_byte(pdev, 0x41, &fifo); - if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411) - /* FIFO is broken */ - pci_write_config_byte(pdev, 0x41, fifo & 0x0F); - else - pci_write_config_byte(pdev, 0x41, fifo | 0xF0); + amd_clear_fifo(pdev); if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7409 || pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401) ata_pci_bmdma_clear_simplex(pdev); } - ata_host_resume(host); return 0; } |