|
@@ -33,6 +33,7 @@
|
|
#ifndef _SMC91X_H_
|
|
#ifndef _SMC91X_H_
|
|
#define _SMC91X_H_
|
|
#define _SMC91X_H_
|
|
|
|
|
|
|
|
+#include <linux/dmaengine.h>
|
|
#include <linux/smc91x.h>
|
|
#include <linux/smc91x.h>
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -244,6 +245,7 @@ struct smc_local {
|
|
u_long physaddr;
|
|
u_long physaddr;
|
|
struct device *device;
|
|
struct device *device;
|
|
#endif
|
|
#endif
|
|
|
|
+ struct dma_chan *dma_chan;
|
|
void __iomem *base;
|
|
void __iomem *base;
|
|
void __iomem *datacs;
|
|
void __iomem *datacs;
|
|
|
|
|
|
@@ -265,21 +267,47 @@ struct smc_local {
|
|
* as RX which can overrun memory and lose packets.
|
|
* as RX which can overrun memory and lose packets.
|
|
*/
|
|
*/
|
|
#include <linux/dma-mapping.h>
|
|
#include <linux/dma-mapping.h>
|
|
-#include <mach/dma.h>
|
|
|
|
|
|
+#include <linux/dma/pxa-dma.h>
|
|
|
|
|
|
#ifdef SMC_insl
|
|
#ifdef SMC_insl
|
|
#undef SMC_insl
|
|
#undef SMC_insl
|
|
#define SMC_insl(a, r, p, l) \
|
|
#define SMC_insl(a, r, p, l) \
|
|
smc_pxa_dma_insl(a, lp, r, dev->dma, p, l)
|
|
smc_pxa_dma_insl(a, lp, r, dev->dma, p, l)
|
|
|
|
+static inline void
|
|
|
|
+smc_pxa_dma_inpump(struct smc_local *lp, u_char *buf, int len)
|
|
|
|
+{
|
|
|
|
+ dma_addr_t dmabuf;
|
|
|
|
+ struct dma_async_tx_descriptor *tx;
|
|
|
|
+ dma_cookie_t cookie;
|
|
|
|
+ enum dma_status status;
|
|
|
|
+ struct dma_tx_state state;
|
|
|
|
+
|
|
|
|
+ dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
|
|
|
|
+ tx = dmaengine_prep_slave_single(lp->dma_chan, dmabuf, len,
|
|
|
|
+ DMA_DEV_TO_MEM, 0);
|
|
|
|
+ if (tx) {
|
|
|
|
+ cookie = dmaengine_submit(tx);
|
|
|
|
+ dma_async_issue_pending(lp->dma_chan);
|
|
|
|
+ do {
|
|
|
|
+ status = dmaengine_tx_status(lp->dma_chan, cookie,
|
|
|
|
+ &state);
|
|
|
|
+ cpu_relax();
|
|
|
|
+ } while (status != DMA_COMPLETE && status != DMA_ERROR &&
|
|
|
|
+ state.residue);
|
|
|
|
+ dmaengine_terminate_all(lp->dma_chan);
|
|
|
|
+ }
|
|
|
|
+ dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
|
|
|
|
+}
|
|
|
|
+
|
|
static inline void
|
|
static inline void
|
|
smc_pxa_dma_insl(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
|
|
smc_pxa_dma_insl(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
|
|
u_char *buf, int len)
|
|
u_char *buf, int len)
|
|
{
|
|
{
|
|
- u_long physaddr = lp->physaddr;
|
|
|
|
- dma_addr_t dmabuf;
|
|
|
|
|
|
+ struct dma_slave_config config;
|
|
|
|
+ int ret;
|
|
|
|
|
|
/* fallback if no DMA available */
|
|
/* fallback if no DMA available */
|
|
- if (dma == (unsigned char)-1) {
|
|
|
|
|
|
+ if (!lp->dma_chan) {
|
|
readsl(ioaddr + reg, buf, len);
|
|
readsl(ioaddr + reg, buf, len);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -291,18 +319,22 @@ smc_pxa_dma_insl(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
|
|
len--;
|
|
len--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ memset(&config, 0, sizeof(config));
|
|
|
|
+ config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
|
|
|
+ config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
|
|
|
+ config.src_addr = lp->physaddr + reg;
|
|
|
|
+ config.dst_addr = lp->physaddr + reg;
|
|
|
|
+ config.src_maxburst = 32;
|
|
|
|
+ config.dst_maxburst = 32;
|
|
|
|
+ ret = dmaengine_slave_config(lp->dma_chan, &config);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_err(lp->device, "dma channel configuration failed: %d\n",
|
|
|
|
+ ret);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
len *= 4;
|
|
len *= 4;
|
|
- dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
|
|
|
|
- DCSR(dma) = DCSR_NODESC;
|
|
|
|
- DTADR(dma) = dmabuf;
|
|
|
|
- DSADR(dma) = physaddr + reg;
|
|
|
|
- DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
|
|
|
|
- DCMD_WIDTH4 | (DCMD_LENGTH & len));
|
|
|
|
- DCSR(dma) = DCSR_NODESC | DCSR_RUN;
|
|
|
|
- while (!(DCSR(dma) & DCSR_STOPSTATE))
|
|
|
|
- cpu_relax();
|
|
|
|
- DCSR(dma) = 0;
|
|
|
|
- dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
|
|
|
|
|
|
+ smc_pxa_dma_inpump(lp, buf, len);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
@@ -314,11 +346,11 @@ static inline void
|
|
smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
|
|
smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
|
|
u_char *buf, int len)
|
|
u_char *buf, int len)
|
|
{
|
|
{
|
|
- u_long physaddr = lp->physaddr;
|
|
|
|
- dma_addr_t dmabuf;
|
|
|
|
|
|
+ struct dma_slave_config config;
|
|
|
|
+ int ret;
|
|
|
|
|
|
/* fallback if no DMA available */
|
|
/* fallback if no DMA available */
|
|
- if (dma == (unsigned char)-1) {
|
|
|
|
|
|
+ if (!lp->dma_chan) {
|
|
readsw(ioaddr + reg, buf, len);
|
|
readsw(ioaddr + reg, buf, len);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
@@ -330,26 +362,25 @@ smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma,
|
|
len--;
|
|
len--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ memset(&config, 0, sizeof(config));
|
|
|
|
+ config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
|
|
|
+ config.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
|
|
|
|
+ config.src_addr = lp->physaddr + reg;
|
|
|
|
+ config.dst_addr = lp->physaddr + reg;
|
|
|
|
+ config.src_maxburst = 32;
|
|
|
|
+ config.dst_maxburst = 32;
|
|
|
|
+ ret = dmaengine_slave_config(lp->dma_chan, &config);
|
|
|
|
+ if (ret) {
|
|
|
|
+ dev_err(lp->device, "dma channel configuration failed: %d\n",
|
|
|
|
+ ret);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
len *= 2;
|
|
len *= 2;
|
|
- dmabuf = dma_map_single(lp->device, buf, len, DMA_FROM_DEVICE);
|
|
|
|
- DCSR(dma) = DCSR_NODESC;
|
|
|
|
- DTADR(dma) = dmabuf;
|
|
|
|
- DSADR(dma) = physaddr + reg;
|
|
|
|
- DCMD(dma) = (DCMD_INCTRGADDR | DCMD_BURST32 |
|
|
|
|
- DCMD_WIDTH2 | (DCMD_LENGTH & len));
|
|
|
|
- DCSR(dma) = DCSR_NODESC | DCSR_RUN;
|
|
|
|
- while (!(DCSR(dma) & DCSR_STOPSTATE))
|
|
|
|
- cpu_relax();
|
|
|
|
- DCSR(dma) = 0;
|
|
|
|
- dma_unmap_single(lp->device, dmabuf, len, DMA_FROM_DEVICE);
|
|
|
|
|
|
+ smc_pxa_dma_inpump(lp, buf, len);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-static void
|
|
|
|
-smc_pxa_dma_irq(int dma, void *dummy)
|
|
|
|
-{
|
|
|
|
- DCSR(dma) = 0;
|
|
|
|
-}
|
|
|
|
#endif /* CONFIG_ARCH_PXA */
|
|
#endif /* CONFIG_ARCH_PXA */
|
|
|
|
|
|
|
|
|