Commit 4cadc711 authored by Peter Ujfalusi's avatar Peter Ujfalusi Committed by Greg Kroah-Hartman

usb: musb: tusb6010_omap: Allocate DMA channels upfront

Instead of requesting the DMA channel in tusb_omap_dma_allocate() do it
when the controller is created and in runtime work from the DMA channel
pool.

This change is needed for the DMAengine conversion of the driver since the
tusb_omap_dma_allocate() is called in interrupt context which might lead
to lock within the DMAengine API when requesting channel.
Signed-off-by: default avatarPeter Ujfalusi <peter.ujfalusi@ti.com>
Tested-by: default avatarTony Lindgren <tony@atomide.com>
Signed-off-by: default avatarBin Liu <b-liu@ti.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 1df9d9ec
...@@ -45,7 +45,7 @@ struct tusb_omap_dma_ch { ...@@ -45,7 +45,7 @@ struct tusb_omap_dma_ch {
u8 tx; u8 tx;
struct musb_hw_ep *hw_ep; struct musb_hw_ep *hw_ep;
struct tusb_dma_data dma_data; struct tusb_dma_data *dma_data;
struct tusb_omap_dma *tusb_dma; struct tusb_omap_dma *tusb_dma;
...@@ -62,7 +62,7 @@ struct tusb_omap_dma { ...@@ -62,7 +62,7 @@ struct tusb_omap_dma {
struct dma_controller controller; struct dma_controller controller;
void __iomem *tbase; void __iomem *tbase;
struct tusb_dma_data dma_data; struct tusb_dma_data dma_pool[MAX_DMAREQ];
unsigned multichannel:1; unsigned multichannel:1;
}; };
...@@ -120,10 +120,7 @@ static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data) ...@@ -120,10 +120,7 @@ static void tusb_omap_dma_cb(int lch, u16 ch_status, void *data)
spin_lock_irqsave(&musb->lock, flags); spin_lock_irqsave(&musb->lock, flags);
if (tusb_dma->multichannel) ch = chdat->dma_data->ch;
ch = chdat->dma_data.ch;
else
ch = tusb_dma->dma_data.ch;
if (ch_status != OMAP_DMA_BLOCK_IRQ) if (ch_status != OMAP_DMA_BLOCK_IRQ)
printk(KERN_ERR "TUSB DMA error status: %i\n", ch_status); printk(KERN_ERR "TUSB DMA error status: %i\n", ch_status);
...@@ -248,7 +245,8 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz, ...@@ -248,7 +245,8 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
dma_remaining = TUSB_EP_CONFIG_XFR_SIZE(dma_remaining); dma_remaining = TUSB_EP_CONFIG_XFR_SIZE(dma_remaining);
if (dma_remaining) { if (dma_remaining) {
dev_dbg(musb->controller, "Busy %s dma ch%i, not using: %08x\n", dev_dbg(musb->controller, "Busy %s dma ch%i, not using: %08x\n",
chdat->tx ? "tx" : "rx", chdat->dma_data.ch, chdat->tx ? "tx" : "rx",
chdat->dma_data ? chdat->dma_data->ch : -1,
dma_remaining); dma_remaining);
return false; return false;
} }
...@@ -260,11 +258,8 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz, ...@@ -260,11 +258,8 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
else else
chdat->transfer_packet_sz = packet_sz; chdat->transfer_packet_sz = packet_sz;
if (tusb_dma->multichannel) { dma_data = chdat->dma_data;
dma_data = &chdat->dma_data; if (!tusb_dma->multichannel) {
} else {
dma_data = &tusb_dma->dma_data;
if (tusb_omap_use_shared_dmareq(chdat) != 0) { if (tusb_omap_use_shared_dmareq(chdat) != 0) {
dev_dbg(musb->controller, "could not get dma for ep%i\n", chdat->epnum); dev_dbg(musb->controller, "could not get dma for ep%i\n", chdat->epnum);
return false; return false;
...@@ -276,10 +271,10 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz, ...@@ -276,10 +271,10 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
WARN_ON(1); WARN_ON(1);
return false; return false;
} }
omap_set_dma_callback(dma_data->ch, tusb_omap_dma_cb, channel);
} }
omap_set_dma_callback(dma_data->ch, tusb_omap_dma_cb, channel);
chdat->packet_sz = packet_sz; chdat->packet_sz = packet_sz;
chdat->len = len; chdat->len = len;
channel->actual_len = 0; channel->actual_len = 0;
...@@ -410,19 +405,9 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz, ...@@ -410,19 +405,9 @@ static int tusb_omap_dma_program(struct dma_channel *channel, u16 packet_sz,
static int tusb_omap_dma_abort(struct dma_channel *channel) static int tusb_omap_dma_abort(struct dma_channel *channel)
{ {
struct tusb_omap_dma_ch *chdat = to_chdat(channel); struct tusb_omap_dma_ch *chdat = to_chdat(channel);
struct tusb_omap_dma *tusb_dma = chdat->tusb_dma;
struct tusb_dma_data *dma_data = &tusb_dma->dma_data;
if (!tusb_dma->multichannel) { if (chdat->dma_data)
if (dma_data->ch >= 0) { omap_stop_dma(chdat->dma_data->ch);
omap_stop_dma(dma_data->ch);
omap_free_dma(dma_data->ch);
dma_data->ch = -1;
}
dma_data->dmareq = -1;
dma_data->sync_dev = -1;
}
channel->status = MUSB_DMA_STATUS_FREE; channel->status = MUSB_DMA_STATUS_FREE;
...@@ -434,15 +419,6 @@ static inline int tusb_omap_dma_allocate_dmareq(struct tusb_omap_dma_ch *chdat) ...@@ -434,15 +419,6 @@ static inline int tusb_omap_dma_allocate_dmareq(struct tusb_omap_dma_ch *chdat)
u32 reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP); u32 reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
int i, dmareq_nr = -1; int i, dmareq_nr = -1;
const int sync_dev[6] = {
OMAP24XX_DMA_EXT_DMAREQ0,
OMAP24XX_DMA_EXT_DMAREQ1,
OMAP242X_DMA_EXT_DMAREQ2,
OMAP242X_DMA_EXT_DMAREQ3,
OMAP242X_DMA_EXT_DMAREQ4,
OMAP242X_DMA_EXT_DMAREQ5,
};
for (i = 0; i < MAX_DMAREQ; i++) { for (i = 0; i < MAX_DMAREQ; i++) {
int cur = (reg & (0xf << (i * 5))) >> (i * 5); int cur = (reg & (0xf << (i * 5))) >> (i * 5);
if (cur == 0) { if (cur == 0) {
...@@ -459,8 +435,7 @@ static inline int tusb_omap_dma_allocate_dmareq(struct tusb_omap_dma_ch *chdat) ...@@ -459,8 +435,7 @@ static inline int tusb_omap_dma_allocate_dmareq(struct tusb_omap_dma_ch *chdat)
reg |= ((1 << 4) << (dmareq_nr * 5)); reg |= ((1 << 4) << (dmareq_nr * 5));
musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg); musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg);
chdat->dma_data.dmareq = dmareq_nr; chdat->dma_data = &chdat->tusb_dma->dma_pool[dmareq_nr];
chdat->dma_data.sync_dev = sync_dev[chdat->dma_data.dmareq];
return 0; return 0;
} }
...@@ -469,15 +444,14 @@ static inline void tusb_omap_dma_free_dmareq(struct tusb_omap_dma_ch *chdat) ...@@ -469,15 +444,14 @@ static inline void tusb_omap_dma_free_dmareq(struct tusb_omap_dma_ch *chdat)
{ {
u32 reg; u32 reg;
if (!chdat || chdat->dma_data.dmareq < 0) if (!chdat || !chdat->dma_data || chdat->dma_data->dmareq < 0)
return; return;
reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP); reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP);
reg &= ~(0x1f << (chdat->dma_data.dmareq * 5)); reg &= ~(0x1f << (chdat->dma_data->dmareq * 5));
musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg); musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg);
chdat->dma_data.dmareq = -1; chdat->dma_data = NULL;
chdat->dma_data.sync_dev = -1;
} }
static struct dma_channel *dma_channel_pool[MAX_DMAREQ]; static struct dma_channel *dma_channel_pool[MAX_DMAREQ];
...@@ -488,8 +462,6 @@ tusb_omap_dma_allocate(struct dma_controller *c, ...@@ -488,8 +462,6 @@ tusb_omap_dma_allocate(struct dma_controller *c,
u8 tx) u8 tx)
{ {
int ret, i; int ret, i;
const char *dev_name;
void *cb_data;
struct tusb_omap_dma *tusb_dma; struct tusb_omap_dma *tusb_dma;
struct musb *musb; struct musb *musb;
void __iomem *tbase; void __iomem *tbase;
...@@ -543,46 +515,22 @@ tusb_omap_dma_allocate(struct dma_controller *c, ...@@ -543,46 +515,22 @@ tusb_omap_dma_allocate(struct dma_controller *c,
channel->desired_mode = 0; channel->desired_mode = 0;
channel->actual_len = 0; channel->actual_len = 0;
if (tusb_dma->multichannel) { if (!chdat->dma_data) {
dma_data = &chdat->dma_data; if (tusb_dma->multichannel) {
ret = tusb_omap_dma_allocate_dmareq(chdat); ret = tusb_omap_dma_allocate_dmareq(chdat);
if (ret != 0) if (ret != 0)
goto free_dmareq; goto free_dmareq;
} else {
if (chdat->tx) chdat->dma_data = &tusb_dma->dma_pool[0];
dev_name = "TUSB transmit"; }
else
dev_name = "TUSB receive";
cb_data = channel;
} else if (tusb_dma->dma_data.ch == -1) {
dma_data = &tusb_dma->dma_data;
dma_data->dmareq = 0;
dma_data->sync_dev = OMAP24XX_DMA_EXT_DMAREQ0;
dev_name = "TUSB shared";
/* Callback data gets set later in the shared dmareq case */
cb_data = NULL;
chdat->dma_data.dmareq = -1;
chdat->dma_data.ch = -1;
chdat->dma_data.sync_dev = -1;
} }
if (dma_data) { dma_data = chdat->dma_data;
ret = omap_request_dma(dma_data->sync_dev, dev_name,
tusb_omap_dma_cb, cb_data,
&dma_data->ch);
if (ret != 0)
goto free_dmareq;
} else {
/* Already allocated shared, single DMA channel. */
dma_data = &tusb_dma->dma_data;
}
dev_dbg(musb->controller, "ep%i %s dma: %s dma%i dmareq%i sync%i\n", dev_dbg(musb->controller, "ep%i %s dma: %s dma%i dmareq%i sync%i\n",
chdat->epnum, chdat->epnum,
chdat->tx ? "tx" : "rx", chdat->tx ? "tx" : "rx",
chdat->dma_data.ch >= 0 ? "dedicated" : "shared", tusb_dma->multichannel ? "shared" : "dedicated",
dma_data->ch, dma_data->dmareq, dma_data->sync_dev); dma_data->ch, dma_data->dmareq, dma_data->sync_dev);
return channel; return channel;
...@@ -604,7 +552,7 @@ static void tusb_omap_dma_release(struct dma_channel *channel) ...@@ -604,7 +552,7 @@ static void tusb_omap_dma_release(struct dma_channel *channel)
u32 reg; u32 reg;
dev_dbg(musb->controller, "ep%i ch%i\n", chdat->epnum, dev_dbg(musb->controller, "ep%i ch%i\n", chdat->epnum,
chdat->dma_data.ch); chdat->dma_data->ch);
reg = musb_readl(tbase, TUSB_DMA_INT_MASK); reg = musb_readl(tbase, TUSB_DMA_INT_MASK);
if (chdat->tx) if (chdat->tx)
...@@ -622,14 +570,8 @@ static void tusb_omap_dma_release(struct dma_channel *channel) ...@@ -622,14 +570,8 @@ static void tusb_omap_dma_release(struct dma_channel *channel)
channel->status = MUSB_DMA_STATUS_UNKNOWN; channel->status = MUSB_DMA_STATUS_UNKNOWN;
if (chdat->dma_data.ch >= 0) { omap_stop_dma(chdat->dma_data->ch);
omap_stop_dma(chdat->dma_data.ch); tusb_omap_dma_free_dmareq(chdat);
omap_free_dma(chdat->dma_data.ch);
chdat->dma_data.ch = -1;
}
if (chdat->dma_data.dmareq >= 0)
tusb_omap_dma_free_dmareq(chdat);
channel = NULL; channel = NULL;
} }
...@@ -646,15 +588,73 @@ void tusb_dma_controller_destroy(struct dma_controller *c) ...@@ -646,15 +588,73 @@ void tusb_dma_controller_destroy(struct dma_controller *c)
kfree(ch->private_data); kfree(ch->private_data);
kfree(ch); kfree(ch);
} }
}
if (tusb_dma && !tusb_dma->multichannel && tusb_dma->dma_data.ch >= 0) /* Free up the DMA channels */
omap_free_dma(tusb_dma->dma_data.ch); if (tusb_dma && tusb_dma->dma_pool[i].ch >= 0)
omap_free_dma(tusb_dma->dma_pool[i].ch);
}
kfree(tusb_dma); kfree(tusb_dma);
} }
EXPORT_SYMBOL_GPL(tusb_dma_controller_destroy); EXPORT_SYMBOL_GPL(tusb_dma_controller_destroy);
static int tusb_omap_allocate_dma_pool(struct tusb_omap_dma *tusb_dma)
{
int i;
int ret = 0;
const int sync_dev[6] = {
OMAP24XX_DMA_EXT_DMAREQ0,
OMAP24XX_DMA_EXT_DMAREQ1,
OMAP242X_DMA_EXT_DMAREQ2,
OMAP242X_DMA_EXT_DMAREQ3,
OMAP242X_DMA_EXT_DMAREQ4,
OMAP242X_DMA_EXT_DMAREQ5,
};
for (i = 0; i < MAX_DMAREQ; i++) {
struct tusb_dma_data *dma_data = &tusb_dma->dma_pool[i];
/*
* Request DMA channels:
* - one channel in case of non multichannel mode
* - MAX_DMAREQ number of channels in multichannel mode
*/
if (i == 0 || tusb_dma->multichannel) {
char ch_name[8];
sprintf(ch_name, "dmareq%d", i);
dma_data->sync_dev = sync_dev[i];
dma_data->ch = -1;
/* callback data is ngoing to be set later */
ret = omap_request_dma(dma_data->sync_dev, ch_name,
tusb_omap_dma_cb, NULL, &dma_data->ch);
if (ret != 0) {
dev_err(tusb_dma->controller.musb->controller,
"Failed to request %s\n", ch_name);
goto dma_error;
}
dma_data->dmareq = i;
} else {
dma_data->dmareq = -1;
dma_data->sync_dev = -1;
dma_data->ch = -1;
}
}
return 0;
dma_error:
for (; i >= 0; i--) {
struct tusb_dma_data *dma_data = &tusb_dma->dma_pool[i];
if (dma_data->ch >= 0)
omap_free_dma(dma_data->ch);
}
return ret;
}
struct dma_controller * struct dma_controller *
tusb_dma_controller_create(struct musb *musb, void __iomem *base) tusb_dma_controller_create(struct musb *musb, void __iomem *base)
{ {
...@@ -679,10 +679,6 @@ tusb_dma_controller_create(struct musb *musb, void __iomem *base) ...@@ -679,10 +679,6 @@ tusb_dma_controller_create(struct musb *musb, void __iomem *base)
tusb_dma->controller.musb = musb; tusb_dma->controller.musb = musb;
tusb_dma->tbase = musb->ctrl_base; tusb_dma->tbase = musb->ctrl_base;
tusb_dma->dma_data.ch = -1;
tusb_dma->dma_data.dmareq = -1;
tusb_dma->dma_data.sync_dev = -1;
tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate; tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;
tusb_dma->controller.channel_release = tusb_omap_dma_release; tusb_dma->controller.channel_release = tusb_omap_dma_release;
tusb_dma->controller.channel_program = tusb_omap_dma_program; tusb_dma->controller.channel_program = tusb_omap_dma_program;
...@@ -709,6 +705,9 @@ tusb_dma_controller_create(struct musb *musb, void __iomem *base) ...@@ -709,6 +705,9 @@ tusb_dma_controller_create(struct musb *musb, void __iomem *base)
ch->private_data = chdat; ch->private_data = chdat;
} }
if (tusb_omap_allocate_dma_pool(tusb_dma))
goto cleanup;
return &tusb_dma->controller; return &tusb_dma->controller;
cleanup: cleanup:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment