patch 6/7: Push part of the irq driven pio out to workqueue. Signed-off-by: Albert Lee <albertcc@xxxxxxxxxx> --- It seems this creates new race condition with ata_exec_internal_sg() and EH? diff -Nrup 05_narrow_lock/drivers/ata/libata-core.c 06_irq_wq/drivers/ata/libata-core.c --- 05_narrow_lock/drivers/ata/libata-core.c 2007-05-11 11:46:41.000000000 +0800 +++ 06_irq_wq/drivers/ata/libata-core.c 2007-05-11 11:54:56.000000000 +0800 @@ -4370,20 +4370,15 @@ err_out: static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc) { - if (qc->tf.flags & ATA_TFLAG_POLLING) - return 1; - - if (ap->hsm_task_state == HSM_ST_FIRST) { - if (qc->tf.protocol == ATA_PROT_PIO && - (qc->tf.flags & ATA_TFLAG_WRITE)) - return 1; - - if (is_atapi_taskfile(&qc->tf) && - !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) - return 1; + switch (qc->tf.protocol) { + case ATA_PROT_DMA: + return 0; + case ATA_PROT_ATAPI_DMA: + if (ap->hsm_task_state != HSM_ST_FIRST) + return 0; } - return 0; + return (ap->pflags & ATA_PFLAG_HSM_WQ) ? 1 : 0; } /** @@ -4559,7 +4554,7 @@ fsm_start: goto fsm_start; } - atapi_pio_bytes(qc, 0); + atapi_pio_bytes(qc, in_wq); if (unlikely(ap->hsm_task_state == HSM_ST_ERR)) /* bad ireason reported by device */ @@ -4614,7 +4609,7 @@ fsm_start: goto fsm_start; } - ata_pio_sectors(qc, 0); + ata_pio_sectors(qc, in_wq); if (ap->hsm_task_state == HSM_ST_IDLE) { /* all data read */ @@ -4713,6 +4708,31 @@ fsm_start: goto fsm_start; } +static void ata_irq_task(struct work_struct *work) +{ + struct ata_port *ap = + container_of(work, struct ata_port, port_task.work); + struct ata_queued_cmd *qc = ap->port_task_data; + u8 status; + + WARN_ON(ap->hsm_task_state == HSM_ST_IDLE); + + /* double check the device is not busy */ + status = ata_chk_status(ap); + if (status & ATA_BUSY) { + ata_port_printk(ap, KERN_ERR, "Unexpected device busy " + "(Status 0x%x)\n", status); + return; + } + + /* move the HSM */ + ata_hsm_move(ap, qc, status, 1); + + /* another command or interrupt handler + * may be running at this point. + */ +} + /** * ata_qc_new - Request an available ATA command, for queueing * @ap: Port associated with device @dev @@ -5250,11 +5270,20 @@ inline unsigned int ata_host_intr (struc /* ack bmdma irq events */ ap->ops->irq_clear(ap); - ata_hsm_move(ap, qc, status, 0); + /* invoke HSM */ + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + case HSM_ST: + ap->pflags |= ATA_PFLAG_HSM_WQ; + ata_port_queue_task(ap, ata_irq_task, qc, 0); + break; + default: + ata_hsm_move(ap, qc, status, 0); - if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || - qc->tf.protocol == ATA_PROT_ATAPI_DMA)) - ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); + if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_DMA)) + ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat); + } return 1; /* irq handled */ - To unsubscribe from this list: send the line "unsubscribe linux-ide" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html