On Mon, Aug 24, 2015 at 01:39:15PM +0100, Qais Yousef wrote:
+int axd_cmd_set_pc(struct axd_cmd *cmd, unsigned int thread, unsigned long pc)Return sensible error codes please.
+{
+ if (thread >= THREAD_COUNT)
+ return -1;
+unsigned long axd_cmd_get_datain_address(struct axd_cmd *cmd)What's going on with these casts?
+{
+ struct axd_dev *axd = container_of(cmd, struct axd_dev, cmd);
+
+ return (unsigned long) axd->buf_base_m;
+}
+static inline void axd_set_flag(unsigned int *flag, unsigned int value)Please use a normal locking construct rather than hand rolling
+{
+ *flag = value;
+ smp_wmb(); /* guarantee smp ordering */
+}
+
+static inline unsigned int axd_get_flag(unsigned int *flag)
+{
+ smp_rmb(); /* guarantee smp ordering */
+ return *flag;
+}
something, or alternatively introduce new generic operations. The fact
that you're hand rolling these things that have no driver specific
content is really worrying in terms of their safety.
+/*Why is the case with in place buffers not a simple zero iteration loop?
+ * axd_pipe->enabled_flg for output pipes is overloaded to mean two things:
+ *
+ * - PIPE_STARTED: indicates that pipe was opened but no buffers were passed.
+ * When stopping the pipes, we know that we don't need to discard anything if
+ * the discard_flg is set in cmd struct. Which allows us to terminate easily
+ * and quickly.
+ *
+ * - PIPE_RUNNING: indicates that pipe has processed some buffers, so we should
+ * discard if user terminates early (and discard_flg is set in cmd struct).
+ */
+#define PIPE_STARTED 1
+#define PIPE_RUNNING 2
+#ifdef AXD_DEBUG_DIAGNo static globals and please follow the kernel coding style.
+static unsigned int inSentCount[AXD_MAX_PIPES];
+static unsigned int inRecvCount[AXD_MAX_PIPES];
+static unsigned int outSentCount[AXD_MAX_PIPES];
+static unsigned int outRecvCount[AXD_MAX_PIPES];
+static unsigned int primeupCount[AXD_MAX_PIPES];
+static unsigned int read_size[AXD_MAX_PIPES];
+static unsigned int write_size[AXD_MAX_PIPES];
+static unsigned int recv_size[AXD_MAX_PIPES];
+static inline void axd_datain_kick(struct axd_pipe *axd_pipe)Define accessor macros for these and then define them to noops when not
+{
+ unsigned long flags;
+ struct axd_memory_map __iomem *message = axd_pipe->cmd->message;
+ unsigned int pipe = axd_pipe->id;
+ unsigned int temp;
+
+#ifdef AXD_DEBUG_DIAG
+ inSentCount[pipe]++;
+#endif
debugging rather than having #defines in the code.
+static irqreturn_t axd_irq(int irq, void *data)Eew.
+{
+ struct axd_cmd *cmd = data;
+ unsigned int int_status;
+ unsigned long flags;
+ int i, ret;
+
+ /*
+ * int_status is ioremapped() which means it could page fault. When axd
+ * is running on the same core as the host, holding lock2 would disable
+ * exception handling in that core which means a page fault would stuff
+ * host thread executing the driver. We do a double read here to ensure
+ * that we stall until the memory access is done before lock2 is
+ * acquired, hence ensuring that any page fault is handled outside lock2
+ * region.
+ */
+ int_status = ioread32(&cmd->message->int_status);
+ int_status = ioread32(&cmd->message->int_status);
+When would this ever be called anywhere else? Just inline it (and it's
+ axd_platform_irq_ack();
better practice to only ack things we handle...).
+ flags = axd_platform_lock();This should cause us to return IRQ_NONE.
+ int_status = ioread32(&cmd->message->int_status);
+ iowrite32(0, &cmd->message->int_status);
+
+ if (!int_status)
+ goto out;
+ if (int_status & AXD_INT_ERROR) {We just ignore these?
+ struct axd_dev *axd = container_of(cmd, struct axd_dev, cmd);
+ int error = ioread32(&cmd->message->error);
+
+ pr_debug("<---- Received error interrupt\n");
+ switch (error) {
+ default:
+ case 0:
+ break;
+ case 2:Does the configuration command notice?
+ dev_warn(axd->dev, "Failed to set last configuration command\n");
+ break;
+ /*It really feels like this locking is all complicated and fragile. I'm
+ * if we could lock the semaphore, then we're guaranteed that the
+ * current rd_idx is valid and ready to be used. So no need to verify
+ * that the status of the descriptor at rd_idx is valid.
+ */
+ spin_lock(&desc_ctrl->rd_lock);
not entirely sure the optimisation is worth it - are we really sending
compressed audio at such a high rate that it's worth having concurrency
handling that's hard to think about?
+void axd_cmd_free_irq(struct axd_cmd *cmd, unsigned int irqnum)_sync()
+{
+ flush_workqueue(cmd->in_workq);
+ destroy_workqueue(cmd->in_workq);We're freeing the interrupts after we destroy the workqueue which means
+ flush_workqueue(cmd->out_workq);
+ destroy_workqueue(cmd->out_workq);
+ free_irq(irqnum, cmd);
we could try to schedule new work after destruction.
+ /*I'm not sure that was an especially tricky line of code to follow... am
+ * Based on the defined axd_pipe->buf_size and number of input pipes
+ * supported by the firmware, we calculate the number of descriptors we
+ * need to use using this formula:
+ *
+ * axd_pipe->buf_size * num_desc = total_size / num_inputs
+ */
+ num_desc = total_size / (cmd->num_inputs * axd_pipe->buf_size);
I missing something here?
I've stopped reviewing here mostly because it's the end of my day and
this patch is 72K which is enormous for something that's not just lots
of defines or whatever and actually needs reading in considerable detail
given all the tricky concurrency stuff you're doing. Please split this
code up into multiple patches for ease of review. For example all the
queue management and allocation seems rather separate to the interrupt
handling.
It also feels like there's room for pruning the code, perhaps sharing
more of it between input and output paths and removing some layers of
abstraction.