patch 6/8: - Delegate irq driven pio to workqueue. - HSM_ST_LAST is kept in the interrupt since this is not CPU intensive. (Mostly for DMA and non-data.) Signed-off-by: Albert Lee <albertcc@xxxxxxxxxx> Cc: Alan Cox <alan@xxxxxxxxxxxxxxxxxxx> Cc: Tejun Heo <htejun@xxxxxxxxx> --- sata_sil is not changed to delegate to workqueue at this moment. Maybe we can add such feature in the future if needed. diff -Nrup 05_polling_ack/drivers/ata/libata-core.c 06_irq_wq/drivers/ata/libata-core.c --- 05_polling_ack/drivers/ata/libata-core.c 2007-05-16 13:53:20.000000000 +0800 +++ 06_irq_wq/drivers/ata/libata-core.c 2007-05-16 13:53:25.000000000 +0800 @@ -4864,20 +4864,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; } /** @@ -5217,6 +5212,39 @@ fsm_start: } /** + * ata_irq_task - queue task for irq pio + * @work: associated work_struct + * + * LOCKING: + * None. + */ + +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 * @dev: Device from whom we request an available command structure @@ -5756,11 +5784,21 @@ inline unsigned int ata_host_intr (struc /* ack bmdma irq events */ ap->ops->irq_clear(ap); - ata_hsm_move(ap, qc, status, 0); + /* move the HSM */ + switch (ap->hsm_task_state) { + case HSM_ST_FIRST: + case HSM_ST: + /* delegate PIO data transfer to workqueue */ + 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