diff options
author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2007-03-03 22:48:08 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-03-06 04:04:30 -0500 |
commit | 63ed71019c4437caef65fca1f83c990ae729024f (patch) | |
tree | 27ff3f4c907c34702ca4eb111175132a6816fdd8 /drivers | |
parent | 8b966dddc29899008fb178a533263afa8d1ad849 (diff) |
pata_pdc202xx_old: fix data corruption and other problems
Fix wrong "port" calculations in pdc202xx_{configure_piomode,set_dmamode}()
They were broken for all configurations except one (master device on primary
channel, no other devices) and as a result device settings + PIO/DMA timings
were being programmed into the wrong PCI registers. This could result in
a large variety of problems including data corruption, hangs etc. (depending
on devices used and your luck :-).
ap->port_no ap->devno used PCI registers correct PCI registers
0 0 0x60-0x62 0x60-0x62
0 1 0x62-0x64 0x64-0x66
1 0 0x64-0x66 0x68-0x6a
1 1 0x66-0x68 0x6c-0x6e
Also forward port recent fixes from drivers/ide pdc202xx_old driver:
* fix XFER_MW_DMA0 timings (they were overclocked, use the official ones)
* fix bitmasks for clearing bits of register B:
- when programming DMA mode bit 0x10 of register B was cleared which
resulted in overclocked PIO timing setting (iff PIO0 was used)
- when programming PIO mode bits 0x18 weren't cleared so suboptimal
timings were used for PIO1-4 if PIO0 was previously set (bit 0x10)
and for PIO0/3/4 if PIO1/2 was previously set (bit 0x08)
and finally bump driver version.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/pata_pdc202xx_old.c | 22 |
1 files changed, 14 insertions, 8 deletions
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c index 3fb417780166..acdc52cbe38a 100644 --- a/drivers/ata/pata_pdc202xx_old.c +++ b/drivers/ata/pata_pdc202xx_old.c | |||
@@ -2,13 +2,14 @@ | |||
2 | * pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer | 2 | * pata_pdc202xx_old.c - Promise PDC202xx PATA for new ATA layer |
3 | * (C) 2005 Red Hat Inc | 3 | * (C) 2005 Red Hat Inc |
4 | * Alan Cox <alan@redhat.com> | 4 | * Alan Cox <alan@redhat.com> |
5 | * (C) 2007 Bartlomiej Zolnierkiewicz | ||
5 | * | 6 | * |
6 | * Based in part on linux/drivers/ide/pci/pdc202xx_old.c | 7 | * Based in part on linux/drivers/ide/pci/pdc202xx_old.c |
7 | * | 8 | * |
8 | * First cut with LBA48/ATAPI | 9 | * First cut with LBA48/ATAPI |
9 | * | 10 | * |
10 | * TODO: | 11 | * TODO: |
11 | * Channel interlock/reset on both required ? | 12 | * Channel interlock/reset on both required |
12 | */ | 13 | */ |
13 | 14 | ||
14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
@@ -21,7 +22,7 @@ | |||
21 | #include <linux/libata.h> | 22 | #include <linux/libata.h> |
22 | 23 | ||
23 | #define DRV_NAME "pata_pdc202xx_old" | 24 | #define DRV_NAME "pata_pdc202xx_old" |
24 | #define DRV_VERSION "0.3.0" | 25 | #define DRV_VERSION "0.4.0" |
25 | 26 | ||
26 | /** | 27 | /** |
27 | * pdc2024x_pre_reset - probe begin | 28 | * pdc2024x_pre_reset - probe begin |
@@ -76,7 +77,7 @@ static void pdc2026x_error_handler(struct ata_port *ap) | |||
76 | static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) | 77 | static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *adev, int pio) |
77 | { | 78 | { |
78 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | 79 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); |
79 | int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; | 80 | int port = 0x60 + 8 * ap->port_no + 4 * adev->devno; |
80 | static u16 pio_timing[5] = { | 81 | static u16 pio_timing[5] = { |
81 | 0x0913, 0x050C , 0x0308, 0x0206, 0x0104 | 82 | 0x0913, 0x050C , 0x0308, 0x0206, 0x0104 |
82 | }; | 83 | }; |
@@ -85,7 +86,7 @@ static void pdc202xx_configure_piomode(struct ata_port *ap, struct ata_device *a | |||
85 | pci_read_config_byte(pdev, port, &r_ap); | 86 | pci_read_config_byte(pdev, port, &r_ap); |
86 | pci_read_config_byte(pdev, port + 1, &r_bp); | 87 | pci_read_config_byte(pdev, port + 1, &r_bp); |
87 | r_ap &= ~0x3F; /* Preserve ERRDY_EN, SYNC_IN */ | 88 | r_ap &= ~0x3F; /* Preserve ERRDY_EN, SYNC_IN */ |
88 | r_bp &= ~0x07; | 89 | r_bp &= ~0x1F; |
89 | r_ap |= (pio_timing[pio] >> 8); | 90 | r_ap |= (pio_timing[pio] >> 8); |
90 | r_bp |= (pio_timing[pio] & 0xFF); | 91 | r_bp |= (pio_timing[pio] & 0xFF); |
91 | 92 | ||
@@ -123,7 +124,7 @@ static void pdc202xx_set_piomode(struct ata_port *ap, struct ata_device *adev) | |||
123 | static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) | 124 | static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) |
124 | { | 125 | { |
125 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); | 126 | struct pci_dev *pdev = to_pci_dev(ap->host->dev); |
126 | int port = 0x60 + 4 * ap->port_no + 2 * adev->devno; | 127 | int port = 0x60 + 8 * ap->port_no + 4 * adev->devno; |
127 | static u8 udma_timing[6][2] = { | 128 | static u8 udma_timing[6][2] = { |
128 | { 0x60, 0x03 }, /* 33 Mhz Clock */ | 129 | { 0x60, 0x03 }, /* 33 Mhz Clock */ |
129 | { 0x40, 0x02 }, | 130 | { 0x40, 0x02 }, |
@@ -132,12 +133,17 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) | |||
132 | { 0x20, 0x01 }, | 133 | { 0x20, 0x01 }, |
133 | { 0x20, 0x01 } | 134 | { 0x20, 0x01 } |
134 | }; | 135 | }; |
136 | static u8 mdma_timing[3][2] = { | ||
137 | { 0x60, 0x03 }, | ||
138 | { 0x60, 0x04 }, | ||
139 | { 0xe0, 0x0f }, | ||
140 | }; | ||
135 | u8 r_bp, r_cp; | 141 | u8 r_bp, r_cp; |
136 | 142 | ||
137 | pci_read_config_byte(pdev, port + 1, &r_bp); | 143 | pci_read_config_byte(pdev, port + 1, &r_bp); |
138 | pci_read_config_byte(pdev, port + 2, &r_cp); | 144 | pci_read_config_byte(pdev, port + 2, &r_cp); |
139 | 145 | ||
140 | r_bp &= ~0xF0; | 146 | r_bp &= ~0xE0; |
141 | r_cp &= ~0x0F; | 147 | r_cp &= ~0x0F; |
142 | 148 | ||
143 | if (adev->dma_mode >= XFER_UDMA_0) { | 149 | if (adev->dma_mode >= XFER_UDMA_0) { |
@@ -147,8 +153,8 @@ static void pdc202xx_set_dmamode(struct ata_port *ap, struct ata_device *adev) | |||
147 | 153 | ||
148 | } else { | 154 | } else { |
149 | int speed = adev->dma_mode - XFER_MW_DMA_0; | 155 | int speed = adev->dma_mode - XFER_MW_DMA_0; |
150 | r_bp |= 0x60; | 156 | r_bp |= mdma_timing[speed][0]; |
151 | r_cp |= (5 - speed); | 157 | r_cp |= mdma_timing[speed][1]; |
152 | } | 158 | } |
153 | pci_write_config_byte(pdev, port + 1, r_bp); | 159 | pci_write_config_byte(pdev, port + 1, r_bp); |
154 | pci_write_config_byte(pdev, port + 2, r_cp); | 160 | pci_write_config_byte(pdev, port + 2, r_cp); |