diff options
author | Sonic Zhang <sonic.zhang@analog.com> | 2008-04-25 05:19:25 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-04-29 02:17:18 -0400 |
commit | 65c0d4e54ae4b81d8c8bb685169e48306656bb5c (patch) | |
tree | c1e7eb0b88c16cc17c9a33431246e0114af6ccd7 /drivers/ata/pata_bf54x.c | |
parent | 7368f91926a2870a8c3f9546d86535ce71ae0757 (diff) |
Fix bug - Implement bfin ata interrupt handler to avoid "irq 68 nobody cared" (v2)
Return IRQ_HANDLED when bfin ata device is busy.
http://blackfin.uclinux.org/gf/project/uclinux-dist/tracker/?action=TrackerItemEdit&tracker_item_id=3513
v1-v2:
- fold api breakage fixing patch together.
- mark 'static', not 'inline'.
Signed-off-by: Sonic Zhang <sonic.zhang@analog.com>
Signed-off-by: Bryan Wu <cooloney@kernel.org>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/ata/pata_bf54x.c')
-rw-r--r-- | drivers/ata/pata_bf54x.c | 124 |
1 files changed, 120 insertions, 4 deletions
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c index a75de0684c15..9ab89732cf94 100644 --- a/drivers/ata/pata_bf54x.c +++ b/drivers/ata/pata_bf54x.c | |||
@@ -1272,8 +1272,8 @@ static void bfin_freeze(struct ata_port *ap) | |||
1272 | 1272 | ||
1273 | void bfin_thaw(struct ata_port *ap) | 1273 | void bfin_thaw(struct ata_port *ap) |
1274 | { | 1274 | { |
1275 | dev_dbg(ap->dev, "in atapi dma thaw\n"); | ||
1275 | bfin_check_status(ap); | 1276 | bfin_check_status(ap); |
1276 | bfin_irq_clear(ap); | ||
1277 | bfin_irq_on(ap); | 1277 | bfin_irq_on(ap); |
1278 | } | 1278 | } |
1279 | 1279 | ||
@@ -1339,13 +1339,130 @@ static int bfin_port_start(struct ata_port *ap) | |||
1339 | return 0; | 1339 | return 0; |
1340 | } | 1340 | } |
1341 | 1341 | ||
1342 | static unsigned int bfin_ata_host_intr(struct ata_port *ap, | ||
1343 | struct ata_queued_cmd *qc) | ||
1344 | { | ||
1345 | struct ata_eh_info *ehi = &ap->link.eh_info; | ||
1346 | u8 status, host_stat = 0; | ||
1347 | |||
1348 | VPRINTK("ata%u: protocol %d task_state %d\n", | ||
1349 | ap->print_id, qc->tf.protocol, ap->hsm_task_state); | ||
1350 | |||
1351 | /* Check whether we are expecting interrupt in this state */ | ||
1352 | switch (ap->hsm_task_state) { | ||
1353 | case HSM_ST_FIRST: | ||
1354 | /* Some pre-ATAPI-4 devices assert INTRQ | ||
1355 | * at this state when ready to receive CDB. | ||
1356 | */ | ||
1357 | |||
1358 | /* Check the ATA_DFLAG_CDB_INTR flag is enough here. | ||
1359 | * The flag was turned on only for atapi devices. | ||
1360 | * No need to check is_atapi_taskfile(&qc->tf) again. | ||
1361 | */ | ||
1362 | if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) | ||
1363 | goto idle_irq; | ||
1364 | break; | ||
1365 | case HSM_ST_LAST: | ||
1366 | if (qc->tf.protocol == ATA_PROT_DMA || | ||
1367 | qc->tf.protocol == ATAPI_PROT_DMA) { | ||
1368 | /* check status of DMA engine */ | ||
1369 | host_stat = ap->ops->bmdma_status(ap); | ||
1370 | VPRINTK("ata%u: host_stat 0x%X\n", | ||
1371 | ap->print_id, host_stat); | ||
1372 | |||
1373 | /* if it's not our irq... */ | ||
1374 | if (!(host_stat & ATA_DMA_INTR)) | ||
1375 | goto idle_irq; | ||
1376 | |||
1377 | /* before we do anything else, clear DMA-Start bit */ | ||
1378 | ap->ops->bmdma_stop(qc); | ||
1379 | |||
1380 | if (unlikely(host_stat & ATA_DMA_ERR)) { | ||
1381 | /* error when transfering data to/from memory */ | ||
1382 | qc->err_mask |= AC_ERR_HOST_BUS; | ||
1383 | ap->hsm_task_state = HSM_ST_ERR; | ||
1384 | } | ||
1385 | } | ||
1386 | break; | ||
1387 | case HSM_ST: | ||
1388 | break; | ||
1389 | default: | ||
1390 | goto idle_irq; | ||
1391 | } | ||
1392 | |||
1393 | /* check altstatus */ | ||
1394 | status = ap->ops->sff_check_altstatus(ap); | ||
1395 | if (status & ATA_BUSY) | ||
1396 | goto busy_ata; | ||
1397 | |||
1398 | /* check main status, clearing INTRQ */ | ||
1399 | status = ap->ops->sff_check_status(ap); | ||
1400 | if (unlikely(status & ATA_BUSY)) | ||
1401 | goto busy_ata; | ||
1402 | |||
1403 | /* ack bmdma irq events */ | ||
1404 | ap->ops->sff_irq_clear(ap); | ||
1405 | |||
1406 | ata_sff_hsm_move(ap, qc, status, 0); | ||
1407 | |||
1408 | if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || | ||
1409 | qc->tf.protocol == ATAPI_PROT_DMA)) | ||
1410 | ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); | ||
1411 | |||
1412 | busy_ata: | ||
1413 | return 1; /* irq handled */ | ||
1414 | |||
1415 | idle_irq: | ||
1416 | ap->stats.idle_irq++; | ||
1417 | |||
1418 | #ifdef ATA_IRQ_TRAP | ||
1419 | if ((ap->stats.idle_irq % 1000) == 0) { | ||
1420 | ap->ops->irq_ack(ap, 0); /* debug trap */ | ||
1421 | ata_port_printk(ap, KERN_WARNING, "irq trap\n"); | ||
1422 | return 1; | ||
1423 | } | ||
1424 | #endif | ||
1425 | return 0; /* irq not handled */ | ||
1426 | } | ||
1427 | |||
1428 | static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance) | ||
1429 | { | ||
1430 | struct ata_host *host = dev_instance; | ||
1431 | unsigned int i; | ||
1432 | unsigned int handled = 0; | ||
1433 | unsigned long flags; | ||
1434 | |||
1435 | /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */ | ||
1436 | spin_lock_irqsave(&host->lock, flags); | ||
1437 | |||
1438 | for (i = 0; i < host->n_ports; i++) { | ||
1439 | struct ata_port *ap; | ||
1440 | |||
1441 | ap = host->ports[i]; | ||
1442 | if (ap && | ||
1443 | !(ap->flags & ATA_FLAG_DISABLED)) { | ||
1444 | struct ata_queued_cmd *qc; | ||
1445 | |||
1446 | qc = ata_qc_from_tag(ap, ap->link.active_tag); | ||
1447 | if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) && | ||
1448 | (qc->flags & ATA_QCFLAG_ACTIVE)) | ||
1449 | handled |= bfin_ata_host_intr(ap, qc); | ||
1450 | } | ||
1451 | } | ||
1452 | |||
1453 | spin_unlock_irqrestore(&host->lock, flags); | ||
1454 | |||
1455 | return IRQ_RETVAL(handled); | ||
1456 | } | ||
1457 | |||
1458 | |||
1342 | static struct scsi_host_template bfin_sht = { | 1459 | static struct scsi_host_template bfin_sht = { |
1343 | ATA_BASE_SHT(DRV_NAME), | 1460 | ATA_BASE_SHT(DRV_NAME), |
1344 | .sg_tablesize = SG_NONE, | 1461 | .sg_tablesize = SG_NONE, |
1345 | .dma_boundary = ATA_DMA_BOUNDARY, | 1462 | .dma_boundary = ATA_DMA_BOUNDARY, |
1346 | }; | 1463 | }; |
1347 | 1464 | ||
1348 | static const struct ata_port_operations bfin_pata_ops = { | 1465 | static struct ata_port_operations bfin_pata_ops = { |
1349 | .inherits = &ata_sff_port_ops, | 1466 | .inherits = &ata_sff_port_ops, |
1350 | 1467 | ||
1351 | .set_piomode = bfin_set_piomode, | 1468 | .set_piomode = bfin_set_piomode, |
@@ -1370,7 +1487,6 @@ static const struct ata_port_operations bfin_pata_ops = { | |||
1370 | .thaw = bfin_thaw, | 1487 | .thaw = bfin_thaw, |
1371 | .softreset = bfin_softreset, | 1488 | .softreset = bfin_softreset, |
1372 | .postreset = bfin_postreset, | 1489 | .postreset = bfin_postreset, |
1373 | .post_internal_cmd = bfin_bmdma_stop, | ||
1374 | 1490 | ||
1375 | .sff_irq_clear = bfin_irq_clear, | 1491 | .sff_irq_clear = bfin_irq_clear, |
1376 | .sff_irq_on = bfin_irq_on, | 1492 | .sff_irq_on = bfin_irq_on, |
@@ -1507,7 +1623,7 @@ static int __devinit bfin_atapi_probe(struct platform_device *pdev) | |||
1507 | } | 1623 | } |
1508 | 1624 | ||
1509 | if (ata_host_activate(host, platform_get_irq(pdev, 0), | 1625 | if (ata_host_activate(host, platform_get_irq(pdev, 0), |
1510 | ata_sff_interrupt, IRQF_SHARED, &bfin_sht) != 0) { | 1626 | bfin_ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) { |
1511 | peripheral_free_list(atapi_io_port); | 1627 | peripheral_free_list(atapi_io_port); |
1512 | dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); | 1628 | dev_err(&pdev->dev, "Fail to attach ATAPI device\n"); |
1513 | return -ENODEV; | 1629 | return -ENODEV; |