Loading src/drivers/ata/ahci_elphel.c +48 −58 Original line number Original line Diff line number Diff line Loading @@ -144,7 +144,8 @@ static void remove_timer(struct elphel_ahci_priv *dpriv) if (timer_pending(&dpriv->cmd_timer)) { if (timer_pending(&dpriv->cmd_timer)) { ret = del_timer_sync(&dpriv->cmd_timer); ret = del_timer_sync(&dpriv->cmd_timer); if (ret < 0) if (ret < 0) dev_err(dpriv->dev, "can not remove timer\n"); dev_err(dpriv->dev, "can not remove command guard timer\n"); reset_flag(dpriv, IRQ_PROCESSED); } } } } Loading Loading @@ -176,11 +177,22 @@ static void reset_all_commands(struct elphel_ahci_priv *dpriv) /** Command execution timer has expired, set flag indicating that recording should be restarted */ /** Command execution timer has expired, set flag indicating that recording should be restarted */ static void process_timeout(unsigned long data) static void process_timeout(unsigned long data) { { int report = 0; unsigned long irq_flags; struct elphel_ahci_priv *dpriv = (struct elphel_ahci_priv *)data; struct elphel_ahci_priv *dpriv = (struct elphel_ahci_priv *)data; dev_err(dpriv->dev, "AHCI error: command execution timeout, LBA start = 0x%llx\n", dpriv->lba_ptr.lba_write); /* we are racing with interrupt here, IRQ handler sets IRQ_PROCESSED flag to prevent timer from * triggering error handler before this timer is removed */ spin_lock_irqsave(&dpriv->flags_lock, irq_flags); if (!(dpriv->flags & IRQ_PROCESSED)) { dpriv->flags |= START_EH; report = 1; } spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); if (report) { set_dscope_tstamp(dpriv, TSTMP_CMD_SYS); set_dscope_tstamp(dpriv, TSTMP_CMD_SYS); set_flag(dpriv, START_EH); } } } /** Calculate the difference between two time stamps and return it in microseconds */ /** Calculate the difference between two time stamps and return it in microseconds */ Loading Loading @@ -232,26 +244,19 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) host_irq_stat = readl(hpriv->mmio + HOST_IRQ_STAT); host_irq_stat = readl(hpriv->mmio + HOST_IRQ_STAT); if (!host_irq_stat) { if (!host_irq_stat) { dev_err(dpriv->dev, "Spurious IRQ received, host_irq_stat = 0x%x\n", host_irq_stat); dev_err(dpriv->dev, "Spurious IRQ received, host_irq_stat = 0x%x\n", host_irq_stat); // debug actions, check it one more time before exit host_irq_stat = readl(hpriv->mmio + HOST_IRQ_STAT); if (!host_irq_stat) { return IRQ_NONE; return IRQ_NONE; } else { dev_err(dpriv->dev, "Spurious interrupt not confirmed, host_irq_stat = 0x%x, proceed to IRQ processing\n", host_irq_stat); } } } // dpriv->flags &= ~IRQ_SIMPLE; reset_flag(dpriv, IRQ_SIMPLE); reset_flag(dpriv, IRQ_SIMPLE); irq_stat = readl(port_mmio + PORT_IRQ_STAT); irq_stat = readl(port_mmio + PORT_IRQ_STAT); serror = readl(port_mmio + PORT_SCR_ERR); serror = readl(port_mmio + PORT_SCR_ERR); /* debug feature, save current state for analysis */ dpriv->datascope.reg_stat[REG_HOST_IS] = host_irq_stat; dpriv->datascope.reg_stat[REG_HOST_IS] = host_irq_stat; dpriv->datascope.reg_stat[REG_PxIS] = irq_stat; dpriv->datascope.reg_stat[REG_PxIS] = irq_stat; dpriv->datascope.reg_stat[REG_PxSERR] = serror; dpriv->datascope.reg_stat[REG_PxSERR] = serror; dpriv->datascope.reg_stat[REG_PxIE] = readl(port_mmio + PORT_IRQ_MASK); dpriv->datascope.reg_stat[REG_PxIE] = readl(port_mmio + PORT_IRQ_MASK); dpriv->datascope.reg_stat[IRQ_COUNTER] = dpriv->datascope.reg_stat[IRQ_COUNTER] + 1; dpriv->datascope.reg_stat[IRQ_COUNTER] = dpriv->datascope.reg_stat[IRQ_COUNTER] + 1; // dev_dbg(host->dev, "irq_stat = 0x%x, host irq_stat = 0x%x, SErr = 0x%x\n", irq_stat, host_irq_stat, serror); if (unlikely(irq_stat & PORT_IRQ_ERROR)) { if (unlikely(irq_stat & PORT_IRQ_ERROR)) { dpriv->eh.irq_stat = irq_stat; dpriv->eh.irq_stat = irq_stat; Loading @@ -264,18 +269,21 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) handled = IRQ_HANDLED; handled = IRQ_HANDLED; set_dscope_tstamp(dpriv, TSTMP_IRQ_MARK_1); set_dscope_tstamp(dpriv, TSTMP_IRQ_MARK_1); /* check if this command timed out and charged error handler, do not schedule tasklet in this case as /* * check if this command timed out and charged error handler, do not schedule tasklet in this case as * the processing will restart from error handler * the processing will restart from error handler */ */ spin_lock_irqsave(&dpriv->flags_lock, irq_flags); if (dpriv->flags & (START_EH | WAIT_EH)) { if (dpriv->flags & (START_EH | WAIT_EH)) { // tell to EH that the command will be processed in normal way // tell to EH that the command will be processed in normal way set_dscope_tstamp(dpriv, TSTMP_IRQ_MARK_1); set_dscope_tstamp(dpriv, TSTMP_IRQ_MARK_1); set_flag(dpriv, DELAYED_IRQ_RCVD); dpriv->flags |= DELAYED_IRQ_RCVD; wake_up_interruptible(&dpriv->eh.wait); wake_up_interruptible(&dpriv->eh.wait); } else { } else { dpriv->flags |= IRQ_PROCESSED; tasklet_schedule(&dpriv->bh); tasklet_schedule(&dpriv->bh); } } spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); } else { } else { set_dscope_tstamp(dpriv, TSTMP_IRQ_SYS); set_dscope_tstamp(dpriv, TSTMP_IRQ_SYS); Loading @@ -294,12 +302,12 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) return handled; return handled; } } /** Command queue processing tasklet */ /** Command queue processing tasklet */ void process_queue(unsigned long data) void process_queue(unsigned long data) { { int i; int i; size_t total_sz = 0; size_t total_sz = 0; unsigned long irq_flags; unsigned long time_usec; unsigned long time_usec; sec_usec_t end_time = {0}; sec_usec_t end_time = {0}; struct elphel_ahci_priv *dpriv = (struct elphel_ahci_priv *)data; struct elphel_ahci_priv *dpriv = (struct elphel_ahci_priv *)data; Loading @@ -313,9 +321,9 @@ void process_queue(unsigned long data) add_sample(total_sz / time_usec, &dpriv->stat); add_sample(total_sz / time_usec, &dpriv->stat); } } // check if we can proceed - this was debug feature to fully stop cmd processing // // check if we can proceed - this was debug feature to fully stop cmd processing if (dpriv->flags & (START_EH | WAIT_EH)) // if (dpriv->flags & (START_EH | WAIT_EH)) return; // return; if (process_cmd(dpriv) == 0) { if (process_cmd(dpriv) == 0) { finish_cmd(dpriv); finish_cmd(dpriv); Loading @@ -327,9 +335,6 @@ void process_queue(unsigned long data) finish_rec(dpriv); finish_rec(dpriv); } else { } else { /* all commands have been processed */ /* all commands have been processed */ // spin_lock_irqsave(&dpriv->flags_lock, irq_flags); // dpriv->flags &= ~DISK_BUSY; // spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); reset_flag(dpriv, DISK_BUSY); reset_flag(dpriv, DISK_BUSY); } } } } Loading Loading @@ -1253,7 +1258,7 @@ static size_t get_prev_slot(const struct elphel_ahci_priv *dpriv) return slot; return slot; } } /** Handle delayed interrupt or ather errors */ /** Handle delayed interrupt or other errors */ void error_handler(struct elphel_ahci_priv *dpriv) void error_handler(struct elphel_ahci_priv *dpriv) { { long rc; long rc; Loading @@ -1272,27 +1277,25 @@ void error_handler(struct elphel_ahci_priv *dpriv) } } rc = wait_event_interruptible_timeout(dpriv->eh.wait, dpriv->flags & DELAYED_IRQ_RCVD, deadline); rc = wait_event_interruptible_timeout(dpriv->eh.wait, dpriv->flags & DELAYED_IRQ_RCVD, deadline); dev_warn(dpriv->dev, "wait_event_interruptible_timeout returned %ld\n", rc); dev_dbg(dpriv->dev, "wait_event_interruptible_timeout returned %ld\n", rc); if (!rc) { if (!rc) { return; reset_flag(dpriv, IRQ_SIMPLE | DISK_BUSY | PROC_CMD | START_EH); // reset_flag(dpriv, IRQ_SIMPLE | DISK_BUSY | PROC_CMD | START_EH); /* interrupt has not been received after more than (DEFAULT_CMD_TIMEOUT + WAIT_IRQ_TIMEOUT) ms, // /* interrupt has not been received after more than (DEFAULT_CMD_TIMEOUT + WAIT_IRQ_TIMEOUT) ms, * try to recover the link using WAIT_IRQ_TIMEOUT value for next deadline // * try to recover the link using WAIT_IRQ_TIMEOUT value for next deadline */ // */ deadline = jiffies + msecs_to_jiffies(WAIT_IRQ_TIMEOUT); // deadline = jiffies + msecs_to_jiffies(WAIT_IRQ_TIMEOUT); rc = ap->ops->hardreset(link, &class, deadline); // rc = ap->ops->hardreset(link, &class, deadline); if (!rc) // if (!rc) dev_err(dpriv->dev, "error: ahci_hardreset returned %ld\n", rc); // dev_err(dpriv->dev, "error: ahci_hardreset returned %ld\n", rc); ata_port_wait_eh(ap); // ata_port_wait_eh(ap); // // here we assume that circbuf has not been overrun yet, prepare to repeat current command // // here we assume that circbuf has not been overrun yet, prepare to repeat current command dpriv->lba_ptr.wr_count = 0; // dpriv->lba_ptr.wr_count = 0; dpriv->curr_cmd = 0; // dpriv->curr_cmd = 0; dpriv->max_data_sz = 0; // dpriv->max_data_sz = 0; dpriv->curr_data_chunk = 0; // dpriv->curr_data_chunk = 0; dpriv->curr_data_offset = 0; // dpriv->curr_data_offset = 0; dev_dbg(dpriv->dev, "repeat command from slot (head_ptr): %u\n", dpriv->head_ptr); dev_dbg(dpriv->dev, "repeat command from slot (head_ptr): %u\n", dpriv->head_ptr); // process_cmd(dpriv); } else { } else { // late interrupt received or the queue was woken up, proceed to normal operation // late interrupt received or the queue was woken up, proceed to normal operation if (rc < 0) { if (rc < 0) { Loading @@ -1302,7 +1305,7 @@ void error_handler(struct elphel_ahci_priv *dpriv) } } dpriv->stat.last_irq_delay = jiffies_to_msecs(delay) + DEFAULT_CMD_TIMEOUT; dpriv->stat.last_irq_delay = jiffies_to_msecs(delay) + DEFAULT_CMD_TIMEOUT; dpriv->stat.stat_ready = 1; dpriv->stat.stat_ready = 1; dev_warn(dpriv->dev, "late interrupt received, delay is %lu ms\n", dpriv->stat.last_irq_delay); dev_dbg(dpriv->dev, "late interrupt received, delay is %lu ms\n", dpriv->stat.last_irq_delay); reset_flag(dpriv, DELAYED_IRQ_RCVD | START_EH); reset_flag(dpriv, DELAYED_IRQ_RCVD | START_EH); } } reset_flag(dpriv, WAIT_EH); reset_flag(dpriv, WAIT_EH); Loading Loading @@ -1581,8 +1584,6 @@ static int elphel_qc_defer(struct ata_queued_cmd *qc) unsigned long irq_flags; unsigned long irq_flags; struct elphel_ahci_priv *dpriv = dev_get_dpriv(qc->ap->dev); struct elphel_ahci_priv *dpriv = dev_get_dpriv(qc->ap->dev); dev_dbg(qc->ap->dev, "flags: %u\n", dpriv->flags); /* First apply the usual rules */ /* First apply the usual rules */ ret = ata_std_qc_defer(qc); ret = ata_std_qc_defer(qc); if (ret != 0) if (ret != 0) Loading Loading @@ -1948,24 +1949,13 @@ static void set_dscope_tstamp(struct elphel_ahci_priv *dpriv, unsigned int cmd) void __iomem *port_mmio; void __iomem *port_mmio; uint32_t data = 0; uint32_t data = 0; // if (!dpriv->datascope.enable) // return; host = dev_get_drvdata(dpriv->dev); host = dev_get_drvdata(dpriv->dev); hpriv = host->private_data; hpriv = host->private_data; ap = host->ports[DEFAULT_PORT_NUM]; ap = host->ports[DEFAULT_PORT_NUM]; port_mmio = ahci_port_base(ap); port_mmio = ahci_port_base(ap); // one bit command flag (TSTMP_*) // three bits command flag (TSTMP_*) data |= (cmd & 0x7); data |= (cmd & 0x7); // command counter // data |= ((dpriv->datascope.cmd_cntr & 0x3) << 1); // if (cmd == TSTMP_IRQ_RCVD) { // dpriv->datascope.cmd_cntr++; // if (dpriv->datascope.cmd_cntr > 3) // dpriv->datascope.cmd_cntr = 0; // } iowrite32(data, port_mmio + PORT_TIMESTAMP_ADDR); iowrite32(data, port_mmio + PORT_TIMESTAMP_ADDR); } } Loading src/drivers/ata/ahci_elphel.h +8 −7 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ #define START_EH (1 << 6) ///< Start error handling procedure #define START_EH (1 << 6) ///< Start error handling procedure #define WAIT_EH (1 << 7) ///< Wait for error handler completion #define WAIT_EH (1 << 7) ///< Wait for error handler completion #define DELAYED_IRQ_RCVD (1 << 8) ///< Delayed interrupt received and should be processed #define DELAYED_IRQ_RCVD (1 << 8) ///< Delayed interrupt received and should be processed #define IRQ_PROCESSED (1 << 9) ///< Tell command guard timer that IRQ is received and EH should not be started #define CMD_FIS_LEN 5 ///< The length of a command FIS in double words #define CMD_FIS_LEN 5 ///< The length of a command FIS in double words #define ADDR_MASK_28_BIT ((u64)0xfffffff)///< This is used to get 28-bit address from 64-bit value #define ADDR_MASK_28_BIT ((u64)0xfffffff)///< This is used to get 28-bit address from 64-bit value #define MAX_PRDT_LEN 0x3fffff ///< A maximum of length of 4MB may exist for PRDT entry #define MAX_PRDT_LEN 0x3fffff ///< A maximum of length of 4MB may exist for PRDT entry Loading @@ -62,14 +63,14 @@ #define INCLUDE_REM 1 ///< Include REM buffer to total size calculation #define INCLUDE_REM 1 ///< Include REM buffer to total size calculation #define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation #define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation #define SPEED_SAMPLES_NUM 5 ///< Maximum number of samples for disk recording speed measurement #define SPEED_SAMPLES_NUM 5 ///< Maximum number of samples for disk recording speed measurement #define DEFAULT_CMD_TIMEOUT 100 ///< Default timeout for commands, in ms #define DEFAULT_CMD_TIMEOUT 200 ///< Default timeout for commands, in ms #define WAIT_IRQ_TIMEOUT 5000 ///< Wait delayed interrupt for this amount of time, in ms #define WAIT_IRQ_TIMEOUT 5000 ///< Wait delayed interrupt for this amount of time, in ms #define TSTMP_CMD_SYS 1 ///< command issued by system #define TSTMP_CMD_SYS 1 ///< command issued by system #define TSTMP_CMD_DRV 2 ///< command issued by driver #define TSTMP_CMD_DRV 2 ///< command issued by driver #define TSTMP_IRQ_SYS 3 ///< irq processed by system #define TSTMP_IRQ_SYS 3 ///< irq processed by system #define TSTMP_IRQ_DRV 4 ///< irq processed by driver #define TSTMP_IRQ_DRV 4 ///< irq processed by driver #define TSTMP_IRQ_MARK_1 5 #define TSTMP_IRQ_MARK_1 5 ///< additional time stamp mark enum { enum { PORT_VS = 0x70, ///< vendor specific port address PORT_VS = 0x70, ///< vendor specific port address PORT_TIMESTAMP_ADDR = 0x78 ///< datascope timestamp register PORT_TIMESTAMP_ADDR = 0x78 ///< datascope timestamp register Loading @@ -93,8 +94,8 @@ struct datascope { /** Data for error handler */ /** Data for error handler */ struct error_handler { struct error_handler { uint32_t s_error; uint32_t s_error; ///< the content of PxSERR register uint32_t irq_stat; uint32_t irq_stat; ///< the content of PxIS register wait_queue_head_t wait; ///< wait queue for delayed interrupts wait_queue_head_t wait; ///< wait queue for delayed interrupts }; }; Loading Loading
src/drivers/ata/ahci_elphel.c +48 −58 Original line number Original line Diff line number Diff line Loading @@ -144,7 +144,8 @@ static void remove_timer(struct elphel_ahci_priv *dpriv) if (timer_pending(&dpriv->cmd_timer)) { if (timer_pending(&dpriv->cmd_timer)) { ret = del_timer_sync(&dpriv->cmd_timer); ret = del_timer_sync(&dpriv->cmd_timer); if (ret < 0) if (ret < 0) dev_err(dpriv->dev, "can not remove timer\n"); dev_err(dpriv->dev, "can not remove command guard timer\n"); reset_flag(dpriv, IRQ_PROCESSED); } } } } Loading Loading @@ -176,11 +177,22 @@ static void reset_all_commands(struct elphel_ahci_priv *dpriv) /** Command execution timer has expired, set flag indicating that recording should be restarted */ /** Command execution timer has expired, set flag indicating that recording should be restarted */ static void process_timeout(unsigned long data) static void process_timeout(unsigned long data) { { int report = 0; unsigned long irq_flags; struct elphel_ahci_priv *dpriv = (struct elphel_ahci_priv *)data; struct elphel_ahci_priv *dpriv = (struct elphel_ahci_priv *)data; dev_err(dpriv->dev, "AHCI error: command execution timeout, LBA start = 0x%llx\n", dpriv->lba_ptr.lba_write); /* we are racing with interrupt here, IRQ handler sets IRQ_PROCESSED flag to prevent timer from * triggering error handler before this timer is removed */ spin_lock_irqsave(&dpriv->flags_lock, irq_flags); if (!(dpriv->flags & IRQ_PROCESSED)) { dpriv->flags |= START_EH; report = 1; } spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); if (report) { set_dscope_tstamp(dpriv, TSTMP_CMD_SYS); set_dscope_tstamp(dpriv, TSTMP_CMD_SYS); set_flag(dpriv, START_EH); } } } /** Calculate the difference between two time stamps and return it in microseconds */ /** Calculate the difference between two time stamps and return it in microseconds */ Loading Loading @@ -232,26 +244,19 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) host_irq_stat = readl(hpriv->mmio + HOST_IRQ_STAT); host_irq_stat = readl(hpriv->mmio + HOST_IRQ_STAT); if (!host_irq_stat) { if (!host_irq_stat) { dev_err(dpriv->dev, "Spurious IRQ received, host_irq_stat = 0x%x\n", host_irq_stat); dev_err(dpriv->dev, "Spurious IRQ received, host_irq_stat = 0x%x\n", host_irq_stat); // debug actions, check it one more time before exit host_irq_stat = readl(hpriv->mmio + HOST_IRQ_STAT); if (!host_irq_stat) { return IRQ_NONE; return IRQ_NONE; } else { dev_err(dpriv->dev, "Spurious interrupt not confirmed, host_irq_stat = 0x%x, proceed to IRQ processing\n", host_irq_stat); } } } // dpriv->flags &= ~IRQ_SIMPLE; reset_flag(dpriv, IRQ_SIMPLE); reset_flag(dpriv, IRQ_SIMPLE); irq_stat = readl(port_mmio + PORT_IRQ_STAT); irq_stat = readl(port_mmio + PORT_IRQ_STAT); serror = readl(port_mmio + PORT_SCR_ERR); serror = readl(port_mmio + PORT_SCR_ERR); /* debug feature, save current state for analysis */ dpriv->datascope.reg_stat[REG_HOST_IS] = host_irq_stat; dpriv->datascope.reg_stat[REG_HOST_IS] = host_irq_stat; dpriv->datascope.reg_stat[REG_PxIS] = irq_stat; dpriv->datascope.reg_stat[REG_PxIS] = irq_stat; dpriv->datascope.reg_stat[REG_PxSERR] = serror; dpriv->datascope.reg_stat[REG_PxSERR] = serror; dpriv->datascope.reg_stat[REG_PxIE] = readl(port_mmio + PORT_IRQ_MASK); dpriv->datascope.reg_stat[REG_PxIE] = readl(port_mmio + PORT_IRQ_MASK); dpriv->datascope.reg_stat[IRQ_COUNTER] = dpriv->datascope.reg_stat[IRQ_COUNTER] + 1; dpriv->datascope.reg_stat[IRQ_COUNTER] = dpriv->datascope.reg_stat[IRQ_COUNTER] + 1; // dev_dbg(host->dev, "irq_stat = 0x%x, host irq_stat = 0x%x, SErr = 0x%x\n", irq_stat, host_irq_stat, serror); if (unlikely(irq_stat & PORT_IRQ_ERROR)) { if (unlikely(irq_stat & PORT_IRQ_ERROR)) { dpriv->eh.irq_stat = irq_stat; dpriv->eh.irq_stat = irq_stat; Loading @@ -264,18 +269,21 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) handled = IRQ_HANDLED; handled = IRQ_HANDLED; set_dscope_tstamp(dpriv, TSTMP_IRQ_MARK_1); set_dscope_tstamp(dpriv, TSTMP_IRQ_MARK_1); /* check if this command timed out and charged error handler, do not schedule tasklet in this case as /* * check if this command timed out and charged error handler, do not schedule tasklet in this case as * the processing will restart from error handler * the processing will restart from error handler */ */ spin_lock_irqsave(&dpriv->flags_lock, irq_flags); if (dpriv->flags & (START_EH | WAIT_EH)) { if (dpriv->flags & (START_EH | WAIT_EH)) { // tell to EH that the command will be processed in normal way // tell to EH that the command will be processed in normal way set_dscope_tstamp(dpriv, TSTMP_IRQ_MARK_1); set_dscope_tstamp(dpriv, TSTMP_IRQ_MARK_1); set_flag(dpriv, DELAYED_IRQ_RCVD); dpriv->flags |= DELAYED_IRQ_RCVD; wake_up_interruptible(&dpriv->eh.wait); wake_up_interruptible(&dpriv->eh.wait); } else { } else { dpriv->flags |= IRQ_PROCESSED; tasklet_schedule(&dpriv->bh); tasklet_schedule(&dpriv->bh); } } spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); } else { } else { set_dscope_tstamp(dpriv, TSTMP_IRQ_SYS); set_dscope_tstamp(dpriv, TSTMP_IRQ_SYS); Loading @@ -294,12 +302,12 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) return handled; return handled; } } /** Command queue processing tasklet */ /** Command queue processing tasklet */ void process_queue(unsigned long data) void process_queue(unsigned long data) { { int i; int i; size_t total_sz = 0; size_t total_sz = 0; unsigned long irq_flags; unsigned long time_usec; unsigned long time_usec; sec_usec_t end_time = {0}; sec_usec_t end_time = {0}; struct elphel_ahci_priv *dpriv = (struct elphel_ahci_priv *)data; struct elphel_ahci_priv *dpriv = (struct elphel_ahci_priv *)data; Loading @@ -313,9 +321,9 @@ void process_queue(unsigned long data) add_sample(total_sz / time_usec, &dpriv->stat); add_sample(total_sz / time_usec, &dpriv->stat); } } // check if we can proceed - this was debug feature to fully stop cmd processing // // check if we can proceed - this was debug feature to fully stop cmd processing if (dpriv->flags & (START_EH | WAIT_EH)) // if (dpriv->flags & (START_EH | WAIT_EH)) return; // return; if (process_cmd(dpriv) == 0) { if (process_cmd(dpriv) == 0) { finish_cmd(dpriv); finish_cmd(dpriv); Loading @@ -327,9 +335,6 @@ void process_queue(unsigned long data) finish_rec(dpriv); finish_rec(dpriv); } else { } else { /* all commands have been processed */ /* all commands have been processed */ // spin_lock_irqsave(&dpriv->flags_lock, irq_flags); // dpriv->flags &= ~DISK_BUSY; // spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); reset_flag(dpriv, DISK_BUSY); reset_flag(dpriv, DISK_BUSY); } } } } Loading Loading @@ -1253,7 +1258,7 @@ static size_t get_prev_slot(const struct elphel_ahci_priv *dpriv) return slot; return slot; } } /** Handle delayed interrupt or ather errors */ /** Handle delayed interrupt or other errors */ void error_handler(struct elphel_ahci_priv *dpriv) void error_handler(struct elphel_ahci_priv *dpriv) { { long rc; long rc; Loading @@ -1272,27 +1277,25 @@ void error_handler(struct elphel_ahci_priv *dpriv) } } rc = wait_event_interruptible_timeout(dpriv->eh.wait, dpriv->flags & DELAYED_IRQ_RCVD, deadline); rc = wait_event_interruptible_timeout(dpriv->eh.wait, dpriv->flags & DELAYED_IRQ_RCVD, deadline); dev_warn(dpriv->dev, "wait_event_interruptible_timeout returned %ld\n", rc); dev_dbg(dpriv->dev, "wait_event_interruptible_timeout returned %ld\n", rc); if (!rc) { if (!rc) { return; reset_flag(dpriv, IRQ_SIMPLE | DISK_BUSY | PROC_CMD | START_EH); // reset_flag(dpriv, IRQ_SIMPLE | DISK_BUSY | PROC_CMD | START_EH); /* interrupt has not been received after more than (DEFAULT_CMD_TIMEOUT + WAIT_IRQ_TIMEOUT) ms, // /* interrupt has not been received after more than (DEFAULT_CMD_TIMEOUT + WAIT_IRQ_TIMEOUT) ms, * try to recover the link using WAIT_IRQ_TIMEOUT value for next deadline // * try to recover the link using WAIT_IRQ_TIMEOUT value for next deadline */ // */ deadline = jiffies + msecs_to_jiffies(WAIT_IRQ_TIMEOUT); // deadline = jiffies + msecs_to_jiffies(WAIT_IRQ_TIMEOUT); rc = ap->ops->hardreset(link, &class, deadline); // rc = ap->ops->hardreset(link, &class, deadline); if (!rc) // if (!rc) dev_err(dpriv->dev, "error: ahci_hardreset returned %ld\n", rc); // dev_err(dpriv->dev, "error: ahci_hardreset returned %ld\n", rc); ata_port_wait_eh(ap); // ata_port_wait_eh(ap); // // here we assume that circbuf has not been overrun yet, prepare to repeat current command // // here we assume that circbuf has not been overrun yet, prepare to repeat current command dpriv->lba_ptr.wr_count = 0; // dpriv->lba_ptr.wr_count = 0; dpriv->curr_cmd = 0; // dpriv->curr_cmd = 0; dpriv->max_data_sz = 0; // dpriv->max_data_sz = 0; dpriv->curr_data_chunk = 0; // dpriv->curr_data_chunk = 0; dpriv->curr_data_offset = 0; // dpriv->curr_data_offset = 0; dev_dbg(dpriv->dev, "repeat command from slot (head_ptr): %u\n", dpriv->head_ptr); dev_dbg(dpriv->dev, "repeat command from slot (head_ptr): %u\n", dpriv->head_ptr); // process_cmd(dpriv); } else { } else { // late interrupt received or the queue was woken up, proceed to normal operation // late interrupt received or the queue was woken up, proceed to normal operation if (rc < 0) { if (rc < 0) { Loading @@ -1302,7 +1305,7 @@ void error_handler(struct elphel_ahci_priv *dpriv) } } dpriv->stat.last_irq_delay = jiffies_to_msecs(delay) + DEFAULT_CMD_TIMEOUT; dpriv->stat.last_irq_delay = jiffies_to_msecs(delay) + DEFAULT_CMD_TIMEOUT; dpriv->stat.stat_ready = 1; dpriv->stat.stat_ready = 1; dev_warn(dpriv->dev, "late interrupt received, delay is %lu ms\n", dpriv->stat.last_irq_delay); dev_dbg(dpriv->dev, "late interrupt received, delay is %lu ms\n", dpriv->stat.last_irq_delay); reset_flag(dpriv, DELAYED_IRQ_RCVD | START_EH); reset_flag(dpriv, DELAYED_IRQ_RCVD | START_EH); } } reset_flag(dpriv, WAIT_EH); reset_flag(dpriv, WAIT_EH); Loading Loading @@ -1581,8 +1584,6 @@ static int elphel_qc_defer(struct ata_queued_cmd *qc) unsigned long irq_flags; unsigned long irq_flags; struct elphel_ahci_priv *dpriv = dev_get_dpriv(qc->ap->dev); struct elphel_ahci_priv *dpriv = dev_get_dpriv(qc->ap->dev); dev_dbg(qc->ap->dev, "flags: %u\n", dpriv->flags); /* First apply the usual rules */ /* First apply the usual rules */ ret = ata_std_qc_defer(qc); ret = ata_std_qc_defer(qc); if (ret != 0) if (ret != 0) Loading Loading @@ -1948,24 +1949,13 @@ static void set_dscope_tstamp(struct elphel_ahci_priv *dpriv, unsigned int cmd) void __iomem *port_mmio; void __iomem *port_mmio; uint32_t data = 0; uint32_t data = 0; // if (!dpriv->datascope.enable) // return; host = dev_get_drvdata(dpriv->dev); host = dev_get_drvdata(dpriv->dev); hpriv = host->private_data; hpriv = host->private_data; ap = host->ports[DEFAULT_PORT_NUM]; ap = host->ports[DEFAULT_PORT_NUM]; port_mmio = ahci_port_base(ap); port_mmio = ahci_port_base(ap); // one bit command flag (TSTMP_*) // three bits command flag (TSTMP_*) data |= (cmd & 0x7); data |= (cmd & 0x7); // command counter // data |= ((dpriv->datascope.cmd_cntr & 0x3) << 1); // if (cmd == TSTMP_IRQ_RCVD) { // dpriv->datascope.cmd_cntr++; // if (dpriv->datascope.cmd_cntr > 3) // dpriv->datascope.cmd_cntr = 0; // } iowrite32(data, port_mmio + PORT_TIMESTAMP_ADDR); iowrite32(data, port_mmio + PORT_TIMESTAMP_ADDR); } } Loading
src/drivers/ata/ahci_elphel.h +8 −7 Original line number Original line Diff line number Diff line Loading @@ -40,6 +40,7 @@ #define START_EH (1 << 6) ///< Start error handling procedure #define START_EH (1 << 6) ///< Start error handling procedure #define WAIT_EH (1 << 7) ///< Wait for error handler completion #define WAIT_EH (1 << 7) ///< Wait for error handler completion #define DELAYED_IRQ_RCVD (1 << 8) ///< Delayed interrupt received and should be processed #define DELAYED_IRQ_RCVD (1 << 8) ///< Delayed interrupt received and should be processed #define IRQ_PROCESSED (1 << 9) ///< Tell command guard timer that IRQ is received and EH should not be started #define CMD_FIS_LEN 5 ///< The length of a command FIS in double words #define CMD_FIS_LEN 5 ///< The length of a command FIS in double words #define ADDR_MASK_28_BIT ((u64)0xfffffff)///< This is used to get 28-bit address from 64-bit value #define ADDR_MASK_28_BIT ((u64)0xfffffff)///< This is used to get 28-bit address from 64-bit value #define MAX_PRDT_LEN 0x3fffff ///< A maximum of length of 4MB may exist for PRDT entry #define MAX_PRDT_LEN 0x3fffff ///< A maximum of length of 4MB may exist for PRDT entry Loading @@ -62,14 +63,14 @@ #define INCLUDE_REM 1 ///< Include REM buffer to total size calculation #define INCLUDE_REM 1 ///< Include REM buffer to total size calculation #define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation #define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation #define SPEED_SAMPLES_NUM 5 ///< Maximum number of samples for disk recording speed measurement #define SPEED_SAMPLES_NUM 5 ///< Maximum number of samples for disk recording speed measurement #define DEFAULT_CMD_TIMEOUT 100 ///< Default timeout for commands, in ms #define DEFAULT_CMD_TIMEOUT 200 ///< Default timeout for commands, in ms #define WAIT_IRQ_TIMEOUT 5000 ///< Wait delayed interrupt for this amount of time, in ms #define WAIT_IRQ_TIMEOUT 5000 ///< Wait delayed interrupt for this amount of time, in ms #define TSTMP_CMD_SYS 1 ///< command issued by system #define TSTMP_CMD_SYS 1 ///< command issued by system #define TSTMP_CMD_DRV 2 ///< command issued by driver #define TSTMP_CMD_DRV 2 ///< command issued by driver #define TSTMP_IRQ_SYS 3 ///< irq processed by system #define TSTMP_IRQ_SYS 3 ///< irq processed by system #define TSTMP_IRQ_DRV 4 ///< irq processed by driver #define TSTMP_IRQ_DRV 4 ///< irq processed by driver #define TSTMP_IRQ_MARK_1 5 #define TSTMP_IRQ_MARK_1 5 ///< additional time stamp mark enum { enum { PORT_VS = 0x70, ///< vendor specific port address PORT_VS = 0x70, ///< vendor specific port address PORT_TIMESTAMP_ADDR = 0x78 ///< datascope timestamp register PORT_TIMESTAMP_ADDR = 0x78 ///< datascope timestamp register Loading @@ -93,8 +94,8 @@ struct datascope { /** Data for error handler */ /** Data for error handler */ struct error_handler { struct error_handler { uint32_t s_error; uint32_t s_error; ///< the content of PxSERR register uint32_t irq_stat; uint32_t irq_stat; ///< the content of PxIS register wait_queue_head_t wait; ///< wait queue for delayed interrupts wait_queue_head_t wait; ///< wait queue for delayed interrupts }; }; Loading