Loading src/drivers/ata/ahci_elphel.c +56 −8 Original line number Original line Diff line number Diff line Loading @@ -13,6 +13,8 @@ * more details. * more details. */ */ #define CONFIG_PRINK #include <linux/errno.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/module.h> Loading Loading @@ -123,6 +125,7 @@ static void elphel_defer_load(struct device *dev) static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) { { unsigned long irq_flags; irqreturn_t handled; irqreturn_t handled; struct ata_host *host = dev_instance; struct ata_host *host = dev_instance; struct ahci_host_priv *hpriv = host->private_data; struct ahci_host_priv *hpriv = host->private_data; Loading @@ -133,7 +136,7 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) if (dpriv->flags & IRQ_SIMPLE) { if (dpriv->flags & IRQ_SIMPLE) { /* handle interrupt */ /* handle interrupt from internal command */ 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) return IRQ_NONE; return IRQ_NONE; Loading @@ -143,24 +146,27 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) dev_dbg(host->dev, "irq_stat = 0x%x, host irq_stat = 0x%x, time stamp: %u\n", irq_stat, host_irq_stat, get_rtc_usec()); dev_dbg(host->dev, "irq_stat = 0x%x, host irq_stat = 0x%x, time stamp: %u\n", irq_stat, host_irq_stat, get_rtc_usec()); writel(irq_stat, port_mmio + PORT_IRQ_STAT); writel(irq_stat, port_mmio + PORT_IRQ_STAT); // writel(0xffffffff, port_mmio + PORT_IRQ_STAT); writel(host_irq_stat, hpriv->mmio + HOST_IRQ_STAT); writel(host_irq_stat, hpriv->mmio + HOST_IRQ_STAT); handled = IRQ_HANDLED; handled = IRQ_HANDLED; if (process_cmd(host->dev, dpriv, host->ports[0]) == 0) { if (process_cmd(host->dev, dpriv, host->ports[DEFAULT_PORT_NUM]) == 0) { finish_cmd(host->dev, dpriv); finish_cmd(host->dev, dpriv); if (move_head(dpriv) != -1) { if (move_head(dpriv) != -1) { process_cmd(host->dev, dpriv, host->ports[0]); process_cmd(host->dev, dpriv, host->ports[DEFAULT_PORT_NUM]); } else { } else { if (dpriv->flags & DELAYED_FINISH) { if (dpriv->flags & DELAYED_FINISH) { dpriv->flags &= ~DELAYED_FINISH; dpriv->flags &= ~DELAYED_FINISH; finish_rec(host->dev, dpriv, port); finish_rec(host->dev, dpriv, port); } else { /* all commands have been processed; flag reset here does not need spin lock protection */ dpriv->flags &= ~INTERNAL_CMD; } } } } } } } else { } else { /* pass handling to AHCI level */ /* pass handling to AHCI level; flag reset here does not need spin lock protection */ dpriv->flags &= ~NATIVE_CMD; handled = ahci_single_irq_intr(irq, dev_instance); handled = ahci_single_irq_intr(irq, dev_instance); } } Loading Loading @@ -269,6 +275,8 @@ static int elphel_drv_probe(struct platform_device *pdev) if (!dpriv) if (!dpriv) return -ENOMEM; return -ENOMEM; spin_lock_init(&dpriv->flags_lock); for (i = 0; i < MAX_CMD_SLOTS; i++) { for (i = 0; i < MAX_CMD_SLOTS; i++) { ret = init_buffers(dev, &dpriv->fbuffs[i]); ret = init_buffers(dev, &dpriv->fbuffs[i]); if (ret != 0) if (ret != 0) Loading Loading @@ -783,7 +791,6 @@ static void align_frame(struct device *dev, struct elphel_ahci_priv *dpriv) dma_sync_single_for_cpu(dev, fbuffs->common_buff.iov_dma, fbuffs->common_buff.iov_len, DMA_TO_DEVICE); dma_sync_single_for_cpu(dev, fbuffs->common_buff.iov_dma, fbuffs->common_buff.iov_len, DMA_TO_DEVICE); /* copy remainder of previous frame to the beginning of common buffer */ /* copy remainder of previous frame to the beginning of common buffer */ printk(KERN_DEBUG "current command slot: %u, prev slot: %u\n", cmd_slot, prev_slot); if (likely(rbuff->iov_len != 0)) { if (likely(rbuff->iov_len != 0)) { len = rbuff->iov_len; len = rbuff->iov_len; dev_dbg(dev, "copy %u bytes from REM #%u to common buffer\n", len, prev_slot); dev_dbg(dev, "copy %u bytes from REM #%u to common buffer\n", len, prev_slot); Loading Loading @@ -1152,6 +1159,7 @@ static int process_cmd(struct device *dev, struct elphel_ahci_priv *dpriv, struc static void finish_cmd(struct device *dev, struct elphel_ahci_priv *dpriv) static void finish_cmd(struct device *dev, struct elphel_ahci_priv *dpriv) { { int all; int all; unsigned long irq_flags; dpriv->lba_ptr.wr_count = 0; dpriv->lba_ptr.wr_count = 0; if ((dpriv->flags & LAST_BLOCK) == 0) { if ((dpriv->flags & LAST_BLOCK) == 0) { Loading @@ -1162,6 +1170,7 @@ static void finish_cmd(struct device *dev, struct elphel_ahci_priv *dpriv) } } printk(KERN_DEBUG "reset chunks in slot %u, all = %d\n", dpriv->head_ptr, all); printk(KERN_DEBUG "reset chunks in slot %u, all = %d\n", dpriv->head_ptr, all); reset_chunks(dpriv->data_chunks[dpriv->head_ptr], all); reset_chunks(dpriv->data_chunks[dpriv->head_ptr], all); /* flag reset here does not need spin lock protection */ dpriv->flags &= ~PROC_CMD; dpriv->flags &= ~PROC_CMD; dpriv->curr_cmd = 0; dpriv->curr_cmd = 0; dpriv->max_data_sz = 0; dpriv->max_data_sz = 0; Loading Loading @@ -1253,6 +1262,7 @@ static ssize_t rawdev_write(struct device *dev, ///< size_t buff_sz) ///< size_t buff_sz) ///< { { int i; int i; unsigned long irq_flags; struct ata_host *host = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev); struct ata_port *port = host->ports[DEFAULT_PORT_NUM]; struct ata_port *port = host->ports[DEFAULT_PORT_NUM]; struct elphel_ahci_priv *dpriv = dev_get_dpriv(dev); struct elphel_ahci_priv *dpriv = dev_get_dpriv(dev); Loading @@ -1262,12 +1272,25 @@ static ssize_t rawdev_write(struct device *dev, ///< struct fvec *chunks; struct fvec *chunks; static int dont_process = 0; static int dont_process = 0; /* simple check if we've got the right command */ if (buff_sz != sizeof(struct frame_data)) { if (buff_sz != sizeof(struct frame_data)) { dev_err(dev, "the size of the data buffer is incorrect, should be equal to sizeof(struct frame_data)\n"); dev_err(dev, "the size of the data buffer is incorrect, should be equal to sizeof(struct frame_data)\n"); return -EINVAL; return -EINVAL; } } memcpy(&fdata, buff, sizeof(struct frame_data)); memcpy(&fdata, buff, sizeof(struct frame_data)); /* check if we can issue internal command */ spin_lock_irqsave(&dpriv->flags_lock, irq_flags); if ((dpriv->flags & NATIVE_CMD) == 0) { dpriv->flags |= INTERNAL_CMD; } else { spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); printk_ratelimited(KERN_DEBUG, "system command is in progress, defer Elphel command\n"); // dev_dbg(dev, "system command is in progress, defer Elphel command\n"); return -EAGAIN; } spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); if (fdata.cmd == DRV_CMD_FINISH) { if (fdata.cmd == DRV_CMD_FINISH) { if (!(dpriv->flags & PROC_CMD)) { if (!(dpriv->flags & PROC_CMD)) { finish_rec(dev, dpriv, port); finish_rec(dev, dpriv, port); Loading @@ -1278,10 +1301,9 @@ static ssize_t rawdev_write(struct device *dev, ///< } } if ((move_tail(dpriv, 1) == -1) || dont_process) { if ((move_tail(dpriv, 1) == -1) || dont_process) { // we are not ready yet /* we are not ready yet because command queue is full */ return -EAGAIN; return -EAGAIN; } } printk(KERN_DEBUG "set current tail slot: %u\n", dpriv->tail_ptr); chunks = &dpriv->data_chunks[dpriv->tail_ptr]; chunks = &dpriv->data_chunks[dpriv->tail_ptr]; buffs = &dpriv->fbuffs[dpriv->tail_ptr]; buffs = &dpriv->fbuffs[dpriv->tail_ptr]; Loading Loading @@ -1499,6 +1521,31 @@ static void elphel_cmd_issue(struct ata_port *ap,///< device port for which the writel(1 << slot_num, port_mmio + PORT_CMD_ISSUE); writel(1 << slot_num, port_mmio + PORT_CMD_ISSUE); } } static int elphel_qc_defer(struct ata_queued_cmd *qc) { int ret; unsigned long irq_flags; struct elphel_ahci_priv *dpriv = dev_get_dpriv(qc->ap->dev); /* First apply the usual rules */ ret = ata_std_qc_defer(qc); if (ret != 0) return ret; /* And now check if internal command is in progress */ spin_lock_irqsave(&dpriv->flags_lock, irq_flags); if (dpriv->flags & INTERNAL_CMD) { ret = ATA_DEFER_LINK; printk_ratelimited(KERN_DEBUG "defer system command\n"); } else { printk_ratelimited(KERN_DEBUG "proceed to system command\n"); dpriv->flags |= NATIVE_CMD; } spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); return ret; } static ssize_t lba_start_read(struct device *dev, struct device_attribute *attr, char *buff) static ssize_t lba_start_read(struct device *dev, struct device_attribute *attr, char *buff) { { struct ata_host *host = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev); Loading Loading @@ -1596,6 +1643,7 @@ static struct ata_port_operations ahci_elphel_ops = { .inherits = &ahci_ops, .inherits = &ahci_ops, .port_start = elphel_port_start, .port_start = elphel_port_start, .qc_prep = elphel_qc_prep, .qc_prep = elphel_qc_prep, .qc_defer = elphel_qc_defer, }; }; static const struct ata_port_info ahci_elphel_port_info = { static const struct ata_port_info ahci_elphel_port_info = { Loading src/drivers/ata/ahci_elphel.h +18 −6 Original line number Original line Diff line number Diff line Loading @@ -24,16 +24,22 @@ #ifndef _AHCI_ELPHEL_EXT #ifndef _AHCI_ELPHEL_EXT #define _AHCI_ELPHEL_EXT #define _AHCI_ELPHEL_EXT /** Flag indicating that IRQ should not be processed in ahci_port_interrupt */ /** Flag indicating that IRQ should not be processed in ahci_handle_port_interrupt */ #define IRQ_SIMPLE (1 << 0) #define IRQ_SIMPLE (1 << 0) /** Processing command in progress */ /** Flag indicating that driver's internal command is in progress. This flag is set when #define PROC_CMD (1 << 1) * driver performs write on its own and is mutually exclusive with #NATIVE_CMD flag */ #define INTERNAL_CMD (1 << 1) /** Flag indicating that libahci command is in progress. This flag is set when * driver performs write from the system calls and is mutually exclusive with #INTERNAL_CMD flag */ #define NATIVE_CMD (1 << 2) /** Processing driver's internal command is in progress */ #define PROC_CMD (1 << 3) /** Flag indicating that the remaining chunk of data will be recorder */ /** Flag indicating that the remaining chunk of data will be recorder */ #define LAST_BLOCK (1 << 2) #define LAST_BLOCK (1 << 4) /** Flag indicating that recording should be stopped right after the last chunk of data /** Flag indicating that recording should be stopped right after the last chunk of data * is written */ * is written */ #define DELAYED_FINISH (1 << 3) #define DELAYED_FINISH (1 << 5) #define LOCK_TAIL (1 << 4) #define LOCK_TAIL (1 << 6) /** The length of a command FIS in double words */ /** The length of a command FIS in double words */ #define CMD_FIS_LEN 5 #define CMD_FIS_LEN 5 /** This is used to get 28-bit address from 64-bit value */ /** This is used to get 28-bit address from 64-bit value */ Loading Loading @@ -119,6 +125,12 @@ struct elphel_ahci_priv { size_t curr_data_offset; ///< offset of the last byte in a data chunk pointed to by @e curr_data_chunk size_t curr_data_offset; ///< offset of the last byte in a data chunk pointed to by @e curr_data_chunk size_t head_ptr; ///< pointer to command slot which will be written next size_t head_ptr; ///< pointer to command slot which will be written next size_t tail_ptr; ///< pointer to next free command slot size_t tail_ptr; ///< pointer to next free command slot spinlock_t flags_lock; ///< controls access to two flags in @e flags variable: ///< #INTERNAL_CMD and #NATIVE_CMD. These flags control access to disk ///< write operations either from the the driver itself or from the system and ///< thus are mutually exclusive. Only flags set operation should be ///> protected by this spin lock. Mutex is not used because these flags are accessed ///> from interrupt context }; }; #endif /* _AHCI_ELPHEL_EXT */ #endif /* _AHCI_ELPHEL_EXT */ Loading
src/drivers/ata/ahci_elphel.c +56 −8 Original line number Original line Diff line number Diff line Loading @@ -13,6 +13,8 @@ * more details. * more details. */ */ #define CONFIG_PRINK #include <linux/errno.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/module.h> Loading Loading @@ -123,6 +125,7 @@ static void elphel_defer_load(struct device *dev) static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) { { unsigned long irq_flags; irqreturn_t handled; irqreturn_t handled; struct ata_host *host = dev_instance; struct ata_host *host = dev_instance; struct ahci_host_priv *hpriv = host->private_data; struct ahci_host_priv *hpriv = host->private_data; Loading @@ -133,7 +136,7 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) if (dpriv->flags & IRQ_SIMPLE) { if (dpriv->flags & IRQ_SIMPLE) { /* handle interrupt */ /* handle interrupt from internal command */ 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) return IRQ_NONE; return IRQ_NONE; Loading @@ -143,24 +146,27 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance) dev_dbg(host->dev, "irq_stat = 0x%x, host irq_stat = 0x%x, time stamp: %u\n", irq_stat, host_irq_stat, get_rtc_usec()); dev_dbg(host->dev, "irq_stat = 0x%x, host irq_stat = 0x%x, time stamp: %u\n", irq_stat, host_irq_stat, get_rtc_usec()); writel(irq_stat, port_mmio + PORT_IRQ_STAT); writel(irq_stat, port_mmio + PORT_IRQ_STAT); // writel(0xffffffff, port_mmio + PORT_IRQ_STAT); writel(host_irq_stat, hpriv->mmio + HOST_IRQ_STAT); writel(host_irq_stat, hpriv->mmio + HOST_IRQ_STAT); handled = IRQ_HANDLED; handled = IRQ_HANDLED; if (process_cmd(host->dev, dpriv, host->ports[0]) == 0) { if (process_cmd(host->dev, dpriv, host->ports[DEFAULT_PORT_NUM]) == 0) { finish_cmd(host->dev, dpriv); finish_cmd(host->dev, dpriv); if (move_head(dpriv) != -1) { if (move_head(dpriv) != -1) { process_cmd(host->dev, dpriv, host->ports[0]); process_cmd(host->dev, dpriv, host->ports[DEFAULT_PORT_NUM]); } else { } else { if (dpriv->flags & DELAYED_FINISH) { if (dpriv->flags & DELAYED_FINISH) { dpriv->flags &= ~DELAYED_FINISH; dpriv->flags &= ~DELAYED_FINISH; finish_rec(host->dev, dpriv, port); finish_rec(host->dev, dpriv, port); } else { /* all commands have been processed; flag reset here does not need spin lock protection */ dpriv->flags &= ~INTERNAL_CMD; } } } } } } } else { } else { /* pass handling to AHCI level */ /* pass handling to AHCI level; flag reset here does not need spin lock protection */ dpriv->flags &= ~NATIVE_CMD; handled = ahci_single_irq_intr(irq, dev_instance); handled = ahci_single_irq_intr(irq, dev_instance); } } Loading Loading @@ -269,6 +275,8 @@ static int elphel_drv_probe(struct platform_device *pdev) if (!dpriv) if (!dpriv) return -ENOMEM; return -ENOMEM; spin_lock_init(&dpriv->flags_lock); for (i = 0; i < MAX_CMD_SLOTS; i++) { for (i = 0; i < MAX_CMD_SLOTS; i++) { ret = init_buffers(dev, &dpriv->fbuffs[i]); ret = init_buffers(dev, &dpriv->fbuffs[i]); if (ret != 0) if (ret != 0) Loading Loading @@ -783,7 +791,6 @@ static void align_frame(struct device *dev, struct elphel_ahci_priv *dpriv) dma_sync_single_for_cpu(dev, fbuffs->common_buff.iov_dma, fbuffs->common_buff.iov_len, DMA_TO_DEVICE); dma_sync_single_for_cpu(dev, fbuffs->common_buff.iov_dma, fbuffs->common_buff.iov_len, DMA_TO_DEVICE); /* copy remainder of previous frame to the beginning of common buffer */ /* copy remainder of previous frame to the beginning of common buffer */ printk(KERN_DEBUG "current command slot: %u, prev slot: %u\n", cmd_slot, prev_slot); if (likely(rbuff->iov_len != 0)) { if (likely(rbuff->iov_len != 0)) { len = rbuff->iov_len; len = rbuff->iov_len; dev_dbg(dev, "copy %u bytes from REM #%u to common buffer\n", len, prev_slot); dev_dbg(dev, "copy %u bytes from REM #%u to common buffer\n", len, prev_slot); Loading Loading @@ -1152,6 +1159,7 @@ static int process_cmd(struct device *dev, struct elphel_ahci_priv *dpriv, struc static void finish_cmd(struct device *dev, struct elphel_ahci_priv *dpriv) static void finish_cmd(struct device *dev, struct elphel_ahci_priv *dpriv) { { int all; int all; unsigned long irq_flags; dpriv->lba_ptr.wr_count = 0; dpriv->lba_ptr.wr_count = 0; if ((dpriv->flags & LAST_BLOCK) == 0) { if ((dpriv->flags & LAST_BLOCK) == 0) { Loading @@ -1162,6 +1170,7 @@ static void finish_cmd(struct device *dev, struct elphel_ahci_priv *dpriv) } } printk(KERN_DEBUG "reset chunks in slot %u, all = %d\n", dpriv->head_ptr, all); printk(KERN_DEBUG "reset chunks in slot %u, all = %d\n", dpriv->head_ptr, all); reset_chunks(dpriv->data_chunks[dpriv->head_ptr], all); reset_chunks(dpriv->data_chunks[dpriv->head_ptr], all); /* flag reset here does not need spin lock protection */ dpriv->flags &= ~PROC_CMD; dpriv->flags &= ~PROC_CMD; dpriv->curr_cmd = 0; dpriv->curr_cmd = 0; dpriv->max_data_sz = 0; dpriv->max_data_sz = 0; Loading Loading @@ -1253,6 +1262,7 @@ static ssize_t rawdev_write(struct device *dev, ///< size_t buff_sz) ///< size_t buff_sz) ///< { { int i; int i; unsigned long irq_flags; struct ata_host *host = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev); struct ata_port *port = host->ports[DEFAULT_PORT_NUM]; struct ata_port *port = host->ports[DEFAULT_PORT_NUM]; struct elphel_ahci_priv *dpriv = dev_get_dpriv(dev); struct elphel_ahci_priv *dpriv = dev_get_dpriv(dev); Loading @@ -1262,12 +1272,25 @@ static ssize_t rawdev_write(struct device *dev, ///< struct fvec *chunks; struct fvec *chunks; static int dont_process = 0; static int dont_process = 0; /* simple check if we've got the right command */ if (buff_sz != sizeof(struct frame_data)) { if (buff_sz != sizeof(struct frame_data)) { dev_err(dev, "the size of the data buffer is incorrect, should be equal to sizeof(struct frame_data)\n"); dev_err(dev, "the size of the data buffer is incorrect, should be equal to sizeof(struct frame_data)\n"); return -EINVAL; return -EINVAL; } } memcpy(&fdata, buff, sizeof(struct frame_data)); memcpy(&fdata, buff, sizeof(struct frame_data)); /* check if we can issue internal command */ spin_lock_irqsave(&dpriv->flags_lock, irq_flags); if ((dpriv->flags & NATIVE_CMD) == 0) { dpriv->flags |= INTERNAL_CMD; } else { spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); printk_ratelimited(KERN_DEBUG, "system command is in progress, defer Elphel command\n"); // dev_dbg(dev, "system command is in progress, defer Elphel command\n"); return -EAGAIN; } spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); if (fdata.cmd == DRV_CMD_FINISH) { if (fdata.cmd == DRV_CMD_FINISH) { if (!(dpriv->flags & PROC_CMD)) { if (!(dpriv->flags & PROC_CMD)) { finish_rec(dev, dpriv, port); finish_rec(dev, dpriv, port); Loading @@ -1278,10 +1301,9 @@ static ssize_t rawdev_write(struct device *dev, ///< } } if ((move_tail(dpriv, 1) == -1) || dont_process) { if ((move_tail(dpriv, 1) == -1) || dont_process) { // we are not ready yet /* we are not ready yet because command queue is full */ return -EAGAIN; return -EAGAIN; } } printk(KERN_DEBUG "set current tail slot: %u\n", dpriv->tail_ptr); chunks = &dpriv->data_chunks[dpriv->tail_ptr]; chunks = &dpriv->data_chunks[dpriv->tail_ptr]; buffs = &dpriv->fbuffs[dpriv->tail_ptr]; buffs = &dpriv->fbuffs[dpriv->tail_ptr]; Loading Loading @@ -1499,6 +1521,31 @@ static void elphel_cmd_issue(struct ata_port *ap,///< device port for which the writel(1 << slot_num, port_mmio + PORT_CMD_ISSUE); writel(1 << slot_num, port_mmio + PORT_CMD_ISSUE); } } static int elphel_qc_defer(struct ata_queued_cmd *qc) { int ret; unsigned long irq_flags; struct elphel_ahci_priv *dpriv = dev_get_dpriv(qc->ap->dev); /* First apply the usual rules */ ret = ata_std_qc_defer(qc); if (ret != 0) return ret; /* And now check if internal command is in progress */ spin_lock_irqsave(&dpriv->flags_lock, irq_flags); if (dpriv->flags & INTERNAL_CMD) { ret = ATA_DEFER_LINK; printk_ratelimited(KERN_DEBUG "defer system command\n"); } else { printk_ratelimited(KERN_DEBUG "proceed to system command\n"); dpriv->flags |= NATIVE_CMD; } spin_unlock_irqrestore(&dpriv->flags_lock, irq_flags); return ret; } static ssize_t lba_start_read(struct device *dev, struct device_attribute *attr, char *buff) static ssize_t lba_start_read(struct device *dev, struct device_attribute *attr, char *buff) { { struct ata_host *host = dev_get_drvdata(dev); struct ata_host *host = dev_get_drvdata(dev); Loading Loading @@ -1596,6 +1643,7 @@ static struct ata_port_operations ahci_elphel_ops = { .inherits = &ahci_ops, .inherits = &ahci_ops, .port_start = elphel_port_start, .port_start = elphel_port_start, .qc_prep = elphel_qc_prep, .qc_prep = elphel_qc_prep, .qc_defer = elphel_qc_defer, }; }; static const struct ata_port_info ahci_elphel_port_info = { static const struct ata_port_info ahci_elphel_port_info = { Loading
src/drivers/ata/ahci_elphel.h +18 −6 Original line number Original line Diff line number Diff line Loading @@ -24,16 +24,22 @@ #ifndef _AHCI_ELPHEL_EXT #ifndef _AHCI_ELPHEL_EXT #define _AHCI_ELPHEL_EXT #define _AHCI_ELPHEL_EXT /** Flag indicating that IRQ should not be processed in ahci_port_interrupt */ /** Flag indicating that IRQ should not be processed in ahci_handle_port_interrupt */ #define IRQ_SIMPLE (1 << 0) #define IRQ_SIMPLE (1 << 0) /** Processing command in progress */ /** Flag indicating that driver's internal command is in progress. This flag is set when #define PROC_CMD (1 << 1) * driver performs write on its own and is mutually exclusive with #NATIVE_CMD flag */ #define INTERNAL_CMD (1 << 1) /** Flag indicating that libahci command is in progress. This flag is set when * driver performs write from the system calls and is mutually exclusive with #INTERNAL_CMD flag */ #define NATIVE_CMD (1 << 2) /** Processing driver's internal command is in progress */ #define PROC_CMD (1 << 3) /** Flag indicating that the remaining chunk of data will be recorder */ /** Flag indicating that the remaining chunk of data will be recorder */ #define LAST_BLOCK (1 << 2) #define LAST_BLOCK (1 << 4) /** Flag indicating that recording should be stopped right after the last chunk of data /** Flag indicating that recording should be stopped right after the last chunk of data * is written */ * is written */ #define DELAYED_FINISH (1 << 3) #define DELAYED_FINISH (1 << 5) #define LOCK_TAIL (1 << 4) #define LOCK_TAIL (1 << 6) /** The length of a command FIS in double words */ /** The length of a command FIS in double words */ #define CMD_FIS_LEN 5 #define CMD_FIS_LEN 5 /** This is used to get 28-bit address from 64-bit value */ /** This is used to get 28-bit address from 64-bit value */ Loading Loading @@ -119,6 +125,12 @@ struct elphel_ahci_priv { size_t curr_data_offset; ///< offset of the last byte in a data chunk pointed to by @e curr_data_chunk size_t curr_data_offset; ///< offset of the last byte in a data chunk pointed to by @e curr_data_chunk size_t head_ptr; ///< pointer to command slot which will be written next size_t head_ptr; ///< pointer to command slot which will be written next size_t tail_ptr; ///< pointer to next free command slot size_t tail_ptr; ///< pointer to next free command slot spinlock_t flags_lock; ///< controls access to two flags in @e flags variable: ///< #INTERNAL_CMD and #NATIVE_CMD. These flags control access to disk ///< write operations either from the the driver itself or from the system and ///< thus are mutually exclusive. Only flags set operation should be ///> protected by this spin lock. Mutex is not used because these flags are accessed ///> from interrupt context }; }; #endif /* _AHCI_ELPHEL_EXT */ #endif /* _AHCI_ELPHEL_EXT */