aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorSergei Shtylyov <sshtylyov@ru.mvista.com>2009-12-17 01:11:27 -0500
committerJeff Garzik <jgarzik@redhat.com>2009-12-17 01:11:27 -0500
commit256ace9bbd4cdb6d48d5f55d55d42fa20527fad1 (patch)
treeef768224eace1e50b8b80cedae9a37bb9cd4c035 /drivers/ata
parent9a8fd68b15e7b047678a651b7f7e2f3dcd19d20d (diff)
pata_hpt3x2n: fix clock turnaround
The clock turnaround code still doesn't work for several reasons: - 'USE_DPLL' flag in 'ap->host->private_data' is never initialized or updated, so the driver can only set the chip to the DPLL clock mode, not the PCI mode; - the driver doesn't serialize access to the channels depending on the current clock mode like the vendor drivers, so the clock turnaround is only executed "optionally", not always as it should be; - the wrong ports are written to when hpt3x2n_set_clock() is called for the secondary channel; - hpt3x2n_set_clock() can inadvertently enable the disabled channels when resetting the channel state machines. Signed-off-by: Sergei Shtylyov <sshtylyov@ru.mvista.com> Cc: stable@kernel.org Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/pata_hpt3x2n.c64
1 files changed, 35 insertions, 29 deletions
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 9a09a1b11ca5..dd26bc73bd9a 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -8,7 +8,7 @@
8 * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org> 8 * Copyright (C) 1999-2003 Andre Hedrick <andre@linux-ide.org>
9 * Portions Copyright (C) 2001 Sun Microsystems, Inc. 9 * Portions Copyright (C) 2001 Sun Microsystems, Inc.
10 * Portions Copyright (C) 2003 Red Hat Inc 10 * Portions Copyright (C) 2003 Red Hat Inc
11 * Portions Copyright (C) 2005-2007 MontaVista Software, Inc. 11 * Portions Copyright (C) 2005-2009 MontaVista Software, Inc.
12 * 12 *
13 * 13 *
14 * TODO 14 * TODO
@@ -25,7 +25,7 @@
25#include <linux/libata.h> 25#include <linux/libata.h>
26 26
27#define DRV_NAME "pata_hpt3x2n" 27#define DRV_NAME "pata_hpt3x2n"
28#define DRV_VERSION "0.3.7" 28#define DRV_VERSION "0.3.8"
29 29
30enum { 30enum {
31 HPT_PCI_FAST = (1 << 31), 31 HPT_PCI_FAST = (1 << 31),
@@ -264,7 +264,7 @@ static void hpt3x2n_bmdma_stop(struct ata_queued_cmd *qc)
264 264
265static void hpt3x2n_set_clock(struct ata_port *ap, int source) 265static void hpt3x2n_set_clock(struct ata_port *ap, int source)
266{ 266{
267 void __iomem *bmdma = ap->ioaddr.bmdma_addr; 267 void __iomem *bmdma = ap->ioaddr.bmdma_addr - ap->port_no * 8;
268 268
269 /* Tristate the bus */ 269 /* Tristate the bus */
270 iowrite8(0x80, bmdma+0x73); 270 iowrite8(0x80, bmdma+0x73);
@@ -274,9 +274,9 @@ static void hpt3x2n_set_clock(struct ata_port *ap, int source)
274 iowrite8(source, bmdma+0x7B); 274 iowrite8(source, bmdma+0x7B);
275 iowrite8(0xC0, bmdma+0x79); 275 iowrite8(0xC0, bmdma+0x79);
276 276
277 /* Reset state machines */ 277 /* Reset state machines, avoid enabling the disabled channels */
278 iowrite8(0x37, bmdma+0x70); 278 iowrite8(ioread8(bmdma+0x70) | 0x32, bmdma+0x70);
279 iowrite8(0x37, bmdma+0x74); 279 iowrite8(ioread8(bmdma+0x74) | 0x32, bmdma+0x74);
280 280
281 /* Complete reset */ 281 /* Complete reset */
282 iowrite8(0x00, bmdma+0x79); 282 iowrite8(0x00, bmdma+0x79);
@@ -286,21 +286,10 @@ static void hpt3x2n_set_clock(struct ata_port *ap, int source)
286 iowrite8(0x00, bmdma+0x77); 286 iowrite8(0x00, bmdma+0x77);
287} 287}
288 288
289/* Check if our partner interface is busy */
290
291static int hpt3x2n_pair_idle(struct ata_port *ap)
292{
293 struct ata_host *host = ap->host;
294 struct ata_port *pair = host->ports[ap->port_no ^ 1];
295
296 if (pair->hsm_task_state == HSM_ST_IDLE)
297 return 1;
298 return 0;
299}
300
301static int hpt3x2n_use_dpll(struct ata_port *ap, int writing) 289static int hpt3x2n_use_dpll(struct ata_port *ap, int writing)
302{ 290{
303 long flags = (long)ap->host->private_data; 291 long flags = (long)ap->host->private_data;
292
304 /* See if we should use the DPLL */ 293 /* See if we should use the DPLL */
305 if (writing) 294 if (writing)
306 return USE_DPLL; /* Needed for write */ 295 return USE_DPLL; /* Needed for write */
@@ -309,20 +298,35 @@ static int hpt3x2n_use_dpll(struct ata_port *ap, int writing)
309 return 0; 298 return 0;
310} 299}
311 300
301static int hpt3x2n_qc_defer(struct ata_queued_cmd *qc)
302{
303 struct ata_port *ap = qc->ap;
304 struct ata_port *alt = ap->host->ports[ap->port_no ^ 1];
305 int rc, flags = (long)ap->host->private_data;
306 int dpll = hpt3x2n_use_dpll(ap, qc->tf.flags & ATA_TFLAG_WRITE);
307
308 /* First apply the usual rules */
309 rc = ata_std_qc_defer(qc);
310 if (rc != 0)
311 return rc;
312
313 if ((flags & USE_DPLL) != dpll && alt->qc_active)
314 return ATA_DEFER_PORT;
315 return 0;
316}
317
312static unsigned int hpt3x2n_qc_issue(struct ata_queued_cmd *qc) 318static unsigned int hpt3x2n_qc_issue(struct ata_queued_cmd *qc)
313{ 319{
314 struct ata_taskfile *tf = &qc->tf;
315 struct ata_port *ap = qc->ap; 320 struct ata_port *ap = qc->ap;
316 int flags = (long)ap->host->private_data; 321 int flags = (long)ap->host->private_data;
322 int dpll = hpt3x2n_use_dpll(ap, qc->tf.flags & ATA_TFLAG_WRITE);
317 323
318 if (hpt3x2n_pair_idle(ap)) { 324 if ((flags & USE_DPLL) != dpll) {
319 int dpll = hpt3x2n_use_dpll(ap, (tf->flags & ATA_TFLAG_WRITE)); 325 flags &= ~USE_DPLL;
320 if ((flags & USE_DPLL) != dpll) { 326 flags |= dpll;
321 if (dpll == 1) 327 ap->host->private_data = (void *)(long)flags;
322 hpt3x2n_set_clock(ap, 0x21); 328
323 else 329 hpt3x2n_set_clock(ap, dpll ? 0x21 : 0x23);
324 hpt3x2n_set_clock(ap, 0x23);
325 }
326 } 330 }
327 return ata_sff_qc_issue(qc); 331 return ata_sff_qc_issue(qc);
328} 332}
@@ -339,6 +343,8 @@ static struct ata_port_operations hpt3x2n_port_ops = {
339 .inherits = &ata_bmdma_port_ops, 343 .inherits = &ata_bmdma_port_ops,
340 344
341 .bmdma_stop = hpt3x2n_bmdma_stop, 345 .bmdma_stop = hpt3x2n_bmdma_stop,
346
347 .qc_defer = hpt3x2n_qc_defer,
342 .qc_issue = hpt3x2n_qc_issue, 348 .qc_issue = hpt3x2n_qc_issue,
343 349
344 .cable_detect = hpt3x2n_cable_detect, 350 .cable_detect = hpt3x2n_cable_detect,
@@ -454,7 +460,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
454 unsigned int f_low, f_high; 460 unsigned int f_low, f_high;
455 int adjust; 461 int adjust;
456 unsigned long iobase = pci_resource_start(dev, 4); 462 unsigned long iobase = pci_resource_start(dev, 4);
457 void *hpriv = NULL; 463 void *hpriv = (void *)USE_DPLL;
458 int rc; 464 int rc;
459 465
460 rc = pcim_enable_device(dev); 466 rc = pcim_enable_device(dev);
@@ -539,7 +545,7 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
539 /* Set our private data up. We only need a few flags so we use 545 /* Set our private data up. We only need a few flags so we use
540 it directly */ 546 it directly */
541 if (pci_mhz > 60) { 547 if (pci_mhz > 60) {
542 hpriv = (void *)PCI66; 548 hpriv = (void *)(PCI66 | USE_DPLL);
543 /* 549 /*
544 * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in 550 * On HPT371N, if ATA clock is 66 MHz we must set bit 2 in
545 * the MISC. register to stretch the UltraDMA Tss timing. 551 * the MISC. register to stretch the UltraDMA Tss timing.