diff options
-rw-r--r-- | drivers/ata/pata_cmd64x.c | 116 |
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 | ||
263 | static void cmd646r1_bmdma_stop(struct ata_queued_cmd *qc) | 264 | static 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 | |||
279 | static 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 | */ | ||
326 | irqreturn_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], ®); | ||
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 | } | ||
268 | static struct scsi_host_template cmd64x_sht = { | 360 | static 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 | ||
278 | static struct ata_port_operations cmd64x_port_ops = { | 372 | static struct ata_port_operations cmd64x_port_ops = { |
@@ -282,7 +376,6 @@ static struct ata_port_operations cmd64x_port_ops = { | |||
282 | 376 | ||
283 | static struct ata_port_operations cmd646r1_port_ops = { | 377 | static 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 | ||
295 | static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) | 389 | static 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 |