Ver código fonte

waterHeterogeneousDataSynchronization memoryOperation.c 姚强 commit at 2020-09-25

姚强 4 anos atrás
pai
commit
87f572be2e

+ 176 - 0
waterHeterogeneousDataSynchronization/dataSharedMemory/memoryOperation.c

@@ -196,3 +196,179 @@ s3c2410_dma_waitforload(struct s3c2410_dma_chan *chan, int line)
 	return 0;
 }
 
+/* s3c2410_dma_loadbuffer
+ *
+ * load a buffer, and update the channel state
+*/
+
+static inline int
+s3c2410_dma_loadbuffer(struct s3c2410_dma_chan *chan,
+		       struct s3c2410_dma_buf *buf)
+{
+	unsigned long reload;
+
+	if (buf == NULL) {
+		dmawarn("buffer is NULL\n");
+		return -EINVAL;
+	}
+
+	pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
+		 buf, (unsigned long)buf->data, buf->size);
+
+	/* check the state of the channel before we do anything */
+
+	if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
+		dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
+	}
+
+	if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
+		dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
+	}
+
+	/* it would seem sensible if we are the last buffer to not bother
+	 * with the auto-reload bit, so that the DMA engine will not try
+	 * and load another transfer after this one has finished...
+	 */
+	if (chan->load_state == S3C2410_DMALOAD_NONE) {
+		pr_debug("load_state is none, checking for noreload (next=%p)\n",
+			 buf->next);
+		reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
+	} else {
+		//pr_debug("load_state is %d => autoreload\n", chan->load_state);
+		reload = S3C2410_DCON_AUTORELOAD;
+	}
+
+	if ((buf->data & 0xf0000000) != 0x30000000) {
+		dmawarn("dmaload: buffer is %p\n", (void *)buf->data);
+	}
+
+	writel(buf->data, chan->addr_reg);
+
+	dma_wrreg(chan, S3C2410_DMA_DCON,
+		  chan->dcon | reload | (buf->size/chan->xfer_unit));
+
+	chan->next = buf->next;
+
+	/* update the state of the channel */
+
+	switch (chan->load_state) {
+	case S3C2410_DMALOAD_NONE:
+		chan->load_state = S3C2410_DMALOAD_1LOADED;
+		break;
+
+	case S3C2410_DMALOAD_1RUNNING:
+		chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
+		break;
+
+	default:
+		dmawarn("dmaload: unknown state %d in loadbuffer\n",
+			chan->load_state);
+		break;
+	}
+
+	return 0;
+}
+
+/* s3c2410_dma_call_op
+ *
+ * small routine to call the op routine with the given op if it has been
+ * registered
+*/
+
+static void
+s3c2410_dma_call_op(struct s3c2410_dma_chan *chan, enum s3c2410_chan_op op)
+{
+	if (chan->op_fn != NULL) {
+		(chan->op_fn)(chan, op);
+	}
+}
+
+/* s3c2410_dma_buffdone
+ *
+ * small wrapper to check if callback routine needs to be called, and
+ * if so, call it
+*/
+
+static inline void
+s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
+		     enum s3c2410_dma_buffresult result)
+{
+#if 0
+	pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
+		 chan->callback_fn, buf, buf->id, buf->size, result);
+#endif
+
+	if (chan->callback_fn != NULL) {
+		(chan->callback_fn)(chan, buf->id, buf->size, result);
+	}
+}
+
+/* s3c2410_dma_start
+ *
+ * start a dma channel going
+*/
+
+static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
+{
+	unsigned long tmp;
+	unsigned long flags;
+
+	pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
+
+	local_irq_save(flags);
+
+	if (chan->state == S3C2410_DMA_RUNNING) {
+		pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
+		local_irq_restore(flags);
+		return 0;
+	}
+
+	chan->state = S3C2410_DMA_RUNNING;
+
+	/* check whether there is anything to load, and if not, see
+	 * if we can find anything to load
+	 */
+
+	if (chan->load_state == S3C2410_DMALOAD_NONE) {
+		if (chan->next == NULL) {
+			printk(KERN_ERR "dma%d: channel has nothing loaded\n",
+			       chan->number);
+			chan->state = S3C2410_DMA_IDLE;
+			local_irq_restore(flags);
+			return -EINVAL;
+		}
+
+		s3c2410_dma_loadbuffer(chan, chan->next);
+	}
+
+	dbg_showchan(chan);
+
+	/* enable the channel */
+
+	if (!chan->irq_enabled) {
+		enable_irq(chan->irq);
+		chan->irq_enabled = 1;
+	}
+
+	/* start the channel going */
+
+	tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
+	tmp &= ~S3C2410_DMASKTRIG_STOP;
+	tmp |= S3C2410_DMASKTRIG_ON;
+	dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
+
+	pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);
+
+#if 0
+	/* the dma buffer loads should take care of clearing the AUTO
+	 * reloading feature */
+	tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
+	tmp &= ~S3C2410_DCON_NORELOAD;
+	dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
+#endif
+
+	s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
+
+	dbg_showchan(chan);
+
+	/* if we've only loaded one buffer onto the channel, then chec