aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2009-11-30 08:22:54 -0500
committerJeff Garzik <jgarzik@redhat.com>2009-12-03 02:46:36 -0500
commitd43744390e460dce6626fb8de2c02a24ff650005 (patch)
treedef287ec85fa9d1a2cfc70633892b158cef509b4 /drivers/ata
parentf20941f334d8fdb6b598658979709b4e94cd034b (diff)
pata_cmd64x: implement serialization as per notes
Daniela Engert pointed out that there are some implementation notes for the 643 and 646 that deal with certain serialization rules. In theory we don't need them because they apply when the motherboard decides not to retry PCI requests for long enough and the chip is busy doing a DMA transfer on the other channel. The rule basically is "don't touch the taskfile of the other channel while a DMA is in progress". To implement that we need to - not issue a command on a channel when there is a DMA command queued - not issue a DMA command on a channel when there are PIO commands queued - use the alternative access to the interrupt source so that we do not touch altstatus or status on shared IRQ. Updated to remote extra conditional check Bartlomiej noted and to remove the variables for irq checks as the CMD648 doesn't have the underlying problem. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/pata_cmd64x.c116
1 files changed, 108 insertions, 8 deletions
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index f98dffedf4bc..e4d3a1e6b8c7 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -31,7 +31,7 @@
31#include <linux/libata.h> 31#include <linux/libata.h>
32 32
33#define DRV_NAME "pata_cmd64x" 33#define DRV_NAME "pata_cmd64x"
34#define DRV_VERSION "0.2.5" 34#define DRV_VERSION "0.3.1"
35 35
36/* 36/*
37 * CMD64x specific registers definition. 37 * CMD64x specific registers definition.
@@ -254,17 +254,109 @@ static void cmd648_bmdma_stop(struct ata_queued_cmd *qc)
254} 254}
255 255
256/** 256/**
257 * cmd646r1_dma_stop - DMA stop callback 257 * cmd64x_bmdma_stop - DMA stop callback
258 * @qc: Command in progress 258 * @qc: Command in progress
259 * 259 *
260 * Stub for now while investigating the r1 quirk in the old driver. 260 * Track the completion of live DMA commands and clear the
261 * host->private_data DMA tracking flag as we do.
261 */ 262 */
262 263
263static void cmd646r1_bmdma_stop(struct ata_queued_cmd *qc) 264static void cmd64x_bmdma_stop(struct ata_queued_cmd *qc)
264{ 265{
266 struct ata_port *ap = qc->ap;
265 ata_bmdma_stop(qc); 267 ata_bmdma_stop(qc);
268 WARN_ON(ap->host->private_data != ap);
269 ap->host->private_data = NULL;
270}
271
272/**
273 * cmd64x_qc_defer - Defer logic for chip limits
274 * @qc: queued command
275 *
276 * Decide whether we can issue the command. Called under the host lock.
277 */
278
279static int cmd64x_qc_defer(struct ata_queued_cmd *qc)
280{
281 struct ata_host *host = qc->ap->host;
282 struct ata_port *alt = host->ports[1 ^ qc->ap->port_no];
283 int rc;
284 int dma = 0;
285
286 /* Apply the ATA rules first */
287 rc = ata_std_qc_defer(qc);
288 if (rc)
289 return rc;
290
291 if (qc->tf.protocol == ATAPI_PROT_DMA ||
292 qc->tf.protocol == ATA_PROT_DMA)
293 dma = 1;
294
295 /* If the other port is not live then issue the command */
296 if (alt == NULL || !alt->qc_active) {
297 if (dma)
298 host->private_data = qc->ap;
299 return 0;
300 }
301 /* If there is a live DMA command then wait */
302 if (host->private_data != NULL)
303 return ATA_DEFER_PORT;
304 if (dma)
305 /* Cannot overlap our DMA command */
306 return ATA_DEFER_PORT;
307 return 0;
266} 308}
267 309
310/**
311 * cmd64x_interrupt - ATA host interrupt handler
312 * @irq: irq line (unused)
313 * @dev_instance: pointer to our ata_host information structure
314 *
315 * Our interrupt handler for PCI IDE devices. Calls
316 * ata_sff_host_intr() for each port that is flagging an IRQ. We cannot
317 * use the defaults as we need to avoid touching status/altstatus during
318 * a DMA.
319 *
320 * LOCKING:
321 * Obtains host lock during operation.
322 *
323 * RETURNS:
324 * IRQ_NONE or IRQ_HANDLED.
325 */
326irqreturn_t cmd64x_interrupt(int irq, void *dev_instance)
327{
328 struct ata_host *host = dev_instance;
329 struct pci_dev *pdev = to_pci_dev(host->dev);
330 unsigned int i;
331 unsigned int handled = 0;
332 unsigned long flags;
333 static const u8 irq_reg[2] = { CFR, ARTTIM23 };
334 static const u8 irq_mask[2] = { 1 << 2, 1 << 4 };
335
336 /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
337 spin_lock_irqsave(&host->lock, flags);
338
339 for (i = 0; i < host->n_ports; i++) {
340 struct ata_port *ap;
341 u8 reg;
342
343 pci_read_config_byte(pdev, irq_reg[i], &reg);
344 ap = host->ports[i];
345 if (ap && (reg & irq_mask[i]) &&
346 !(ap->flags & ATA_FLAG_DISABLED)) {
347 struct ata_queued_cmd *qc;
348
349 qc = ata_qc_from_tag(ap, ap->link.active_tag);
350 if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
351 (qc->flags & ATA_QCFLAG_ACTIVE))
352 handled |= ata_sff_host_intr(ap, qc);
353 }
354 }
355
356 spin_unlock_irqrestore(&host->lock, flags);
357
358 return IRQ_RETVAL(handled);
359}
268static struct scsi_host_template cmd64x_sht = { 360static struct scsi_host_template cmd64x_sht = {
269 ATA_BMDMA_SHT(DRV_NAME), 361 ATA_BMDMA_SHT(DRV_NAME),
270}; 362};
@@ -273,6 +365,8 @@ static const struct ata_port_operations cmd64x_base_ops = {
273 .inherits = &ata_bmdma_port_ops, 365 .inherits = &ata_bmdma_port_ops,
274 .set_piomode = cmd64x_set_piomode, 366 .set_piomode = cmd64x_set_piomode,
275 .set_dmamode = cmd64x_set_dmamode, 367 .set_dmamode = cmd64x_set_dmamode,
368 .bmdma_stop = cmd64x_bmdma_stop,
369 .qc_defer = cmd64x_qc_defer,
276}; 370};
277 371
278static struct ata_port_operations cmd64x_port_ops = { 372static struct ata_port_operations cmd64x_port_ops = {
@@ -282,7 +376,6 @@ static struct ata_port_operations cmd64x_port_ops = {
282 376
283static struct ata_port_operations cmd646r1_port_ops = { 377static struct ata_port_operations cmd646r1_port_ops = {
284 .inherits = &cmd64x_base_ops, 378 .inherits = &cmd64x_base_ops,
285 .bmdma_stop = cmd646r1_bmdma_stop,
286 .cable_detect = ata_cable_40wire, 379 .cable_detect = ata_cable_40wire,
287}; 380};
288 381
@@ -290,6 +383,7 @@ static struct ata_port_operations cmd648_port_ops = {
290 .inherits = &cmd64x_base_ops, 383 .inherits = &cmd64x_base_ops,
291 .bmdma_stop = cmd648_bmdma_stop, 384 .bmdma_stop = cmd648_bmdma_stop,
292 .cable_detect = cmd648_cable_detect, 385 .cable_detect = cmd648_cable_detect,
386 .qc_defer = ata_std_qc_defer
293}; 387};
294 388
295static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) 389static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -340,6 +434,7 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
340 const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL }; 434 const struct ata_port_info *ppi[] = { &cmd_info[id->driver_data], NULL };
341 u8 mrdmode; 435 u8 mrdmode;
342 int rc; 436 int rc;
437 struct ata_host *host;
343 438
344 rc = pcim_enable_device(pdev); 439 rc = pcim_enable_device(pdev);
345 if (rc) 440 if (rc)
@@ -360,20 +455,25 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
360 ppi[0] = &cmd_info[3]; 455 ppi[0] = &cmd_info[3];
361 } 456 }
362 457
458
363 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); 459 pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
364 pci_read_config_byte(pdev, MRDMODE, &mrdmode); 460 pci_read_config_byte(pdev, MRDMODE, &mrdmode);
365 mrdmode &= ~ 0x30; /* IRQ set up */ 461 mrdmode &= ~ 0x30; /* IRQ set up */
366 mrdmode |= 0x02; /* Memory read line enable */ 462 mrdmode |= 0x02; /* Memory read line enable */
367 pci_write_config_byte(pdev, MRDMODE, mrdmode); 463 pci_write_config_byte(pdev, MRDMODE, mrdmode);
368 464
369 /* Force PIO 0 here.. */
370
371 /* PPC specific fixup copied from old driver */ 465 /* PPC specific fixup copied from old driver */
372#ifdef CONFIG_PPC 466#ifdef CONFIG_PPC
373 pci_write_config_byte(pdev, UDIDETCR0, 0xF0); 467 pci_write_config_byte(pdev, UDIDETCR0, 0xF0);
374#endif 468#endif
469 rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
470 if (rc)
471 return rc;
472 /* We use this pointer to track the AP which has DMA running */
473 host->private_data = NULL;
375 474
376 return ata_pci_sff_init_one(pdev, ppi, &cmd64x_sht, NULL); 475 pci_set_master(pdev);
476 return ata_pci_sff_activate_host(host, cmd64x_interrupt, &cmd64x_sht);
377} 477}
378 478
379#ifdef CONFIG_PM 479#ifdef CONFIG_PM