diff options
author | Greg Kroah-Hartman <gregkh@suse.de> | 2011-09-18 01:42:59 -0700 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-09-18 01:45:29 -0700 |
commit | 073b85469308b41468149f4aa7144c1e1bf4f0d7 (patch) | |
tree | b1ac00c1ccef8ddce2cf167e0a334e0e58eb97fc /drivers/usb | |
parent | b5dd18d8747010e3f3eb1cc76a49f94291938559 (diff) | |
parent | 0ae52d5458ddb14d5da63054f1d8269a13fe9054 (diff) |
Merge branch 'for-next' of git://gitorious.org/usb/usb into usb-next
* 'for-next' of git://gitorious.org/usb/usb: (47 commits)
usb: musb: Enable DMA mode1 RX for transfers without short packets
usb: musb: fix build breakage
usb: gadget: audio: queue wLength-sized requests
usb: gadget: audio: actually support both speeds
usb: gadget: storage: make FSG_NUM_BUFFERS variable size
USB: gadget: storage: remove alignment assumption
usb: gadget: storage: adapt logic block size to bound block devices
usb: dwc3: gadget: improve debug on link state change
usb: dwc3: omap: set idle and standby modes
usb: dwc3: ep0: introduce ep0_expect_in flag
usb: dwc3: ep0: giveback requests on stall_and_restart
usb: dwc3: gadget: drop the useless dma_sync_single* calls
usb: dwc3: gadget: fix GCTL programming
usb: dwc3: define ScaleDown macro helper
usb: dwc3: Fix definition of DWC3_GCTL_U2RSTECN
usb: dwc3: gadget: do not map/unmap ZLP transfers
usb: dwc3: omap: fix IRQ handling
usb: dwc3: omap: change IRQ name to dwc3-omap
usb: dwc3: add module.h to dwc3-omap.c and core.c
usb: dwc3: omap: distinguish between SW and HW modes
...
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/dwc3/core.c | 20 | ||||
-rw-r--r-- | drivers/usb/dwc3/core.h | 58 | ||||
-rw-r--r-- | drivers/usb/dwc3/debugfs.c | 92 | ||||
-rw-r--r-- | drivers/usb/dwc3/dwc3-omap.c | 155 | ||||
-rw-r--r-- | drivers/usb/dwc3/ep0.c | 412 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 141 | ||||
-rw-r--r-- | drivers/usb/gadget/Kconfig | 16 | ||||
-rw-r--r-- | drivers/usb/gadget/f_audio.c | 15 | ||||
-rw-r--r-- | drivers/usb/gadget/f_mass_storage.c | 153 | ||||
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 142 | ||||
-rw-r--r-- | drivers/usb/gadget/storage_common.c | 56 | ||||
-rw-r--r-- | drivers/usb/musb/musb_gadget.c | 69 |
12 files changed, 688 insertions, 641 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 443e4fb9b8f..64ba0979a34 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -37,6 +37,7 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/spinlock.h> @@ -241,6 +242,15 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) u32 reg; int ret; + reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); + /* This should read as U3 followed by revision number */ + if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) { + dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); + ret = -ENODEV; + goto err0; + } + dwc->revision = reg & DWC3_GSNPSREV_MASK; + dwc3_core_soft_reset(dwc); /* issue device SoftReset too */ @@ -260,16 +270,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) cpu_relax(); } while (true); - reg = dwc3_readl(dwc->regs, DWC3_GSNPSID); - /* This should read as U3 followed by revision number */ - if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) { - dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); - ret = -ENODEV; - goto err0; - } - - dwc->revision = reg & DWC3_GSNPSREV_MASK; - ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM, DWC3_EVENT_BUFFERS_SIZE); if (ret) { diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 83b2960cccd..07d20186e46 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -147,7 +147,7 @@ /* Global Configuration Register */ #define DWC3_GCTL_PWRDNSCALE(n) (n << 19) -#define DWC3_GCTL_U2RSTECN 16 +#define DWC3_GCTL_U2RSTECN (1 << 16) #define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6) #define DWC3_GCTL_CLK_BUS (0) #define DWC3_GCTL_CLK_PIPE (1) @@ -160,6 +160,7 @@ #define DWC3_GCTL_PRTCAP_OTG 3 #define DWC3_GCTL_CORESOFTRESET (1 << 11) +#define DWC3_GCTL_SCALEDOWN(n) (n << 4) #define DWC3_GCTL_DISSCRAMBLE (1 << 3) /* Global USB2 PHY Configuration Register */ @@ -348,7 +349,9 @@ struct dwc3_ep { #define DWC3_EP_WEDGE (1 << 2) #define DWC3_EP_BUSY (1 << 4) #define DWC3_EP_PENDING_REQUEST (1 << 5) -#define DWC3_EP_WILL_SHUTDOWN (1 << 6) + + /* This last one is specific to EP0 */ +#define DWC3_EP0_DIR_IN (1 << 31) unsigned current_trb; @@ -368,18 +371,19 @@ enum dwc3_phy { DWC3_PHY_USB2, }; +enum dwc3_ep0_next { + DWC3_EP0_UNKNOWN = 0, + DWC3_EP0_COMPLETE, + DWC3_EP0_NRDY_SETUP, + DWC3_EP0_NRDY_DATA, + DWC3_EP0_NRDY_STATUS, +}; + enum dwc3_ep0_state { EP0_UNCONNECTED = 0, - EP0_IDLE, - EP0_IN_DATA_PHASE, - EP0_OUT_DATA_PHASE, - EP0_IN_WAIT_GADGET, - EP0_OUT_WAIT_GADGET, - EP0_IN_WAIT_NRDY, - EP0_OUT_WAIT_NRDY, - EP0_IN_STATUS_PHASE, - EP0_OUT_STATUS_PHASE, - EP0_STALL, + EP0_SETUP_PHASE, + EP0_DATA_PHASE, + EP0_STATUS_PHASE, }; enum dwc3_link_state { @@ -503,13 +507,15 @@ static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat) /** * struct dwc3 - representation of our controller - * ctrl_req: usb control request which is used for ep0 - * ep0_trb: trb which is used for the ctrl_req - * setup_buf: used while precessing STD USB requests - * ctrl_req_addr: dma address of ctrl_req - * ep0_trb: dma address of ep0_trb - * ep0_usb_req: dummy req used while handling STD USB requests - * setup_buf_addr: dma address of setup_buf + * @ctrl_req: usb control request which is used for ep0 + * @ep0_trb: trb which is used for the ctrl_req + * @ep0_bounce: bounce buffer for ep0 + * @setup_buf: used while precessing STD USB requests + * @ctrl_req_addr: dma address of ctrl_req + * @ep0_trb: dma address of ep0_trb + * @ep0_usb_req: dummy req used while handling STD USB requests + * @setup_buf_addr: dma address of setup_buf + * @ep0_bounce_addr: dma address of ep0_bounce * @lock: for synchronizing * @dev: pointer to our struct device * @event_buffer_list: a list of event buffers @@ -522,6 +528,9 @@ static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat) * @is_selfpowered: true when we are selfpowered * @three_stage_setup: set if we perform a three phase setup * @ep0_status_pending: ep0 status response without a req is pending + * @ep0_bounced: true when we used bounce buffer + * @ep0_expect_in: true when we expect a DATA IN transfer + * @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state * @speed: device speed (super, high, full, low) @@ -531,10 +540,12 @@ static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat) struct dwc3 { struct usb_ctrlrequest *ctrl_req; struct dwc3_trb_hw *ep0_trb; + void *ep0_bounce; u8 *setup_buf; dma_addr_t ctrl_req_addr; dma_addr_t ep0_trb_addr; dma_addr_t setup_buf_addr; + dma_addr_t ep0_bounce_addr; struct usb_request ep0_usb_req; /* device lock */ spinlock_t lock; @@ -564,7 +575,10 @@ struct dwc3 { unsigned is_selfpowered:1; unsigned three_stage_setup:1; unsigned ep0_status_pending:1; + unsigned ep0_bounced:1; + unsigned ep0_expect_in:1; + enum dwc3_ep0_next ep0_next_event; enum dwc3_ep0_state ep0state; enum dwc3_link_state link_state; enum dwc3_device_state dev_state; @@ -634,6 +648,12 @@ struct dwc3_event_depevt { #define DEPEVT_STATUS_SHORT (1 << 1) #define DEPEVT_STATUS_IOC (1 << 2) #define DEPEVT_STATUS_LST (1 << 3) + +/* Control-only Status */ +#define DEPEVT_STATUS_CONTROL_SETUP 0 +#define DEPEVT_STATUS_CONTROL_DATA 1 +#define DEPEVT_STATUS_CONTROL_STATUS 2 + u32 parameters:16; } __packed; diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 432df539372..20d329f2340 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -406,91 +406,6 @@ static const struct file_operations dwc3_regdump_fops = { .release = single_release, }; - -static int dwc3_send_testmode_cmd(struct dwc3 *dwc, int mode) -{ - u32 timeout = 250; - - dwc3_writel(dwc->regs, DWC3_DGCMDPAR, mode); - dwc3_writel(dwc->regs, DWC3_DGCMD, DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK | - DWC3_DEPCMD_CMDACT); - do { - u32 reg; - - reg = dwc3_readl(dwc->regs, DWC3_DGCMD); - if (!(reg & DWC3_DEPCMD_CMDACT)) - return 0; - timeout--; - if (!timeout) - return -ETIMEDOUT; - mdelay(1); - } while (1); -} - -static struct dwc3_trb_hw trb_0 __aligned(16); -static struct dwc3_trb_hw trb_1 __aligned(16); - -#define BUF_SIZE 4096 -static int dwc3_testmode_open(struct inode *inode, struct file *file) -{ - struct dwc3 *dwc = inode->i_private; - struct dwc3_gadget_ep_cmd_params par0; - struct dwc3_gadget_ep_cmd_params par1; - struct dwc3_trb trb; - int ret; - u8 *buf0; - u8 *buf1; - - buf0 = kmalloc(BUF_SIZE, GFP_KERNEL); - if (!buf0) - return -ENOMEM; - buf1 = kmalloc(BUF_SIZE, GFP_KERNEL); - if (!buf1) - return -ENOMEM; - - memset(buf0, 0xaa, BUF_SIZE); - memset(buf1, 0x33, BUF_SIZE); - - memset(&trb, 0, sizeof(trb)); - memset(&par0, 0, sizeof(par0)); - memset(&par1, 0, sizeof(par1)); - - trb.lst = 1; - trb.trbctl = DWC3_TRBCTL_NORMAL; - trb.length = BUF_SIZE; - trb.hwo = 1; - - trb.bplh = virt_to_phys(buf0); - dwc3_trb_to_hw(&trb, &trb_0); - - trb.bplh = virt_to_phys(buf1); - dwc3_trb_to_hw(&trb, &trb_1); - - par0.param0.depstrtxfer.transfer_desc_addr_high = - upper_32_bits(virt_to_phys(&trb_0)); - par0.param1.depstrtxfer.transfer_desc_addr_low = - lower_32_bits(virt_to_phys(&trb_0)); - - par1.param0.depstrtxfer.transfer_desc_addr_high = - upper_32_bits(virt_to_phys(&trb_1)); - par1.param1.depstrtxfer.transfer_desc_addr_low = - lower_32_bits(virt_to_phys(&trb_1)); - - dwc3_send_testmode_cmd(dwc, 1); - - ret = dwc3_send_gadget_ep_cmd(dwc, 0, DWC3_DEPCMD_STARTTRANSFER, &par0); - ret = dwc3_send_gadget_ep_cmd(dwc, 1, DWC3_DEPCMD_STARTTRANSFER, &par1); - - dwc3_send_testmode_cmd(dwc, 0); - return -EBUSY; -} - -static const struct file_operations dwc3_testmode_fops = { - .open = dwc3_testmode_open, - .read = seq_read, - .release = single_release, -}; - int __devinit dwc3_debugfs_init(struct dwc3 *dwc) { struct dentry *root; @@ -511,13 +426,6 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc) ret = PTR_ERR(file); goto err1; } - file = debugfs_create_file("testmode", S_IRUGO, root, dwc, - &dwc3_testmode_fops); - if (IS_ERR(file)) { - ret = PTR_ERR(file); - goto err1; - } - return 0; err1: diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 08fffe6d1a9..72cc92b3da0 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -37,11 +37,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/spinlock.h> #include <linux/platform_device.h> +#include <linux/platform_data/dwc3-omap.h> #include <linux/dma-mapping.h> #include <linux/ioport.h> #include <linux/io.h> @@ -74,8 +76,23 @@ /* SYSCONFIG REGISTER */ #define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16) #define USBOTGSS_SYSCONFIG_STANDBYMODE(x) ((x) << 4) + +#define USBOTGSS_STANDBYMODE_FORCE_STANDBY 0 +#define USBOTGSS_STANDBYMODE_NO_STANDBY 1 +#define USBOTGSS_STANDBYMODE_SMART_STANDBY 2 +#define USBOTGSS_STANDBYMODE_SMART_WAKEUP 3 + +#define USBOTGSS_STANDBYMODE_MASK (0x03 << 4) + #define USBOTGSS_SYSCONFIG_IDLEMODE(x) ((x) << 2) +#define USBOTGSS_IDLEMODE_FORCE_IDLE 0 +#define USBOTGSS_IDLEMODE_NO_IDLE 1 +#define USBOTGSS_IDLEMODE_SMART_IDLE 2 +#define USBOTGSS_IDLEMODE_SMART_WAKEUP 3 + +#define USBOTGSS_IDLEMODE_MASK (0x03 << 2) + /* IRQ_EOI REGISTER */ #define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0) @@ -125,106 +142,51 @@ struct dwc3_omap { u32 dma_status:1; }; -#ifdef CONFIG_PM -static int dwc3_omap_suspend(struct device *dev) -{ - struct dwc3_omap *omap = dev_get_drvdata(dev); - - memcpy_fromio(omap->context, omap->base, omap->resource_size); - - return 0; -} - -static int dwc3_omap_resume(struct device *dev) -{ - struct dwc3_omap *omap = dev_get_drvdata(dev); - - memcpy_toio(omap->base, omap->context, omap->resource_size); - - return 0; -} - -static int dwc3_omap_idle(struct device *dev) -{ - struct dwc3_omap *omap = dev_get_drvdata(dev); - u32 reg; - - /* stop DMA Engine */ - reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG); - reg &= ~(USBOTGSS_SYSCONFIG_DMADISABLE); - dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg); - - return 0; -} - -static UNIVERSAL_DEV_PM_OPS(dwc3_omap_pm_ops, dwc3_omap_suspend, - dwc3_omap_resume, dwc3_omap_idle); - -#define DEV_PM_OPS (&dwc3_omap_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif - static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) { struct dwc3_omap *omap = _omap; u32 reg; - u32 ctrl; spin_lock(&omap->lock); reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1); - ctrl = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_CTRL); if (reg & USBOTGSS_IRQ1_DMADISABLECLR) { - dev_dbg(omap->base, "DMA Disable was Cleared\n"); + dev_dbg(omap->dev, "DMA Disable was Cleared\n"); omap->dma_status = false; } if (reg & USBOTGSS_IRQ1_OEVT) - dev_dbg(omap->base, "OTG Event\n"); + dev_dbg(omap->dev, "OTG Event\n"); - if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE) { - dev_dbg(omap->base, "DRVVBUS Rise\n"); - ctrl |= USBOTGSS_UTMI_OTG_CTRL_DRVVBUS; - } + if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE) + dev_dbg(omap->dev, "DRVVBUS Rise\n"); - if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE) { - dev_dbg(omap->base, "CHRGVBUS Rise\n"); - ctrl |= USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS; - } + if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE) + dev_dbg(omap->dev, "CHRGVBUS Rise\n"); - if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE) { - dev_dbg(omap->base, "DISCHRGVBUS Rise\n"); - ctrl |= USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS; - } + if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE) + dev_dbg(omap->dev, "DISCHRGVBUS Rise\n"); - if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE) { - dev_dbg(omap->base, "IDPULLUP Rise\n"); - ctrl |= USBOTGSS_UTMI_OTG_CTRL_IDPULLUP; - } + if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE) + dev_dbg(omap->dev, "IDPULLUP Rise\n"); - if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL) { - dev_dbg(omap->base, "DRVVBUS Fall\n"); - ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_DRVVBUS; - } + if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL) + dev_dbg(omap->dev, "DRVVBUS Fall\n"); - if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL) { - dev_dbg(omap->base, "CHRGVBUS Fall\n"); - ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS; - } + if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL) + dev_dbg(omap->dev, "CHRGVBUS Fall\n"); - if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL) { - dev_dbg(omap->base, "DISCHRGVBUS Fall\n"); - ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS; - } + if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL) + dev_dbg(omap->dev, "DISCHRGVBUS Fall\n"); - if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL) { - dev_dbg(omap->base, "IDPULLUP Fall\n"); - ctrl &= ~USBOTGSS_UTMI_OTG_CTRL_IDPULLUP; - } + if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL) + dev_dbg(omap->dev, "IDPULLUP Fall\n"); - dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_CTRL, ctrl); + dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg); + + reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0); + dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg); spin_unlock(&omap->lock); @@ -233,6 +195,7 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) static int __devinit dwc3_omap_probe(struct platform_device *pdev) { + struct dwc3_omap_data *pdata = pdev->dev.platform_data; struct platform_device *dwc3; struct dwc3_omap *omap; struct resource *res; @@ -298,12 +261,41 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) omap->base = base; omap->dwc3 = dwc3; + reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS); + + if (!pdata) { + dev_dbg(&pdev->dev, "missing platform data\n"); + } else { + switch (pdata->utmi_mode) { + case DWC3_OMAP_UTMI_MODE_SW: + reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE; + break; + case DWC3_OMAP_UTMI_MODE_HW: + reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE; + break; + default: + dev_dbg(&pdev->dev, "UNKNOWN utmi mode %d\n", + pdata->utmi_mode); + } + } + + dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg); + /* check the DMA Status */ reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG); omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE); + /* Set No-Idle and No-Standby */ + reg &= ~(USBOTGSS_STANDBYMODE_MASK + | USBOTGSS_IDLEMODE_MASK); + + reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY) + | USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE)); + + dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg); + ret = request_irq(omap->irq, dwc3_omap_interrupt, 0, - "dwc3-wrapper", omap); + "dwc3-omap", omap); if (ret) { dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n", omap->irq, ret); @@ -311,10 +303,10 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) } /* enable all IRQs */ - dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, 0x01); + reg = USBOTGSS_IRQO_COREIRQ_ST; + dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg); - reg = (USBOTGSS_IRQ1_DMADISABLECLR | - USBOTGSS_IRQ1_OEVT | + reg = (USBOTGSS_IRQ1_OEVT | USBOTGSS_IRQ1_DRVVBUS_RISE | USBOTGSS_IRQ1_CHRGVBUS_RISE | USBOTGSS_IRQ1_DISCHRGVBUS_RISE | @@ -388,7 +380,6 @@ static struct platform_driver dwc3_omap_driver = { .remove = __devexit_p(dwc3_omap_remove), .driver = { .name = "omap-dwc3", - .pm = DEV_PM_OPS, .of_match_table = of_dwc3_matach, }, }; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 4698fe01376..b66d9690572 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -62,33 +62,19 @@ static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) switch (state) { case EP0_UNCONNECTED: return "Unconnected"; - case EP0_IDLE: - return "Idle"; - case EP0_IN_DATA_PHASE: - return "IN Data Phase"; - case EP0_OUT_DATA_PHASE: - return "OUT Data Phase"; - case EP0_IN_WAIT_GADGET: - return "IN Wait Gadget"; - case EP0_OUT_WAIT_GADGET: - return "OUT Wait Gadget"; - case EP0_IN_WAIT_NRDY: - return "IN Wait NRDY"; - case EP0_OUT_WAIT_NRDY: - return "OUT Wait NRDY"; - case EP0_IN_STATUS_PHASE: - return "IN Status Phase"; - case EP0_OUT_STATUS_PHASE: - return "OUT Status Phase"; - case EP0_STALL: - return "Stall"; + case EP0_SETUP_PHASE: + return "Setup Phase"; + case EP0_DATA_PHASE: + return "Data Phase"; + case EP0_STATUS_PHASE: + return "Status Phase"; default: return "UNKNOWN"; } } static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, - u32 len) + u32 len, u32 type) { struct dwc3_gadget_ep_cmd_params params; struct dwc3_trb_hw *trb_hw; @@ -98,52 +84,15 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, int ret; dep = dwc->eps[epnum]; + if (dep->flags & DWC3_EP_BUSY) { + dev_vdbg(dwc->dev, "%s: still busy\n", dep->name); + return 0; + } trb_hw = dwc->ep0_trb; memset(&trb, 0, sizeof(trb)); - switch (dwc->ep0state) { - case EP0_IDLE: - trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP; - break; - - case EP0_IN_WAIT_NRDY: - case EP0_OUT_WAIT_NRDY: - case EP0_IN_STATUS_PHASE: - case EP0_OUT_STATUS_PHASE: - if (dwc->three_stage_setup) - trb.trbctl = DWC3_TRBCTL_CONTROL_STATUS3; - else - trb.trbctl = DWC3_TRBCTL_CONTROL_STATUS2; - - if (dwc->ep0state == EP0_IN_WAIT_NRDY) - dwc->ep0state = EP0_IN_STATUS_PHASE; - else if (dwc->ep0state == EP0_OUT_WAIT_NRDY) - dwc->ep0state = EP0_OUT_STATUS_PHASE; - break; - - case EP0_IN_WAIT_GADGET: - dwc->ep0state = EP0_IN_WAIT_NRDY; - return 0; - break; - - case EP0_OUT_WAIT_GADGET: - dwc->ep0state = EP0_OUT_WAIT_NRDY; - return 0; - - break; - - case EP0_IN_DATA_PHASE: - case EP0_OUT_DATA_PHASE: - trb.trbctl = DWC3_TRBCTL_CONTROL_DATA; - break; - - default: - dev_err(dwc->dev, "%s() can't in state %d\n", __func__, - dwc->ep0state); - return -EINVAL; - } - + trb.trbctl = type; trb.bplh = buf_dma; trb.length = len; @@ -167,31 +116,58 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, return ret; } + dep->flags |= DWC3_EP_BUSY; dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, dep->number); + dwc->ep0_next_event = DWC3_EP0_COMPLETE; + return 0; } static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep, struct dwc3_request *req) { - struct dwc3 *dwc = dep->dwc; - int ret; + int ret = 0; req->request.actual = 0; req->request.status = -EINPROGRESS; - req->direction = dep->direction; req->epnum = dep->number; list_add_tail(&req->list, &dep->request_list); - dwc3_map_buffer_to_dma(req); - ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma, - req->request.length); - if (ret < 0) { - list_del(&req->list); - dwc3_unmap_buffer_from_dma(req); + /* + * Gadget driver might not be quick enough to queue a request + * before we get a Transfer Not Ready event on this endpoint. + * + * In that case, we will set DWC3_EP_PENDING_REQUEST. When that + * flag is set, it's telling us that as soon as Gadget queues the + * required request, we should kick the transfer here because the + * IRQ we were waiting for is long gone. + */ + if (dep->flags & DWC3_EP_PENDING_REQUEST) { + struct dwc3 *dwc = dep->dwc; + unsigned direction; + u32 type; + + direction = !!(dep->flags & DWC3_EP0_DIR_IN); + + if (dwc->ep0state == EP0_STATUS_PHASE) { + type = dwc->three_stage_setup + ? DWC3_TRBCTL_CONTROL_STATUS3 + : DWC3_TRBCTL_CONTROL_STATUS2; + } else if (dwc->ep0state == EP0_DATA_PHASE) { + type = DWC3_TRBCTL_CONTROL_DATA; + } else { + /* should never happen */ + WARN_ON(1); + return 0; + } + + ret = dwc3_ep0_start_trans(dwc, direction, + req->request.dma, req->request.length, type); + dep->flags &= ~(DWC3_EP_PENDING_REQUEST | + DWC3_EP0_DIR_IN); } return ret; @@ -208,24 +184,6 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int ret; - switch (dwc->ep0state) { - case EP0_IN_DATA_PHASE: - case EP0_IN_WAIT_GADGET: - case EP0_IN_WAIT_NRDY: - case EP0_IN_STATUS_PHASE: - dep = dwc->eps[1]; - break; - - case EP0_OUT_DATA_PHASE: - case EP0_OUT_WAIT_GADGET: - case EP0_OUT_WAIT_NRDY: - case EP0_OUT_STATUS_PHASE: - dep = dwc->eps[0]; - break; - default: - return -EINVAL; - } - spin_lock_irqsave(&dwc->lock, flags); if (!dep->desc) { dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", @@ -256,51 +214,30 @@ out: static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc) { + struct dwc3_ep *dep = dwc->eps[0]; + /* stall is always issued on EP0 */ __dwc3_gadget_ep_set_halt(dwc->eps[0], 1); - dwc->eps[0]->flags &= ~DWC3_EP_STALL; - dwc->ep0state = EP0_IDLE; - dwc3_ep0_out_start(dwc); -} + dwc->eps[0]->flags = DWC3_EP_ENABLED; -void dwc3_ep0_out_start(struct dwc3 *dwc) -{ - struct dwc3_ep *dep; - int ret; + if (!list_empty(&dep->request_list)) { + struct dwc3_request *req; - dep = dwc->eps[0]; + req = next_request(&dep->request_list); + dwc3_gadget_giveback(dep, req, -ECONNRESET); + } - ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8); - WARN_ON(ret < 0); + dwc->ep0state = EP0_SETUP_PHASE; + dwc3_ep0_out_start(dwc); } -/* - * Send a zero length packet for the status phase of the control transfer - */ -static void dwc3_ep0_do_setup_status(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) +void dwc3_ep0_out_start(struct dwc3 *dwc) { - struct dwc3_ep *dep; int ret; - u32 epnum; - - epnum = event->endpoint_number; - dep = dwc->eps[epnum]; - if (epnum) - dwc->ep0state = EP0_IN_STATUS_PHASE; - else - dwc->ep0state = EP0_OUT_STATUS_PHASE; - - /* - * Not sure Why I need a buffer for a zero transfer. Maybe the - * HW reacts strange on a NULL pointer - */ - ret = dwc3_ep0_start_trans(dwc, epnum, dwc->ctrl_req_addr, 0); - if (ret) { - dev_dbg(dwc->dev, "failed to start transfer, stalling\n"); - dwc3_ep0_stall_and_restart(dwc); - } + ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8, + DWC3_TRBCTL_CONTROL_SETUP); + WARN_ON(ret < 0); } static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) @@ -322,16 +259,9 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) static void dwc3_ep0_send_status_response(struct dwc3 *dwc) { - u32 epnum; - - if (dwc->ep0state == EP0_IN_DATA_PHASE) - epnum = 1; - else - epnum = 0; - - dwc3_ep0_start_trans(dwc, epnum, dwc->ctrl_req_addr, - dwc->ep0_usb_req.length); - dwc->ep0_status_pending = 1; + dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr, + dwc->ep0_usb_req.length, + DWC3_TRBCTL_CONTROL_DATA); } /* @@ -376,7 +306,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl response_pkt = (__le16 *) dwc->setup_buf; *response_pkt = cpu_to_le16(usb_status); dwc->ep0_usb_req.length = sizeof(*response_pkt); - dwc3_ep0_send_status_response(dwc); + dwc->ep0_status_pending = 1; return 0; } @@ -486,8 +416,6 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, return -EINVAL; }; - dwc->ep0state = EP0_IN_WAIT_NRDY; - return 0; } @@ -522,7 +450,7 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) ret = -EINVAL; break; } - dwc->ep0state = EP0_IN_WAIT_NRDY; + return ret; } @@ -610,16 +538,15 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, len = le16_to_cpu(ctrl->wLength); if (!len) { - dwc->ep0state = EP0_IN_WAIT_GADGET; dwc->three_stage_setup = 0; + dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; } else { dwc->three_stage_setup = 1; - if (ctrl->bRequestType & USB_DIR_IN) - dwc->ep0state = EP0_IN_DATA_PHASE; - else - dwc->ep0state = EP0_OUT_DATA_PHASE; + dwc->ep0_next_event = DWC3_EP0_NRDY_DATA; } + dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN); + if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) ret = dwc3_ep0_std_request(dwc, ctrl); else @@ -639,14 +566,16 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, struct usb_request *ur; struct dwc3_trb trb; struct dwc3_ep *dep; - u32 transfered; + u32 transferred; u8 epnum; epnum = event->endpoint_number; dep = dwc->eps[epnum]; + dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; + if (!dwc->ep0_status_pending) { - r = next_request(&dep->request_list); + r = next_request(&dwc->eps[0]->request_list); ur = &r->request; } else { ur = &dwc->ep0_usb_req; @@ -655,8 +584,17 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, dwc3_trb_to_nat(dwc->ep0_trb, &trb); - transfered = ur->length - trb.length; - ur->actual += transfered; + if (dwc->ep0_bounced) { + struct dwc3_ep *ep0 = dwc->eps[0]; + + transferred = min_t(u32, ur->length, + ep0->endpoint.maxpacket - trb.length); + memcpy(ur->buf, dwc->ep0_bounce, transferred); + dwc->ep0_bounced = false; + } else { + transferred = ur->length - trb.length; + ur->actual += transferred; + } if ((epnum & 1) && ur->actual < ur->length) { /* for some reason we did not get everything out */ @@ -668,12 +606,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, * handle the case where we have to send a zero packet. This * seems to be case when req.length > maxpacket. Could it be? */ - /* The transfer is complete, wait for HOST */ - if (epnum & 1) - dwc->ep0state = EP0_IN_WAIT_NRDY; - else - dwc->ep0state = EP0_OUT_WAIT_NRDY; - if (r) dwc3_gadget_giveback(dep, r, 0); } @@ -684,10 +616,8 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc, { struct dwc3_request *r; struct dwc3_ep *dep; - u8 epnum; - epnum = event->endpoint_number; - dep = dwc->eps[epnum]; + dep = dwc->eps[0]; if (!list_empty(&dep->request_list)) { r = next_request(&dep->request_list); @@ -695,62 +625,170 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc, dwc3_gadget_giveback(dep, r, 0); } - dwc->ep0state = EP0_IDLE; + dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); } static void dwc3_ep0_xfer_complete(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { + struct dwc3_ep *dep = dwc->eps[event->endpoint_number]; + + dep->flags &= ~DWC3_EP_BUSY; + switch (dwc->ep0state) { - case EP0_IDLE: + case EP0_SETUP_PHASE: + dev_vdbg(dwc->dev, "Inspecting Setup Bytes\n"); dwc3_ep0_inspect_setup(dwc, event); break; - case EP0_IN_DATA_PHASE: - case EP0_OUT_DATA_PHASE: + case EP0_DATA_PHASE: + dev_vdbg(dwc->dev, "Data Phase\n"); dwc3_ep0_complete_data(dwc, event); break; - case EP0_IN_STATUS_PHASE: - case EP0_OUT_STATUS_PHASE: + case EP0_STATUS_PHASE: + dev_vdbg(dwc->dev, "Status Phase\n"); dwc3_ep0_complete_req(dwc, event); break; + default: + WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state); + } +} - case EP0_IN_WAIT_NRDY: - case EP0_OUT_WAIT_NRDY: - case EP0_IN_WAIT_GADGET: - case EP0_OUT_WAIT_GADGET: - case EP0_UNCONNECTED: - case EP0_STALL: - break; +static void dwc3_ep0_do_control_setup(struct dwc3 *dwc, + const struct dwc3_event_depevt *event) +{ + dwc->ep0state = EP0_SETUP_PHASE; + dwc3_ep0_out_start(dwc); +} + +static void dwc3_ep0_do_control_data(struct dwc3 *dwc, + const struct dwc3_event_depevt *event) +{ + struct dwc3_ep *dep; + struct dwc3_request *req; + int ret; + + dep = dwc->eps[0]; + dwc->ep0state = EP0_DATA_PHASE; + + if (dwc->ep0_status_pending) { + dwc3_ep0_send_status_response(dwc); + return; + } + + if (list_empty(&dep->request_list)) { + dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n"); + dep->flags |= DWC3_EP_PENDING_REQUEST; + + if (event->endpoint_number) + dep->flags |= DWC3_EP0_DIR_IN; + return; + } + + req = next_request(&dep->request_list); + req->direction = !!event->endpoint_number; + + dwc->ep0state = EP0_DATA_PHASE; + if (req->request.length == 0) { + ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, + dwc->ctrl_req_addr, 0, + DWC3_TRBCTL_CONTROL_DATA); + } else if ((req->request.length % dep->endpoint.maxpacket) + && (event->endpoint_number == 0)) { + dwc3_map_buffer_to_dma(req); + + WARN_ON(req->request.length > dep->endpoint.maxpacket); + + dwc->ep0_bounced = true; + + /* + * REVISIT in case request length is bigger than EP0 + * wMaxPacketSize, we will need two chained TRBs to handle + * the transfer. + */ + ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, + dwc->ep0_bounce_addr, dep->endpoint.maxpacket, + DWC3_TRBCTL_CONTROL_DATA); + } else { + dwc3_map_buffer_to_dma(req); + + ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, + req->request.dma, req->request.length, + DWC3_TRBCTL_CONTROL_DATA); } + + WARN_ON(ret < 0); +} + +static void dwc3_ep0_do_control_status(struct dwc3 *dwc, + const struct dwc3_event_depevt *event) +{ + u32 type; + int ret; + + dwc->ep0state = EP0_STATUS_PHASE; + + type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3 + : DWC3_TRBCTL_CONTROL_STATUS2; + + ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, + dwc->ctrl_req_addr, 0, type); + + WARN_ON(ret < 0); } static void dwc3_ep0_xfernotready(struct dwc3 *dwc, const struct dwc3_event_depevt *event) { - switch (dwc->ep0state) { - case EP0_IN_WAIT_GADGET: - dwc->ep0state = EP0_IN_WAIT_NRDY; - break; - case EP0_OUT_WAIT_GADGET: - dwc->ep0state = EP0_OUT_WAIT_NRDY; + switch (event->status) { + case DEPEVT_STATUS_CONTROL_SETUP: + dev_vdbg(dwc->dev, "Control Setup\n"); + dwc3_ep0_do_control_setup(dwc, event); break; - case EP0_IN_WAIT_NRDY: - case EP0_OUT_WAIT_NRDY: - dwc3_ep0_do_setup_status(dwc, event); - break; + case DEPEVT_STATUS_CONTROL_DATA: + dev_vdbg(dwc->dev, "Control Data\n"); - case EP0_IDLE: - case EP0_IN_STATUS_PHASE: - case EP0_OUT_STATUS_PHASE: - case EP0_IN_DATA_PHASE: - case EP0_OUT_DATA_PHASE: - case EP0_UNCONNECTED: - case EP0_STALL: + if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) { + dev_vdbg(dwc->dev, "Expected %d got %d\n", + DEPEVT_STATUS_CONTROL_DATA, + event->status); + + dwc3_ep0_stall_and_restart(dwc); + return; + } + + /* + * One of the possible error cases is when Host _does_ + * request for Data Phase, but it does so on the wrong + * direction. + * + * Here, we already know ep0_next_event is DATA (see above), + * so we only need to check for direction. + */ + if (dwc->ep0_expect_in != event->endpoint_number) { + dev_vdbg(dwc->dev, "Wrong direction for Data phase\n"); + dwc3_ep0_stall_and_restart(dwc); + return; + } + + dwc3_ep0_do_control_data(dwc, event); break; + + case DEPEVT_STATUS_CONTROL_STATUS: + dev_vdbg(dwc->dev, "Control Status\n"); + + if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) { + dev_vdbg(dwc->dev, "Expected %d got %d\n", + DEPEVT_STATUS_CONTROL_STATUS, + event->status); + + dwc3_ep0_stall_and_restart(dwc); + return; + } + dwc3_ep0_do_control_status(dwc, event); } } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index cebaef720cd..859257a3d63 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -61,16 +61,16 @@ void dwc3_map_buffer_to_dma(struct dwc3_request *req) { struct dwc3 *dwc = req->dep->dwc; + if (req->request.length == 0) { + /* req->request.dma = dwc->setup_buf_addr; */ + return; + } + if (req->request.dma == DMA_ADDR_INVALID) { req->request.dma = dma_map_single(dwc->dev, req->request.buf, req->request.length, req->direction ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->mapped = true; - } else { - dma_sync_single_for_device(dwc->dev, req->request.dma, - req->request.length, req->direction - ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - req->mapped = false; } } @@ -78,15 +78,17 @@ void dwc3_unmap_buffer_from_dma(struct dwc3_request *req) { struct dwc3 *dwc = req->dep->dwc; + if (req->request.length == 0) { + req->request.dma = DMA_ADDR_INVALID; + return; + } + if (req->mapped) { dma_unmap_single(dwc->dev, req->request.dma, req->request.length, req->direction ? DMA_TO_DEVICE : DMA_FROM_DEVICE); req->mapped = 0; - } else { - dma_sync_single_for_cpu(dwc->dev, req->request.dma, - req->request.length, req->direction - ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + req->request.dma = DMA_ADDR_INVALID; } } @@ -152,7 +154,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) { struct dwc3_ep *dep = dwc->eps[ep]; - unsigned long timeout = 500; + u32 timeout = 500; u32 reg; dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n", @@ -168,13 +170,12 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, do { reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep)); if (!(reg & DWC3_DEPCMD_CMDACT)) { - dev_vdbg(dwc->dev, "CMD Compl Status %d DEPCMD %04x\n", - ((reg & 0xf000) >> 12), reg); + dev_vdbg(dwc->dev, "Command Complete --> %d\n", + DWC3_DEPCMD_STATUS(reg)); return 0; } /* - * XXX Figure out a sane timeout here. 500ms is way too much. * We can't sleep here, because it is also called from * interrupt context. */ @@ -182,7 +183,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, if (!timeout) return -ETIMEDOUT; - mdelay(1); + udelay(1); } while (1); } @@ -358,34 +359,36 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, return 0; } -static void dwc3_gadget_nuke_reqs(struct dwc3_ep *dep, const int status) +static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum); +static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) { struct dwc3_request *req; + if (!list_empty(&dep->req_queued)) + dwc3_stop_active_transfer(dwc, dep->number); + while (!list_empty(&dep->request_list)) { req = next_request(&dep->request_list); - dwc3_gadget_giveback(dep, req, status); + dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } - /* nuke queued TRBs as well on command complete */ - dep->flags |= DWC3_EP_WILL_SHUTDOWN; } /** * __dwc3_gadget_ep_disable - Disables a HW endpoint * @dep: the endpoint to disable * - * Caller should take care of locking + * This function also removes requests which are currently processed ny the + * hardware and those which are not yet scheduled. + * Caller should take care of locking. */ -static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum); static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) { struct dwc3 *dwc = dep->dwc; u32 reg; dep->flags &= ~DWC3_EP_ENABLED; - dwc3_stop_active_transfer(dwc, dep->number); - dwc3_gadget_nuke_reqs(dep, -ESHUTDOWN); + dwc3_remove_requests(dwc, dep); reg = dwc3_readl(dwc->regs, DWC3_DALEPENA); reg &= ~DWC3_DALEPENA_EP(dep->number); @@ -632,7 +635,7 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep, break; case USB_ENDPOINT_XFER_ISOC: - trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS; + trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST; /* IOC every DWC3_TRB_NUM / 4 so we can refill */ if (!(cur_slot % (DWC3_TRB_NUM / 4))) @@ -870,8 +873,14 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value) memset(¶ms, 0x00, sizeof(params)); if (value) { - if (dep->number == 0 || dep->number == 1) - dwc->ep0state = EP0_STALL; + if (dep->number == 0 || dep->number == 1) { + /* + * Whenever EP0 is stalled, we will restart + * the state machine, thus moving back to + * Setup Phase + */ + dwc->ep0state = EP0_SETUP_PHASE; + } ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, DWC3_DEPCMD_SETSTALL, ¶ms); @@ -1063,7 +1072,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) { u32 reg; - unsigned long timeout = 500; + u32 timeout = 500; reg = dwc3_readl(dwc->regs, DWC3_DCTL); if (is_on) @@ -1082,13 +1091,10 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on) if (reg & DWC3_DSTS_DEVCTRLHLT) break; } - /* - * XXX reduce the 500ms delay - */ timeout--; if (!timeout) break; - mdelay(1); + udelay(1); } while (1); dev_vdbg(dwc->dev, "gadget %s data soft-%s\n", @@ -1135,13 +1141,10 @@ static int dwc3_gadget_start(struct usb_gadget *g, reg = dwc3_readl(dwc->regs, DWC3_GCTL); - /* - * REVISIT: power down scale might be different - * depending on PHY used, need to pass that via platform_data - */ - reg |= DWC3_GCTL_PWRDNSCALE(0x61a) - | DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE); + reg &= ~DWC3_GCTL_SCALEDOWN(3); + reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG); reg &= ~DWC3_GCTL_DISSCRAMBLE; + reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE); /* * WORKAROUND: DWC3 revisions <1.90a have a bug @@ -1177,7 +1180,7 @@ static int dwc3_gadget_start(struct usb_gadget *g, } /* begin to receive SETUP packets */ - dwc->ep0state = EP0_IDLE; + dwc->ep0state = EP0_SETUP_PHASE; dwc3_ep0_out_start(dwc); spin_unlock_irqrestore(&dwc->lock, flags); @@ -1309,11 +1312,17 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, dwc3_trb_to_nat(req->trb, &trb); - if (trb.hwo) { + if (trb.hwo && status != -ESHUTDOWN) + /* + * We continue despite the error. There is not much we + * can do. If we don't clean in up we loop for ever. If + * we skip the TRB than it gets overwritten reused after + * a while since we use them in a ring buffer. a BUG() + * would help. Lets hope that if this occures, someone + * fixes the root cause instead of looking away :) + */ dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n", dep->name, req->trb); - continue; - } count = trb.length; if (dep->direction) { @@ -1360,8 +1369,10 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc, status = -ECONNRESET; clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status); - if (clean_busy) + if (clean_busy) { dep->flags &= ~DWC3_EP_BUSY; + dep->res_trans_idx = 0; + } } static void dwc3_gadget_start_isoc(struct dwc3 *dwc, @@ -1407,16 +1418,6 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep, dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN); dep->flags &= ~DWC3_EP_BUSY; /* pending requets are ignored and are queued on XferNotReady */ - - if (dep->flags & DWC3_EP_WILL_SHUTDOWN) { - while (!list_empty(&dep->req_queued)) { - struct dwc3_request *req; - - req = next_request(&dep->req_queued); - dwc3_gadget_giveback(dep, req, -ESHUTDOWN); - } - dep->flags &= DWC3_EP_WILL_SHUTDOWN; - } } static void dwc3_ep_cmd_compl(struct dwc3_ep *dep, @@ -1524,6 +1525,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) dep = dwc->eps[epnum]; + WARN_ON(!dep->res_trans_idx); if (dep->res_trans_idx) { cmd = DWC3_DEPCMD_ENDTRANSFER; cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC; @@ -1531,6 +1533,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum) memset(¶ms, 0, sizeof(params)); ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, ¶ms); WARN_ON_ONCE(ret); + dep->res_trans_idx = 0; } } @@ -1545,7 +1548,7 @@ static void dwc3_stop_active_transfers(struct dwc3 *dwc) if (!(dep->flags & DWC3_EP_ENABLED)) continue; - __dwc3_gadget_ep_disable(dep); + dwc3_remove_requests(dwc, dep); } } @@ -1718,7 +1721,6 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) memset(¶ms, 0x00, sizeof(params)); - dwc->ep0state = EP0_IDLE; reg = dwc3_readl(dwc->regs, DWC3_DSTS); speed = reg & DWC3_DSTS_CONNECTSPD; dwc->speed = speed; @@ -1790,10 +1792,10 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, unsigned int evtinfo) { - dev_vdbg(dwc->dev, "%s\n", __func__); - /* The fith bit says SuperSpeed yes or no. */ dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK; + + dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); } static void dwc3_gadget_interrupt(struct dwc3 *dwc, @@ -1947,6 +1949,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) goto err2; } + dwc->ep0_bounce = dma_alloc_coherent(dwc->dev, + 512, &dwc->ep0_bounce_addr, GFP_KERNEL); + if (!dwc->ep0_bounce) { + dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n"); + ret = -ENOMEM; + goto err3; + } + dev_set_name(&dwc->gadget.dev, "gadget"); dwc->gadget.ops = &dwc3_gadget_ops; @@ -1968,7 +1978,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) ret = dwc3_gadget_init_endpoints(dwc); if (ret) - goto err3; + goto err4; irq = platform_get_irq(to_platform_device(dwc->dev), 0); @@ -1977,7 +1987,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) if (ret) { dev_err(dwc->dev, "failed to request irq #%d --> %d\n", irq, ret); - goto err4; + goto err5; } /* Enable all but Start and End of Frame IRQs */ @@ -1996,27 +2006,31 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) if (ret) { dev_err(dwc->dev, "failed to register gadget device\n"); put_device(&dwc->gadget.dev); - goto err5; + goto err6; } ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); - goto err6; + goto err7; } return 0; -err6: +err7: device_unregister(&dwc->gadget.dev); -err5: +err6: dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00); free_irq(irq, dwc); -err4: +err5: dwc3_gadget_free_endpoints(dwc); +err4: + dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, + dwc->ep0_bounce_addr); + err3: dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2, dwc->setup_buf, dwc->setup_buf_addr); @@ -2049,6 +2063,9 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc3_gadget_free_endpoints(dwc); + dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, + dwc->ep0_bounce_addr); + dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2, dwc->setup_buf, dwc->setup_buf_addr); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index fe563798389..a60b472a0b3 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -96,6 +96,22 @@ config USB_GADGET_VBUS_DRAW This value will be used except for system-specific gadget drivers that have more specific information. +config USB_GADGET_STORAGE_NUM_BUFFERS + int "Number of storage pipeline buffers" + range 2 4 + default 2 + help + Usually 2 buffers are enough to establish a good buffering + pipeline. The number may be increased in order to compensate + for a bursty VFS behaviour. For instance there may be CPU wake up + latencies that makes the VFS to appear bursty in a system with + an CPU on-demand governor. Especially if DMA is doing IO to + offload the CPU. In this case the CPU will go into power + save often and spin up occasionally to move data within VFS. + If selecting USB_GADGET_DEBUG_FILES this value may be set by + a module parameter as well. + If unsure, say 2. + # # USB Peripheral Controller Support # diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index a9a4eade7e8..ec7ffcd0d0c 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c @@ -460,7 +460,7 @@ static int audio_set_endpoint_req(struct usb_function *f, switch (ctrl->bRequest) { case UAC_SET_CUR: - value = 0; + value = len; break; case UAC_SET_MIN: @@ -499,7 +499,7 @@ static int audio_get_endpoint_req(struct usb_function *f, case UAC_GET_MIN: case UAC_GET_MAX: case UAC_GET_RES: - value = 3; + value = len; break; case UAC_GET_MEM: break; @@ -681,17 +681,18 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f) status = -ENOMEM; - /* supcard all relevant hardware speeds... we expect that when + /* copy descriptors, and track endpoint copies */ + f->descriptors = usb_copy_descriptors(f_audio_desc); + + /* + * support all relevant hardware speeds... we expect that when * hardware is dual speed, all bulk-capable endpoints work at * both speeds */ - - /* copy descriptors, and track endpoint copies */ if (gadget_is_dualspeed(c->cdev->gadget)) { c->highspeed = true; f->hs_descriptors = usb_copy_descriptors(f_audio_desc); - } else - f->descriptors = usb_copy_descriptors(f_audio_desc); + } return 0; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 4ce3decda1d..75694147314 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -112,8 +112,7 @@ * is not loaded (an empty string as "filename" in the fsg_config * structure causes error). The CD-ROM emulation includes a single * data track and no audio tracks; hence there need be only one - * backing file per LUN. Note also that the CD-ROM block length is - * set to 512 rather than the more common value 2048. + * backing file per LUN. * * * MSF includes support for module parameters. If gadget using it @@ -363,7 +362,7 @@ struct fsg_common { struct fsg_buffhd *next_buffhd_to_fill; struct fsg_buffhd *next_buffhd_to_drain; - struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; + struct fsg_buffhd *buffhds; int cmnd_size; u8 cmnd[MAX_COMMAND_SIZE]; @@ -745,7 +744,6 @@ static int do_read(struct fsg_common *common) u32 amount_left; loff_t file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nread; /* @@ -771,7 +769,7 @@ static int do_read(struct fsg_common *common) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; return -EINVAL; } - file_offset = ((loff_t) lba) << 9; + file_offset = ((loff_t) lba) << curlun->blkbits; /* Carry out the file reads */ amount_left = common->data_size_from_cmnd; @@ -784,18 +782,10 @@ static int do_read(struct fsg_common *common) * Try to read the remaining amount. * But don't read more than the buffer size. * And don't try to read past the end of the file. - * Finally, if we're not at a page boundary, don't read past - * the next page. - * If this means reading 0 then we were asked to read past - * the end of file. */ amount = min(amount_left, FSG_BUFLEN); amount = min((loff_t)amount, curlun->file_length - file_offset); - partial_page = file_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, (unsigned int)PAGE_CACHE_SIZE - - partial_page); /* Wait for the next buffer to become available */ bh = common->next_buffhd_to_fill; @@ -812,7 +802,8 @@ static int do_read(struct fsg_common *common) if (amount == 0) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; bh->inreq->length = 0; bh->state = BUF_STATE_FULL; @@ -835,18 +826,25 @@ static int do_read(struct fsg_common *common) } else if (nread < amount) { LDBG(curlun, "partial file read: %d/%u\n", (int)nread, amount); - nread -= (nread & 511); /* Round down to a block */ + nread = round_down(nread, curlun->blksize); } file_offset += nread; amount_left -= nread; common->residue -= nread; + + /* + * Except at the end of the transfer, nread will be + * equal to the buffer size, which is divisible by the + * bulk-in maxpacket size. + */ bh->inreq->length = nread; bh->state = BUF_STATE_FULL; /* If an error occurred, report it and its position */ if (nread < amount) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -877,7 +875,6 @@ static int do_write(struct fsg_common *common) u32 amount_left_to_req, amount_left_to_write; loff_t usb_offset, file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nwritten; int rc; @@ -921,7 +918,7 @@ static int do_write(struct fsg_common *common) /* Carry out the file writes */ get_some_more = 1; - file_offset = usb_offset = ((loff_t) lba) << 9; + file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; amount_left_to_req = common->data_size_from_cmnd; amount_left_to_write = common->data_size_from_cmnd; @@ -933,41 +930,21 @@ static int do_write(struct fsg_common *common) /* * Figure out how much we want to get: - * Try to get the remaining amount. - * But don't get more than the buffer size. - * And don't try to go past the end of the file. - * If we're not at a page boundary, - * don't go past the next page. - * If this means getting 0, then we were asked - * to write past the end of file. - * Finally, round down to a block boundary. + * Try to get the remaining amount, + * but not more than the buffer size. */ amount = min(amount_left_to_req, FSG_BUFLEN); - amount = min((loff_t)amount, - curlun->file_length - usb_offset); - partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, - (unsigned int)PAGE_CACHE_SIZE - partial_page); - - if (amount == 0) { + + /* Beyond the end of the backing file? */ + if (usb_offset >= curlun->file_length) { get_some_more = 0; curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = usb_offset >> 9; + curlun->sense_data_info = + usb_offset >> curlun->blkbits; curlun->info_valid = 1; continue; } - amount -= amount & 511; - if (amount == 0) { - - /* - * Why were we were asked to transfer a - * partial block? - */ - get_some_more = 0; - continue; - } /* Get the next buffer */ usb_offset += amount; @@ -977,8 +954,9 @@ static int do_write(struct fsg_common *common) get_some_more = 0; /* - * amount is always divisible by 512, hence by - * the bulk-out maxpacket size + * Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by + * the bulk-out maxpacket size. */ bh->outreq->length = amount; bh->bulk_out_intended_length = amount; @@ -1002,7 +980,8 @@ static int do_write(struct fsg_common *common) /* Did something go wrong with the transfer? */ if (bh->outreq->status != 0) { curlun->sense_data = SS_COMMUNICATION_FAILURE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1016,6 +995,11 @@ static int do_write(struct fsg_common *common) amount = curlun->file_length - file_offset; } + /* Don't write a partial block */ + amount = round_down(amount, curlun->blksize); + if (amount == 0) + goto empty_write; + /* Perform the write */ file_offset_tmp = file_offset; nwritten = vfs_write(curlun->filp, @@ -1033,8 +1017,7 @@ static int do_write(struct fsg_common *common) } else if (nwritten < amount) { LDBG(curlun, "partial file write: %d/%u\n", (int)nwritten, amount); - nwritten -= (nwritten & 511); - /* Round down to a block */ + nwritten = round_down(nwritten, curlun->blksize); } file_offset += nwritten; amount_left_to_write -= nwritten; @@ -1043,11 +1026,13 @@ static int do_write(struct fsg_common *common) /* If an error occurred, report it and its position */ if (nwritten < amount) { curlun->sense_data = SS_WRITE_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } + empty_write: /* Did the host decide to stop early? */ if (bh->outreq->actual != bh->outreq->length) { common->short_packet_received = 1; @@ -1129,8 +1114,8 @@ static int do_verify(struct fsg_common *common) return -EIO; /* No default reply */ /* Prepare to carry out the file verify */ - amount_left = verification_length << 9; - file_offset = ((loff_t) lba) << 9; + amount_left = verification_length << curlun->blkbits; + file_offset = ((loff_t) lba) << curlun->blkbits; /* Write out all the dirty buffers before invalidating them */ fsg_lun_fsync_sub(curlun); @@ -1148,8 +1133,6 @@ static int do_verify(struct fsg_common *common) * Try to read the remaining amount, but not more than * the buffer size. * And don't try to read past the end of the file. - * If this means reading 0 then we were asked to read - * past the end of file. */ amount = min(amount_left, FSG_BUFLEN); amount = min((loff_t)amount, @@ -1157,7 +1140,8 @@ static int do_verify(struct fsg_common *common) if (amount == 0) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1179,11 +1163,12 @@ static int do_verify(struct fsg_common *common) } else if (nread < amount) { LDBG(curlun, "partial file verify: %d/%u\n", (int)nread, amount); - nread -= nread & 511; /* Round down to a sector */ + nread = round_down(nread, curlun->blksize); } if (nread == 0) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = + file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1289,7 +1274,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); /* Max logical block */ - put_unaligned_be32(512, &buf[4]); /* Block length */ + put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ return 8; } @@ -1527,7 +1512,7 @@ static int do_read_format_capacities(struct fsg_common *common, put_unaligned_be32(curlun->num_sectors, &buf[0]); /* Number of blocks */ - put_unaligned_be32(512, &buf[4]); /* Block length */ + put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */ buf[4] = 0x02; /* Current capacity */ return 12; } @@ -1623,7 +1608,8 @@ static int throw_away_data(struct fsg_common *common) amount = min(common->usb_amount_left, FSG_BUFLEN); /* - * amount is always divisible by 512, hence by + * Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by * the bulk-out maxpacket size. */ bh->outreq->length = amount; @@ -2022,7 +2008,8 @@ static int do_scsi_command(struct fsg_common *common) case READ_6: i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + common->data_size_from_cmnd = (i == 0 ? 256 : i) << + common->curlun->blkbits; reply = check_command(common, 6, DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1, "READ(6)"); @@ -2032,7 +2019,8 @@ static int do_scsi_command(struct fsg_common *common) case READ_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << 9; + get_unaligned_be16(&common->cmnd[7]) << + common->curlun->blkbits; reply = check_command(common, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)"); @@ -2042,7 +2030,8 @@ static int do_scsi_command(struct fsg_common *common) case READ_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << 9; + get_unaligned_be32(&common->cmnd[6]) << + common->curlun->blkbits; reply = check_command(common, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)"); @@ -2142,7 +2131,8 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_6: i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + common->data_size_from_cmnd = (i == 0 ? 256 : i) << + common->curlun->blkbits; reply = check_command(common, 6, DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1, "WRITE(6)"); @@ -2152,7 +2142,8 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << 9; + get_unaligned_be16(&common->cmnd[7]) << + common->curlun->blkbits; reply = check_command(common, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)"); @@ -2162,7 +2153,8 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << 9; + get_unaligned_be32(&common->cmnd[6]) << + common->curlun->blkbits; reply = check_command(common, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)"); @@ -2348,7 +2340,7 @@ reset: if (common->fsg) { fsg = common->fsg; - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; if (bh->inreq) { @@ -2405,7 +2397,7 @@ reset: clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); /* Allocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &common->buffhds[i]; rc = alloc_request(common, fsg->bulk_in, &bh->inreq); @@ -2474,7 +2466,7 @@ static void handle_exception(struct fsg_common *common) /* Cancel all the pending transfers */ if (likely(common->fsg)) { - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &common->buffhds[i]; if (bh->inreq_busy) usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); @@ -2486,7 +2478,7 @@ static void handle_exception(struct fsg_common *common) /* Wait until everything is idle */ for (;;) { int num_active = 0; - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &common->buffhds[i]; num_active += bh->inreq_busy + bh->outreq_busy; } @@ -2509,7 +2501,7 @@ static void handle_exception(struct fsg_common *common) */ spin_lock_irq(&common->lock); - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &common->buffhds[i]; bh->state = BUF_STATE_EMPTY; } @@ -2718,6 +2710,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, int nluns, i, rc; char *pathbuf; + rc = fsg_num_buffers_validate(); + if (rc != 0) + return ERR_PTR(rc); + /* Find out how many LUNs there should be */ nluns = cfg->nluns; if (nluns < 1 || nluns > FSG_MAX_LUNS) { @@ -2736,6 +2732,14 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, common->free_storage_on_release = 0; } + common->buffhds = kcalloc(fsg_num_buffers, + sizeof *(common->buffhds), GFP_KERNEL); + if (!common->buffhds) { + if (common->free_storage_on_release) + kfree(common); + return ERR_PTR(-ENOMEM); + } + common->ops = cfg->ops; common->private_data = cfg->private_data; @@ -2813,7 +2817,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common, /* Data buffers cyclic list */ bh = common->buffhds; - i = FSG_NUM_BUFFERS; + i = fsg_num_buffers; goto buffhds_first_it; do { bh->next = bh + 1; @@ -2939,12 +2943,13 @@ static void fsg_common_release(struct kref *ref) { struct fsg_buffhd *bh = common->buffhds; - unsigned i = FSG_NUM_BUFFERS; + unsigned i = fsg_num_buffers; do { kfree(bh->buf); } while (++bh, --i); } + kfree(common->buffhds); if (common->free_storage_on_release) kfree(common); } diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 4ac8084b579..12ac30b21ba 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -69,8 +69,7 @@ * each LUN would be settable independently as a disk drive or a CD-ROM * drive, but currently all LUNs have to be the same type. The CD-ROM * emulation includes a single data track and no audio tracks; hence there - * need be only one backing file per LUN. Note also that the CD-ROM block - * length is set to 512 rather than the more common value 2048. + * need be only one backing file per LUN. * * Requirements are modest; only a bulk-in and a bulk-out endpoint are * needed (an interrupt-out endpoint is also needed for CBI). The memory @@ -461,7 +460,6 @@ struct fsg_dev { struct fsg_buffhd *next_buffhd_to_fill; struct fsg_buffhd *next_buffhd_to_drain; - struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; int thread_wakeup_needed; struct completion thread_notifier; @@ -488,6 +486,8 @@ struct fsg_dev { unsigned int nluns; struct fsg_lun *luns; struct fsg_lun *curlun; + /* Must be the last entry */ + struct fsg_buffhd buffhds[]; }; typedef void (*fsg_routine_t)(struct fsg_dev *); @@ -1136,7 +1136,6 @@ static int do_read(struct fsg_dev *fsg) u32 amount_left; loff_t file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nread; /* Get the starting Logical Block Address and check that it's @@ -1158,7 +1157,7 @@ static int do_read(struct fsg_dev *fsg) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; return -EINVAL; } - file_offset = ((loff_t) lba) << 9; + file_offset = ((loff_t) lba) << curlun->blkbits; /* Carry out the file reads */ amount_left = fsg->data_size_from_cmnd; @@ -1171,17 +1170,10 @@ static int do_read(struct fsg_dev *fsg) * Try to read the remaining amount. * But don't read more than the buffer size. * And don't try to read past the end of the file. - * Finally, if we're not at a page boundary, don't read past - * the next page. - * If this means reading 0 then we were asked to read past - * the end of file. */ + */ amount = min((unsigned int) amount_left, mod_data.buflen); amount = min((loff_t) amount, curlun->file_length - file_offset); - partial_page = file_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - - partial_page); /* Wait for the next buffer to become available */ bh = fsg->next_buffhd_to_fill; @@ -1196,7 +1188,7 @@ static int do_read(struct fsg_dev *fsg) if (amount == 0) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; bh->inreq->length = 0; bh->state = BUF_STATE_FULL; @@ -1221,18 +1213,23 @@ static int do_read(struct fsg_dev *fsg) } else if (nread < amount) { LDBG(curlun, "partial file read: %d/%u\n", (int) nread, amount); - nread -= (nread & 511); // Round down to a block + nread = round_down(nread, curlun->blksize); } file_offset += nread; amount_left -= nread; fsg->residue -= nread; + + /* Except at the end of the transfer, nread will be + * equal to the buffer size, which is divisible by the + * bulk-in maxpacket size. + */ bh->inreq->length = nread; bh->state = BUF_STATE_FULL; /* If an error occurred, report it and its position */ if (nread < amount) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1262,7 +1259,6 @@ static int do_write(struct fsg_dev *fsg) u32 amount_left_to_req, amount_left_to_write; loff_t usb_offset, file_offset, file_offset_tmp; unsigned int amount; - unsigned int partial_page; ssize_t nwritten; int rc; @@ -1303,7 +1299,7 @@ static int do_write(struct fsg_dev *fsg) /* Carry out the file writes */ get_some_more = 1; - file_offset = usb_offset = ((loff_t) lba) << 9; + file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; while (amount_left_to_write > 0) { @@ -1313,38 +1309,20 @@ static int do_write(struct fsg_dev *fsg) if (bh->state == BUF_STATE_EMPTY && get_some_more) { /* Figure out how much we want to get: - * Try to get the remaining amount. - * But don't get more than the buffer size. - * And don't try to go past the end of the file. - * If we're not at a page boundary, - * don't go past the next page. - * If this means getting 0, then we were asked - * to write past the end of file. - * Finally, round down to a block boundary. */ + * Try to get the remaining amount, + * but not more than the buffer size. + */ amount = min(amount_left_to_req, mod_data.buflen); - amount = min((loff_t) amount, curlun->file_length - - usb_offset); - partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, - (unsigned int) PAGE_CACHE_SIZE - partial_page); - - if (amount == 0) { + + /* Beyond the end of the backing file? */ + if (usb_offset >= curlun->file_length) { get_some_more = 0; curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = usb_offset >> 9; + curlun->sense_data_info = usb_offset >> curlun->blkbits; curlun->info_valid = 1; continue; } - amount -= (amount & 511); - if (amount == 0) { - - /* Why were we were asked to transfer a - * partial block? */ - get_some_more = 0; - continue; - } /* Get the next buffer */ usb_offset += amount; @@ -1353,8 +1331,10 @@ static int do_write(struct fsg_dev *fsg) if (amount_left_to_req == 0) get_some_more = 0; - /* amount is always divisible by 512, hence by - * the bulk-out maxpacket size */ + /* Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by + * the bulk-out maxpacket size. + */ bh->outreq->length = bh->bulk_out_intended_length = amount; bh->outreq->short_not_ok = 1; @@ -1376,7 +1356,7 @@ static int do_write(struct fsg_dev *fsg) /* Did something go wrong with the transfer? */ if (bh->outreq->status != 0) { curlun->sense_data = SS_COMMUNICATION_FAILURE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1390,6 +1370,11 @@ static int do_write(struct fsg_dev *fsg) amount = curlun->file_length - file_offset; } + /* Don't write a partial block */ + amount = round_down(amount, curlun->blksize); + if (amount == 0) + goto empty_write; + /* Perform the write */ file_offset_tmp = file_offset; nwritten = vfs_write(curlun->filp, @@ -1408,8 +1393,7 @@ static int do_write(struct fsg_dev *fsg) } else if (nwritten < amount) { LDBG(curlun, "partial file write: %d/%u\n", (int) nwritten, amount); - nwritten -= (nwritten & 511); - // Round down to a block + nwritten = round_down(nwritten, curlun->blksize); } file_offset += nwritten; amount_left_to_write -= nwritten; @@ -1418,11 +1402,12 @@ static int do_write(struct fsg_dev *fsg) /* If an error occurred, report it and its position */ if (nwritten < amount) { curlun->sense_data = SS_WRITE_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } + empty_write: /* Did the host decide to stop early? */ if (bh->outreq->actual != bh->outreq->length) { fsg->short_packet_received = 1; @@ -1500,8 +1485,8 @@ static int do_verify(struct fsg_dev *fsg) return -EIO; // No default reply /* Prepare to carry out the file verify */ - amount_left = verification_length << 9; - file_offset = ((loff_t) lba) << 9; + amount_left = verification_length << curlun->blkbits; + file_offset = ((loff_t) lba) << curlun->blkbits; /* Write out all the dirty buffers before invalidating them */ fsg_lun_fsync_sub(curlun); @@ -1519,15 +1504,14 @@ static int do_verify(struct fsg_dev *fsg) * Try to read the remaining amount, but not more than * the buffer size. * And don't try to read past the end of the file. - * If this means reading 0 then we were asked to read - * past the end of file. */ + */ amount = min((unsigned int) amount_left, mod_data.buflen); amount = min((loff_t) amount, curlun->file_length - file_offset); if (amount == 0) { curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1550,11 +1534,11 @@ static int do_verify(struct fsg_dev *fsg) } else if (nread < amount) { LDBG(curlun, "partial file verify: %d/%u\n", (int) nread, amount); - nread -= (nread & 511); // Round down to a sector + nread = round_down(nread, curlun->blksize); } if (nread == 0) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->sense_data_info = file_offset >> 9; + curlun->sense_data_info = file_offset >> curlun->blkbits; curlun->info_valid = 1; break; } @@ -1668,7 +1652,7 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); /* Max logical block */ - put_unaligned_be32(512, &buf[4]); /* Block length */ + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ return 8; } @@ -1890,7 +1874,7 @@ static int do_read_format_capacities(struct fsg_dev *fsg, put_unaligned_be32(curlun->num_sectors, &buf[0]); /* Number of blocks */ - put_unaligned_be32(512, &buf[4]); /* Block length */ + put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ buf[4] = 0x02; /* Current capacity */ return 12; } @@ -1983,8 +1967,10 @@ static int throw_away_data(struct fsg_dev *fsg) amount = min(fsg->usb_amount_left, (u32) mod_data.buflen); - /* amount is always divisible by 512, hence by - * the bulk-out maxpacket size */ + /* Except at the end of the transfer, amount will be + * equal to the buffer size, which is divisible by + * the bulk-out maxpacket size. + */ bh->outreq->length = bh->bulk_out_intended_length = amount; bh->outreq->short_not_ok = 1; @@ -2415,7 +2401,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case READ_6: i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1, "READ(6)")) == 0) @@ -2424,7 +2410,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case READ_10: fsg->data_size_from_cmnd = - get_unaligned_be16(&fsg->cmnd[7]) << 9; + get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)")) == 0) @@ -2433,7 +2419,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case READ_12: fsg->data_size_from_cmnd = - get_unaligned_be32(&fsg->cmnd[6]) << 9; + get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)")) == 0) @@ -2519,7 +2505,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case WRITE_6: i = fsg->cmnd[4]; - fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1, "WRITE(6)")) == 0) @@ -2528,7 +2514,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case WRITE_10: fsg->data_size_from_cmnd = - get_unaligned_be16(&fsg->cmnd[7]) << 9; + get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)")) == 0) @@ -2537,7 +2523,7 @@ static int do_scsi_command(struct fsg_dev *fsg) case WRITE_12: fsg->data_size_from_cmnd = - get_unaligned_be32(&fsg->cmnd[6]) << 9; + get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)")) == 0) @@ -2752,7 +2738,7 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting) reset: /* Deallocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &fsg->buffhds[i]; if (bh->inreq) { @@ -2813,7 +2799,7 @@ reset: } /* Allocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &fsg->buffhds[i]; if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) @@ -2902,7 +2888,7 @@ static void handle_exception(struct fsg_dev *fsg) /* Cancel all the pending transfers */ if (fsg->intreq_busy) usb_ep_dequeue(fsg->intr_in, fsg->intreq); - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &fsg->buffhds[i]; if (bh->inreq_busy) usb_ep_dequeue(fsg->bulk_in, bh->inreq); @@ -2913,7 +2899,7 @@ static void handle_exception(struct fsg_dev *fsg) /* Wait until everything is idle */ for (;;) { num_active = fsg->intreq_busy; - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &fsg->buffhds[i]; num_active += bh->inreq_busy + bh->outreq_busy; } @@ -2935,7 +2921,7 @@ static void handle_exception(struct fsg_dev *fsg) * state, and the exception. Then invoke the handler. */ spin_lock_irq(&fsg->lock); - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { bh = &fsg->buffhds[i]; bh->state = BUF_STATE_EMPTY; } @@ -3165,7 +3151,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) } /* Free the data buffers */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) + for (i = 0; i < fsg_num_buffers; ++i) kfree(fsg->buffhds[i].buf); /* Free the request and buffer for endpoint 0 */ @@ -3453,7 +3439,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) req->complete = ep0_complete; /* Allocate the data buffers */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { + for (i = 0; i < fsg_num_buffers; ++i) { struct fsg_buffhd *bh = &fsg->buffhds[i]; /* Allocate for the bulk-in endpoint. We assume that @@ -3464,7 +3450,7 @@ static int __init fsg_bind(struct usb_gadget *gadget) goto out; bh->next = bh + 1; } - fsg->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->buffhds[0]; + fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0]; /* This should reflect the actual gadget power source */ usb_gadget_set_selfpowered(gadget); @@ -3580,7 +3566,9 @@ static int __init fsg_alloc(void) { struct fsg_dev *fsg; - fsg = kzalloc(sizeof *fsg, GFP_KERNEL); + fsg = kzalloc(sizeof *fsg + + fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL); + if (!fsg) return -ENOMEM; spin_lock_init(&fsg->lock); @@ -3598,6 +3586,10 @@ static int __init fsg_init(void) int rc; struct fsg_dev *fsg; + rc = fsg_num_buffers_validate(); + if (rc != 0) + return rc; + if ((rc = fsg_alloc()) != 0) return rc; fsg = the_fsg; diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c index 571d9730fca..523626274c0 100644 --- a/drivers/usb/gadget/storage_common.c +++ b/drivers/usb/gadget/storage_common.c @@ -43,6 +43,12 @@ * characters rather then a pointer to void. */ +/* + * When USB_GADGET_DEBUG_FILES is defined the module param num_buffers + * sets the number of pipeline buffers (length of the fsg_buffhd array). + * The valid range of num_buffers is: num >= 2 && num <= 4. + */ + #include <linux/usb/storage.h> #include <scsi/scsi.h> @@ -238,6 +244,8 @@ struct fsg_lun { u32 sense_data_info; u32 unit_attention_data; + unsigned int blkbits; /* Bits of logical block size of bound block device */ + unsigned int blksize; /* logical block size of bound block device */ struct device dev; }; @@ -253,8 +261,31 @@ static struct fsg_lun *fsg_lun_from_dev(struct device *dev) #define EP0_BUFSIZE 256 #define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ -/* Number of buffers we will use. 2 is enough for double-buffering */ -#define FSG_NUM_BUFFERS 2 +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + +static unsigned int fsg_num_buffers = CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS; +module_param_named(num_buffers, fsg_num_buffers, uint, S_IRUGO); +MODULE_PARM_DESC(num_buffers, "Number of pipeline buffers"); + +#else + +/* + * Number of buffers we will use. + * 2 is usually enough for good buffering pipeline + */ +#define fsg_num_buffers CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS + +#endif /* CONFIG_USB_DEBUG */ + +/* check if fsg_num_buffers is within a valid range */ +static inline int fsg_num_buffers_validate(void) +{ + if (fsg_num_buffers >= 2 && fsg_num_buffers <= 4) + return 0; + pr_err("fsg_num_buffers %u is out of range (%d to %d)\n", + fsg_num_buffers, 2 ,4); + return -EINVAL; +} /* Default size of buffer length. */ #define FSG_BUFLEN ((u32)16384) @@ -571,13 +602,24 @@ static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) rc = (int) size; goto out; } - num_sectors = size >> 9; /* File size in 512-byte blocks */ + + if (curlun->cdrom) { + curlun->blksize = 2048; + curlun->blkbits = 11; + } else if (inode->i_bdev) { + curlun->blksize = bdev_logical_block_size(inode->i_bdev); + curlun->blkbits = blksize_bits(curlun->blksize); + } else { + curlun->blksize = 512; + curlun->blkbits = 9; + } + + num_sectors = size >> curlun->blkbits; /* File size in logic-block-size blocks */ min_sectors = 1; if (curlun->cdrom) { - num_sectors &= ~3; /* Reduce to a multiple of 2048 */ - min_sectors = 300*4; /* Smallest track is 300 frames */ - if (num_sectors >= 256*60*75*4) { - num_sectors = (256*60*75 - 1) * 4; + min_sectors = 300; /* Smallest track is 300 frames */ + if (num_sectors >= 256*60*75) { + num_sectors = 256*60*75 - 1; LINFO(curlun, "file too big: %s\n", filename); LINFO(curlun, "using only first %d blocks\n", (int) num_sectors); diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 3f79e7f9a9e..b08b9cad85a 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -634,6 +634,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) u16 len; u16 csr = musb_readw(epio, MUSB_RXCSR); struct musb_hw_ep *hw_ep = &musb->endpoints[epnum]; + u8 use_mode_1; if (hw_ep->is_shared_fifo) musb_ep = &hw_ep->ep_in; @@ -683,6 +684,18 @@ static void rxstate(struct musb *musb, struct musb_request *req) if (csr & MUSB_RXCSR_RXPKTRDY) { len = musb_readw(epio, MUSB_RXCOUNT); + + /* + * Enable Mode 1 on RX transfers only when short_not_ok flag + * is set. Currently short_not_ok flag is set only from + * file_storage and f_mass_storage drivers + */ + + if (request->short_not_ok && len == musb_ep->packet_sz) + use_mode_1 = 1; + else + use_mode_1 = 0; + if (request->actual < request->length) { #ifdef CONFIG_USB_INVENTRA_DMA if (is_buffer_mapped(req)) { @@ -714,37 +727,41 @@ static void rxstate(struct musb *musb, struct musb_request *req) * then becomes usable as a runtime "use mode 1" hint... */ - csr |= MUSB_RXCSR_DMAENAB; -#ifdef USE_MODE1 - csr |= MUSB_RXCSR_AUTOCLEAR; - /* csr |= MUSB_RXCSR_DMAMODE; */ - - /* this special sequence (enabling and then - * disabling MUSB_RXCSR_DMAMODE) is required - * to get DMAReq to activate - */ - musb_writew(epio, MUSB_RXCSR, - csr | MUSB_RXCSR_DMAMODE); -#else - if (!musb_ep->hb_mult && - musb_ep->hw_ep->rx_double_buffered) + /* Experimental: Mode1 works with mass storage use cases */ + if (use_mode_1) { csr |= MUSB_RXCSR_AUTOCLEAR; -#endif - musb_writew(epio, MUSB_RXCSR, csr); + musb_writew(epio, MUSB_RXCSR, csr); + csr |= MUSB_RXCSR_DMAENAB; + musb_writew(epio, MUSB_RXCSR, csr); + + /* + * this special sequence (enabling and then + * disabling MUSB_RXCSR_DMAMODE) is required + * to get DMAReq to activate + */ + musb_writew(epio, MUSB_RXCSR, + csr | MUSB_RXCSR_DMAMODE); + musb_writew(epio, MUSB_RXCSR, csr); + + } else { + if (!musb_ep->hb_mult && + musb_ep->hw_ep->rx_double_buffered) + csr |= MUSB_RXCSR_AUTOCLEAR; + csr |= MUSB_RXCSR_DMAENAB; + musb_writew(epio, MUSB_RXCSR, csr); + } if (request->actual < request->length) { int transfer_size = 0; -#ifdef USE_MODE1 - transfer_size = min(request->length - request->actual, - channel->max_len); -#else - transfer_size = min(request->length - request->actual, - (unsigned)len); -#endif - if (transfer_size <= musb_ep->packet_sz) - musb_ep->dma->desired_mode = 0; - else + if (use_mode_1) { + transfer_size = min(request->length - request->actual, + channel->max_len); musb_ep->dma->desired_mode = 1; + } else { + transfer_size = min(request->length - request->actual, + (unsigned)len); + musb_ep->dma->desired_mode = 0; + } use_dma = c->channel_program( channel, |