forked from Minki/linux
usb: fixes for v3.17-rc3
A new set of fixes which have been pending for a while. All patches have been randconfig build-tested and boot tested where applicable. The most important fixes are MUSB on AM335x learned how to transfer ZLPs, and net2280 got a fix for reset IRQ handling. Signed-of-by: Felipe Balbi <balbi@ti.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUByUCAAoJEIaOsuA1yqRESVUQALJesmh+LwyWEQDplUAm4RlC rB9f9rw2WAiThwwMcMX4PH19uIjOeo3ip2hfsclZTvPyjshLICoRdjL3w8bsne+h bGlRQowcX3exnja8jIPDATb+j4tATL997nitRsCwhbuS3+xnSW3rpS5N5/yLnedP c0/VSf70oVNOxe28C3pHUy3694nDw84uMWT+hGhg6HRyHbjXFWaBsr4ggWCSU8IH oG+IPx6XfzYEBtuAcRCQPwfdOtbaI1htIBot9coONvBX75hQNfqEfpfRccN869Qo xjskMgJGAIkukJhmmZy8h3On2SrOrE5n61/SDD3IC8JxlrwSff6LZFf3pB5qSXTE nyxkJhl9Pf0QpKzSnJTGc+3DiKv882OwQziNx2aKzbMJ96QFib5kuBSvCcXubXMT EPmAYr3twGwVwuKOY2o30UYVZJ4X5WOnt9AgES0DFoxzqUjEG7QeMWJDTUoSaOJ8 kr6N7ko5cu3xrh27mv7ch31LwHiOA6MrQAXjfpnJRIvHac0wkq8Kf1DxAHUavgqL fs1ZsJtEMXZyok4PJsCF43nbl1tJ22SkTvZW/vN9wb9g3toGFeXMXncdK6jH63OB 4+aUVsWeP6fj33P5SHIDCethwi9o6tqdb5d0A4tlYMRNENKIFrRf6Cpsx7C8snck ntDsSsZpNFRpSlGYH8jE =vPu0 -----END PGP SIGNATURE----- Merge tag 'fixes-for-v3.17-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-linus Felipe writes: usb: fixes for v3.17-rc3 A new set of fixes which have been pending for a while. All patches have been randconfig build-tested and boot tested where applicable. The most important fixes are MUSB on AM335x learned how to transfer ZLPs, and net2280 got a fix for reset IRQ handling. Signed-of-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
commit
75dfea530e
@ -5,6 +5,7 @@ Required properties:
|
|||||||
* "fsl,imx23-usbphy" for imx23 and imx28
|
* "fsl,imx23-usbphy" for imx23 and imx28
|
||||||
* "fsl,imx6q-usbphy" for imx6dq and imx6dl
|
* "fsl,imx6q-usbphy" for imx6dq and imx6dl
|
||||||
* "fsl,imx6sl-usbphy" for imx6sl
|
* "fsl,imx6sl-usbphy" for imx6sl
|
||||||
|
* "fsl,imx6sx-usbphy" for imx6sx
|
||||||
"fsl,imx23-usbphy" is still a fallback for other strings
|
"fsl,imx23-usbphy" is still a fallback for other strings
|
||||||
- reg: Should contain registers location and length
|
- reg: Should contain registers location and length
|
||||||
- interrupts: Should contain phy interrupt
|
- interrupts: Should contain phy interrupt
|
||||||
|
@ -155,6 +155,12 @@ struct ffs_io_data {
|
|||||||
struct usb_request *req;
|
struct usb_request *req;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ffs_desc_helper {
|
||||||
|
struct ffs_data *ffs;
|
||||||
|
unsigned interfaces_count;
|
||||||
|
unsigned eps_count;
|
||||||
|
};
|
||||||
|
|
||||||
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
|
static int __must_check ffs_epfiles_create(struct ffs_data *ffs);
|
||||||
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
|
static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count);
|
||||||
|
|
||||||
@ -1830,7 +1836,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
|||||||
u8 *valuep, struct usb_descriptor_header *desc,
|
u8 *valuep, struct usb_descriptor_header *desc,
|
||||||
void *priv)
|
void *priv)
|
||||||
{
|
{
|
||||||
struct ffs_data *ffs = priv;
|
struct ffs_desc_helper *helper = priv;
|
||||||
|
struct usb_endpoint_descriptor *d;
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
@ -1844,8 +1851,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
|||||||
* encountered interface "n" then there are at least
|
* encountered interface "n" then there are at least
|
||||||
* "n+1" interfaces.
|
* "n+1" interfaces.
|
||||||
*/
|
*/
|
||||||
if (*valuep >= ffs->interfaces_count)
|
if (*valuep >= helper->interfaces_count)
|
||||||
ffs->interfaces_count = *valuep + 1;
|
helper->interfaces_count = *valuep + 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFS_STRING:
|
case FFS_STRING:
|
||||||
@ -1853,14 +1860,22 @@ static int __ffs_data_do_entity(enum ffs_entity_type type,
|
|||||||
* Strings are indexed from 1 (0 is magic ;) reserved
|
* Strings are indexed from 1 (0 is magic ;) reserved
|
||||||
* for languages list or some such)
|
* for languages list or some such)
|
||||||
*/
|
*/
|
||||||
if (*valuep > ffs->strings_count)
|
if (*valuep > helper->ffs->strings_count)
|
||||||
ffs->strings_count = *valuep;
|
helper->ffs->strings_count = *valuep;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FFS_ENDPOINT:
|
case FFS_ENDPOINT:
|
||||||
/* Endpoints are indexed from 1 as well. */
|
d = (void *)desc;
|
||||||
if ((*valuep & USB_ENDPOINT_NUMBER_MASK) > ffs->eps_count)
|
helper->eps_count++;
|
||||||
ffs->eps_count = (*valuep & USB_ENDPOINT_NUMBER_MASK);
|
if (helper->eps_count >= 15)
|
||||||
|
return -EINVAL;
|
||||||
|
/* Check if descriptors for any speed were already parsed */
|
||||||
|
if (!helper->ffs->eps_count && !helper->ffs->interfaces_count)
|
||||||
|
helper->ffs->eps_addrmap[helper->eps_count] =
|
||||||
|
d->bEndpointAddress;
|
||||||
|
else if (helper->ffs->eps_addrmap[helper->eps_count] !=
|
||||||
|
d->bEndpointAddress)
|
||||||
|
return -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2053,6 +2068,7 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
|||||||
char *data = _data, *raw_descs;
|
char *data = _data, *raw_descs;
|
||||||
unsigned os_descs_count = 0, counts[3], flags;
|
unsigned os_descs_count = 0, counts[3], flags;
|
||||||
int ret = -EINVAL, i;
|
int ret = -EINVAL, i;
|
||||||
|
struct ffs_desc_helper helper;
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
@ -2101,13 +2117,29 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
|
|||||||
|
|
||||||
/* Read descriptors */
|
/* Read descriptors */
|
||||||
raw_descs = data;
|
raw_descs = data;
|
||||||
|
helper.ffs = ffs;
|
||||||
for (i = 0; i < 3; ++i) {
|
for (i = 0; i < 3; ++i) {
|
||||||
if (!counts[i])
|
if (!counts[i])
|
||||||
continue;
|
continue;
|
||||||
|
helper.interfaces_count = 0;
|
||||||
|
helper.eps_count = 0;
|
||||||
ret = ffs_do_descs(counts[i], data, len,
|
ret = ffs_do_descs(counts[i], data, len,
|
||||||
__ffs_data_do_entity, ffs);
|
__ffs_data_do_entity, &helper);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
if (!ffs->eps_count && !ffs->interfaces_count) {
|
||||||
|
ffs->eps_count = helper.eps_count;
|
||||||
|
ffs->interfaces_count = helper.interfaces_count;
|
||||||
|
} else {
|
||||||
|
if (ffs->eps_count != helper.eps_count) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (ffs->interfaces_count != helper.interfaces_count) {
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
data += ret;
|
data += ret;
|
||||||
len -= ret;
|
len -= ret;
|
||||||
}
|
}
|
||||||
@ -2342,9 +2374,18 @@ static void ffs_event_add(struct ffs_data *ffs,
|
|||||||
spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
|
spin_unlock_irqrestore(&ffs->ev.waitq.lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Bind/unbind USB function hooks *******************************************/
|
/* Bind/unbind USB function hooks *******************************************/
|
||||||
|
|
||||||
|
static int ffs_ep_addr2idx(struct ffs_data *ffs, u8 endpoint_address)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 1; i < ARRAY_SIZE(ffs->eps_addrmap); ++i)
|
||||||
|
if (ffs->eps_addrmap[i] == endpoint_address)
|
||||||
|
return i;
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
|
||||||
static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
|
static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
|
||||||
struct usb_descriptor_header *desc,
|
struct usb_descriptor_header *desc,
|
||||||
void *priv)
|
void *priv)
|
||||||
@ -2378,7 +2419,10 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
|
|||||||
if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
|
if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
idx = (ds->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - 1;
|
idx = ffs_ep_addr2idx(func->ffs, ds->bEndpointAddress) - 1;
|
||||||
|
if (idx < 0)
|
||||||
|
return idx;
|
||||||
|
|
||||||
ffs_ep = func->eps + idx;
|
ffs_ep = func->eps + idx;
|
||||||
|
|
||||||
if (unlikely(ffs_ep->descs[ep_desc_id])) {
|
if (unlikely(ffs_ep->descs[ep_desc_id])) {
|
||||||
|
@ -224,6 +224,8 @@ struct ffs_data {
|
|||||||
void *ms_os_descs_ext_prop_name_avail;
|
void *ms_os_descs_ext_prop_name_avail;
|
||||||
void *ms_os_descs_ext_prop_data_avail;
|
void *ms_os_descs_ext_prop_data_avail;
|
||||||
|
|
||||||
|
u8 eps_addrmap[15];
|
||||||
|
|
||||||
unsigned short strings_count;
|
unsigned short strings_count;
|
||||||
unsigned short interfaces_count;
|
unsigned short interfaces_count;
|
||||||
unsigned short eps_count;
|
unsigned short eps_count;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifndef __FUSB300_UDC_H__
|
#ifndef __FUSB300_UDC_H__
|
||||||
#define __FUSB300_UDC_H_
|
#define __FUSB300_UDC_H__
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
|
|
||||||
|
@ -3320,7 +3320,7 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
|
|||||||
if (stat & tmp) {
|
if (stat & tmp) {
|
||||||
writel(tmp, &dev->regs->irqstat1);
|
writel(tmp, &dev->regs->irqstat1);
|
||||||
if ((((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) &&
|
if ((((stat & BIT(ROOT_PORT_RESET_INTERRUPT)) &&
|
||||||
(readl(&dev->usb->usbstat) & mask)) ||
|
((readl(&dev->usb->usbstat) & mask) == 0)) ||
|
||||||
((readl(&dev->usb->usbctl) &
|
((readl(&dev->usb->usbctl) &
|
||||||
BIT(VBUS_PIN)) == 0)) &&
|
BIT(VBUS_PIN)) == 0)) &&
|
||||||
(dev->gadget.speed != USB_SPEED_UNKNOWN)) {
|
(dev->gadget.speed != USB_SPEED_UNKNOWN)) {
|
||||||
|
@ -39,6 +39,7 @@ struct cppi41_dma_channel {
|
|||||||
u32 transferred;
|
u32 transferred;
|
||||||
u32 packet_sz;
|
u32 packet_sz;
|
||||||
struct list_head tx_check;
|
struct list_head tx_check;
|
||||||
|
int tx_zlp;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MUSB_DMA_NUM_CHANNELS 15
|
#define MUSB_DMA_NUM_CHANNELS 15
|
||||||
@ -122,6 +123,8 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
|
|||||||
{
|
{
|
||||||
struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
|
struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep;
|
||||||
struct musb *musb = hw_ep->musb;
|
struct musb *musb = hw_ep->musb;
|
||||||
|
void __iomem *epio = hw_ep->regs;
|
||||||
|
u16 csr;
|
||||||
|
|
||||||
if (!cppi41_channel->prog_len ||
|
if (!cppi41_channel->prog_len ||
|
||||||
(cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) {
|
(cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) {
|
||||||
@ -131,15 +134,24 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel)
|
|||||||
cppi41_channel->transferred;
|
cppi41_channel->transferred;
|
||||||
cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
|
cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
|
||||||
cppi41_channel->channel.rx_packet_done = true;
|
cppi41_channel->channel.rx_packet_done = true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* transmit ZLP using PIO mode for transfers which size is
|
||||||
|
* multiple of EP packet size.
|
||||||
|
*/
|
||||||
|
if (cppi41_channel->tx_zlp && (cppi41_channel->transferred %
|
||||||
|
cppi41_channel->packet_sz) == 0) {
|
||||||
|
musb_ep_select(musb->mregs, hw_ep->epnum);
|
||||||
|
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_TXPKTRDY;
|
||||||
|
musb_writew(epio, MUSB_TXCSR, csr);
|
||||||
|
}
|
||||||
musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
|
musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
|
||||||
} else {
|
} else {
|
||||||
/* next iteration, reload */
|
/* next iteration, reload */
|
||||||
struct dma_chan *dc = cppi41_channel->dc;
|
struct dma_chan *dc = cppi41_channel->dc;
|
||||||
struct dma_async_tx_descriptor *dma_desc;
|
struct dma_async_tx_descriptor *dma_desc;
|
||||||
enum dma_transfer_direction direction;
|
enum dma_transfer_direction direction;
|
||||||
u16 csr;
|
|
||||||
u32 remain_bytes;
|
u32 remain_bytes;
|
||||||
void __iomem *epio = cppi41_channel->hw_ep->regs;
|
|
||||||
|
|
||||||
cppi41_channel->buf_addr += cppi41_channel->packet_sz;
|
cppi41_channel->buf_addr += cppi41_channel->packet_sz;
|
||||||
|
|
||||||
@ -363,6 +375,7 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
|
|||||||
cppi41_channel->total_len = len;
|
cppi41_channel->total_len = len;
|
||||||
cppi41_channel->transferred = 0;
|
cppi41_channel->transferred = 0;
|
||||||
cppi41_channel->packet_sz = packet_sz;
|
cppi41_channel->packet_sz = packet_sz;
|
||||||
|
cppi41_channel->tx_zlp = (cppi41_channel->is_tx && mode) ? 1 : 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more
|
* Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2013 Freescale Semiconductor, Inc.
|
* Copyright 2012-2014 Freescale Semiconductor, Inc.
|
||||||
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
|
* Copyright (C) 2012 Marek Vasut <marex@denx.de>
|
||||||
* on behalf of DENX Software Engineering GmbH
|
* on behalf of DENX Software Engineering GmbH
|
||||||
*
|
*
|
||||||
@ -125,7 +125,13 @@ static const struct mxs_phy_data imx6sl_phy_data = {
|
|||||||
MXS_PHY_NEED_IP_FIX,
|
MXS_PHY_NEED_IP_FIX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct mxs_phy_data imx6sx_phy_data = {
|
||||||
|
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
|
||||||
|
MXS_PHY_NEED_IP_FIX,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct of_device_id mxs_phy_dt_ids[] = {
|
static const struct of_device_id mxs_phy_dt_ids[] = {
|
||||||
|
{ .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
|
||||||
{ .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
|
{ .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
|
||||||
{ .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
|
{ .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
|
||||||
{ .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
|
{ .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
|
||||||
|
@ -878,8 +878,8 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
tegra_phy->config = devm_kzalloc(&pdev->dev,
|
tegra_phy->config = devm_kzalloc(&pdev->dev, sizeof(*config),
|
||||||
sizeof(*tegra_phy->config), GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!tegra_phy->config) {
|
if (!tegra_phy->config) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"unable to allocate memory for USB UTMIP config\n");
|
"unable to allocate memory for USB UTMIP config\n");
|
||||||
|
@ -108,19 +108,45 @@ static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
|
|||||||
return list_first_entry(&pipe->list, struct usbhs_pkt, node);
|
return list_first_entry(&pipe->list, struct usbhs_pkt, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void usbhsf_fifo_clear(struct usbhs_pipe *pipe,
|
||||||
|
struct usbhs_fifo *fifo);
|
||||||
|
static void usbhsf_fifo_unselect(struct usbhs_pipe *pipe,
|
||||||
|
struct usbhs_fifo *fifo);
|
||||||
|
static struct dma_chan *usbhsf_dma_chan_get(struct usbhs_fifo *fifo,
|
||||||
|
struct usbhs_pkt *pkt);
|
||||||
|
#define usbhsf_dma_map(p) __usbhsf_dma_map_ctrl(p, 1)
|
||||||
|
#define usbhsf_dma_unmap(p) __usbhsf_dma_map_ctrl(p, 0)
|
||||||
|
static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map);
|
||||||
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
|
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
|
||||||
{
|
{
|
||||||
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
|
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
|
||||||
|
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/******************** spin lock ********************/
|
/******************** spin lock ********************/
|
||||||
usbhs_lock(priv, flags);
|
usbhs_lock(priv, flags);
|
||||||
|
|
||||||
|
usbhs_pipe_disable(pipe);
|
||||||
|
|
||||||
if (!pkt)
|
if (!pkt)
|
||||||
pkt = __usbhsf_pkt_get(pipe);
|
pkt = __usbhsf_pkt_get(pipe);
|
||||||
|
|
||||||
if (pkt)
|
if (pkt) {
|
||||||
|
struct dma_chan *chan = NULL;
|
||||||
|
|
||||||
|
if (fifo)
|
||||||
|
chan = usbhsf_dma_chan_get(fifo, pkt);
|
||||||
|
if (chan) {
|
||||||
|
dmaengine_terminate_all(chan);
|
||||||
|
usbhsf_fifo_clear(pipe, fifo);
|
||||||
|
usbhsf_dma_unmap(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
__usbhsf_pkt_del(pkt);
|
__usbhsf_pkt_del(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fifo)
|
||||||
|
usbhsf_fifo_unselect(pipe, fifo);
|
||||||
|
|
||||||
usbhs_unlock(priv, flags);
|
usbhs_unlock(priv, flags);
|
||||||
/******************** spin unlock ******************/
|
/******************** spin unlock ******************/
|
||||||
@ -544,6 +570,7 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
|
|||||||
usbhsf_send_terminator(pipe, fifo);
|
usbhsf_send_terminator(pipe, fifo);
|
||||||
|
|
||||||
usbhsf_tx_irq_ctrl(pipe, !*is_done);
|
usbhsf_tx_irq_ctrl(pipe, !*is_done);
|
||||||
|
usbhs_pipe_running(pipe, !*is_done);
|
||||||
usbhs_pipe_enable(pipe);
|
usbhs_pipe_enable(pipe);
|
||||||
|
|
||||||
dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n",
|
dev_dbg(dev, " send %d (%d/ %d/ %d/ %d)\n",
|
||||||
@ -570,12 +597,21 @@ usbhs_fifo_write_busy:
|
|||||||
* retry in interrupt
|
* retry in interrupt
|
||||||
*/
|
*/
|
||||||
usbhsf_tx_irq_ctrl(pipe, 1);
|
usbhsf_tx_irq_ctrl(pipe, 1);
|
||||||
|
usbhs_pipe_running(pipe, 1);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int usbhsf_pio_prepare_push(struct usbhs_pkt *pkt, int *is_done)
|
||||||
|
{
|
||||||
|
if (usbhs_pipe_is_running(pkt->pipe))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return usbhsf_pio_try_push(pkt, is_done);
|
||||||
|
}
|
||||||
|
|
||||||
struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = {
|
struct usbhs_pkt_handle usbhs_fifo_pio_push_handler = {
|
||||||
.prepare = usbhsf_pio_try_push,
|
.prepare = usbhsf_pio_prepare_push,
|
||||||
.try_run = usbhsf_pio_try_push,
|
.try_run = usbhsf_pio_try_push,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -589,6 +625,9 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
|
|||||||
if (usbhs_pipe_is_busy(pipe))
|
if (usbhs_pipe_is_busy(pipe))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (usbhs_pipe_is_running(pipe))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* pipe enable to prepare packet receive
|
* pipe enable to prepare packet receive
|
||||||
*/
|
*/
|
||||||
@ -597,6 +636,7 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
|
|||||||
|
|
||||||
usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length);
|
usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->length);
|
||||||
usbhs_pipe_enable(pipe);
|
usbhs_pipe_enable(pipe);
|
||||||
|
usbhs_pipe_running(pipe, 1);
|
||||||
usbhsf_rx_irq_ctrl(pipe, 1);
|
usbhsf_rx_irq_ctrl(pipe, 1);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -642,6 +682,7 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)
|
|||||||
(total_len < maxp)) { /* short packet */
|
(total_len < maxp)) { /* short packet */
|
||||||
*is_done = 1;
|
*is_done = 1;
|
||||||
usbhsf_rx_irq_ctrl(pipe, 0);
|
usbhsf_rx_irq_ctrl(pipe, 0);
|
||||||
|
usbhs_pipe_running(pipe, 0);
|
||||||
usbhs_pipe_disable(pipe); /* disable pipe first */
|
usbhs_pipe_disable(pipe); /* disable pipe first */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,8 +804,6 @@ static void __usbhsf_dma_ctrl(struct usbhs_pipe *pipe,
|
|||||||
usbhs_bset(priv, fifo->sel, DREQE, dreqe);
|
usbhs_bset(priv, fifo->sel, DREQE, dreqe);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define usbhsf_dma_map(p) __usbhsf_dma_map_ctrl(p, 1)
|
|
||||||
#define usbhsf_dma_unmap(p) __usbhsf_dma_map_ctrl(p, 0)
|
|
||||||
static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
|
||||||
{
|
{
|
||||||
struct usbhs_pipe *pipe = pkt->pipe;
|
struct usbhs_pipe *pipe = pkt->pipe;
|
||||||
@ -805,6 +844,7 @@ static void xfer_work(struct work_struct *work)
|
|||||||
dev_dbg(dev, " %s %d (%d/ %d)\n",
|
dev_dbg(dev, " %s %d (%d/ %d)\n",
|
||||||
fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero);
|
fifo->name, usbhs_pipe_number(pipe), pkt->length, pkt->zero);
|
||||||
|
|
||||||
|
usbhs_pipe_running(pipe, 1);
|
||||||
usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
|
usbhs_pipe_set_trans_count_if_bulk(pipe, pkt->trans);
|
||||||
usbhs_pipe_enable(pipe);
|
usbhs_pipe_enable(pipe);
|
||||||
usbhsf_dma_start(pipe, fifo);
|
usbhsf_dma_start(pipe, fifo);
|
||||||
@ -836,6 +876,10 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
|
|||||||
if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
|
if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */
|
||||||
goto usbhsf_pio_prepare_push;
|
goto usbhsf_pio_prepare_push;
|
||||||
|
|
||||||
|
/* return at this time if the pipe is running */
|
||||||
|
if (usbhs_pipe_is_running(pipe))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* get enable DMA fifo */
|
/* get enable DMA fifo */
|
||||||
fifo = usbhsf_get_dma_fifo(priv, pkt);
|
fifo = usbhsf_get_dma_fifo(priv, pkt);
|
||||||
if (!fifo)
|
if (!fifo)
|
||||||
@ -869,15 +913,29 @@ usbhsf_pio_prepare_push:
|
|||||||
static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done)
|
static int usbhsf_dma_push_done(struct usbhs_pkt *pkt, int *is_done)
|
||||||
{
|
{
|
||||||
struct usbhs_pipe *pipe = pkt->pipe;
|
struct usbhs_pipe *pipe = pkt->pipe;
|
||||||
|
int is_short = pkt->trans % usbhs_pipe_get_maxpacket(pipe);
|
||||||
|
|
||||||
pkt->actual = pkt->trans;
|
pkt->actual += pkt->trans;
|
||||||
|
|
||||||
*is_done = !pkt->zero; /* send zero packet ? */
|
if (pkt->actual < pkt->length)
|
||||||
|
*is_done = 0; /* there are remainder data */
|
||||||
|
else if (is_short)
|
||||||
|
*is_done = 1; /* short packet */
|
||||||
|
else
|
||||||
|
*is_done = !pkt->zero; /* send zero packet? */
|
||||||
|
|
||||||
|
usbhs_pipe_running(pipe, !*is_done);
|
||||||
|
|
||||||
usbhsf_dma_stop(pipe, pipe->fifo);
|
usbhsf_dma_stop(pipe, pipe->fifo);
|
||||||
usbhsf_dma_unmap(pkt);
|
usbhsf_dma_unmap(pkt);
|
||||||
usbhsf_fifo_unselect(pipe, pipe->fifo);
|
usbhsf_fifo_unselect(pipe, pipe->fifo);
|
||||||
|
|
||||||
|
if (!*is_done) {
|
||||||
|
/* change handler to PIO */
|
||||||
|
pkt->handler = &usbhs_fifo_pio_push_handler;
|
||||||
|
return pkt->handler->try_run(pkt, is_done);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,8 +1030,10 @@ static int usbhsf_dma_pop_done(struct usbhs_pkt *pkt, int *is_done)
|
|||||||
if ((pkt->actual == pkt->length) || /* receive all data */
|
if ((pkt->actual == pkt->length) || /* receive all data */
|
||||||
(pkt->trans < maxp)) { /* short packet */
|
(pkt->trans < maxp)) { /* short packet */
|
||||||
*is_done = 1;
|
*is_done = 1;
|
||||||
|
usbhs_pipe_running(pipe, 0);
|
||||||
} else {
|
} else {
|
||||||
/* re-enable */
|
/* re-enable */
|
||||||
|
usbhs_pipe_running(pipe, 0);
|
||||||
usbhsf_prepare_pop(pkt, is_done);
|
usbhsf_prepare_pop(pkt, is_done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +213,10 @@ static int usbhs_status_get_each_irq(struct usbhs_priv *priv,
|
|||||||
{
|
{
|
||||||
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
|
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
|
||||||
u16 intenb0, intenb1;
|
u16 intenb0, intenb1;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
/******************** spin lock ********************/
|
||||||
|
usbhs_lock(priv, flags);
|
||||||
state->intsts0 = usbhs_read(priv, INTSTS0);
|
state->intsts0 = usbhs_read(priv, INTSTS0);
|
||||||
state->intsts1 = usbhs_read(priv, INTSTS1);
|
state->intsts1 = usbhs_read(priv, INTSTS1);
|
||||||
|
|
||||||
@ -229,6 +232,8 @@ static int usbhs_status_get_each_irq(struct usbhs_priv *priv,
|
|||||||
state->bempsts &= mod->irq_bempsts;
|
state->bempsts &= mod->irq_bempsts;
|
||||||
state->brdysts &= mod->irq_brdysts;
|
state->brdysts &= mod->irq_brdysts;
|
||||||
}
|
}
|
||||||
|
usbhs_unlock(priv, flags);
|
||||||
|
/******************** spin unlock ******************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether the irq enable registers and the irq status are set
|
* Check whether the irq enable registers and the irq status are set
|
||||||
|
@ -578,6 +578,19 @@ int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe)
|
|||||||
return usbhsp_flags_has(pipe, IS_DIR_HOST);
|
return usbhsp_flags_has(pipe, IS_DIR_HOST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int usbhs_pipe_is_running(struct usbhs_pipe *pipe)
|
||||||
|
{
|
||||||
|
return usbhsp_flags_has(pipe, IS_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
|
void usbhs_pipe_running(struct usbhs_pipe *pipe, int running)
|
||||||
|
{
|
||||||
|
if (running)
|
||||||
|
usbhsp_flags_set(pipe, IS_RUNNING);
|
||||||
|
else
|
||||||
|
usbhsp_flags_clr(pipe, IS_RUNNING);
|
||||||
|
}
|
||||||
|
|
||||||
void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)
|
void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)
|
||||||
{
|
{
|
||||||
u16 mask = (SQCLR | SQSET);
|
u16 mask = (SQCLR | SQSET);
|
||||||
|
@ -36,6 +36,7 @@ struct usbhs_pipe {
|
|||||||
#define USBHS_PIPE_FLAGS_IS_USED (1 << 0)
|
#define USBHS_PIPE_FLAGS_IS_USED (1 << 0)
|
||||||
#define USBHS_PIPE_FLAGS_IS_DIR_IN (1 << 1)
|
#define USBHS_PIPE_FLAGS_IS_DIR_IN (1 << 1)
|
||||||
#define USBHS_PIPE_FLAGS_IS_DIR_HOST (1 << 2)
|
#define USBHS_PIPE_FLAGS_IS_DIR_HOST (1 << 2)
|
||||||
|
#define USBHS_PIPE_FLAGS_IS_RUNNING (1 << 3)
|
||||||
|
|
||||||
struct usbhs_pkt_handle *handler;
|
struct usbhs_pkt_handle *handler;
|
||||||
|
|
||||||
@ -80,6 +81,9 @@ int usbhs_pipe_probe(struct usbhs_priv *priv);
|
|||||||
void usbhs_pipe_remove(struct usbhs_priv *priv);
|
void usbhs_pipe_remove(struct usbhs_priv *priv);
|
||||||
int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe);
|
int usbhs_pipe_is_dir_in(struct usbhs_pipe *pipe);
|
||||||
int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe);
|
int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe);
|
||||||
|
int usbhs_pipe_is_running(struct usbhs_pipe *pipe);
|
||||||
|
void usbhs_pipe_running(struct usbhs_pipe *pipe, int running);
|
||||||
|
|
||||||
void usbhs_pipe_init(struct usbhs_priv *priv,
|
void usbhs_pipe_init(struct usbhs_priv *priv,
|
||||||
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map));
|
int (*dma_map_ctrl)(struct usbhs_pkt *pkt, int map));
|
||||||
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
|
int usbhs_pipe_get_maxpacket(struct usbhs_pipe *pipe);
|
||||||
|
Loading…
Reference in New Issue
Block a user