diff options
Diffstat (limited to 'drivers')
155 files changed, 4364 insertions, 1782 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index e1284b8dc6ee..3270d3c8ba4e 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -908,9 +908,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) device->cap._DDC = 1; } - if (acpi_video_init_brightness(device)) - return; - if (acpi_video_backlight_support()) { struct backlight_properties props; struct pci_dev *pdev; @@ -920,6 +917,9 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) static int count = 0; char *name; + result = acpi_video_init_brightness(device); + if (result) + return; name = kasprintf(GFP_KERNEL, "acpi_video%d", count); if (!name) return; @@ -979,11 +979,6 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device) if (result) printk(KERN_ERR PREFIX "Create sysfs link\n"); - } else { - /* Remove the brightness object. */ - kfree(device->brightness->levels); - kfree(device->brightness); - device->brightness = NULL; } } diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 1c41722bb7e2..20fd337a5731 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -289,24 +289,24 @@ static int sata_pmp_configure(struct ata_device *dev, int print_info) /* Disable sending Early R_OK. * With "cached read" HDD testing and multiple ports busy on a SATA - * host controller, 3726 PMP will very rarely drop a deferred + * host controller, 3x26 PMP will very rarely drop a deferred * R_OK that was intended for the host. Symptom will be all * 5 drives under test will timeout, get reset, and recover. */ - if (vendor == 0x1095 && devid == 0x3726) { + if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) { u32 reg; err_mask = sata_pmp_read(&ap->link, PMP_GSCR_SII_POL, ®); if (err_mask) { rc = -EIO; - reason = "failed to read Sil3726 Private Register"; + reason = "failed to read Sil3x26 Private Register"; goto fail; } reg &= ~0x1; err_mask = sata_pmp_write(&ap->link, PMP_GSCR_SII_POL, reg); if (err_mask) { rc = -EIO; - reason = "failed to write Sil3726 Private Register"; + reason = "failed to write Sil3x26 Private Register"; goto fail; } } @@ -383,8 +383,8 @@ static void sata_pmp_quirks(struct ata_port *ap) u16 devid = sata_pmp_gscr_devid(gscr); struct ata_link *link; - if (vendor == 0x1095 && devid == 0x3726) { - /* sil3726 quirks */ + if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) { + /* sil3x26 quirks */ ata_for_each_link(link, ap, EDGE) { /* link reports offline after LPM */ link->flags |= ATA_LFLAG_NO_LPM; diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 19720a0a4a65..851bd3f43ac6 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c @@ -293,6 +293,7 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host, { struct sata_fsl_host_priv *host_priv = host->private_data; void __iomem *hcr_base = host_priv->hcr_base; + unsigned long flags; if (count > ICC_MAX_INT_COUNT_THRESHOLD) count = ICC_MAX_INT_COUNT_THRESHOLD; @@ -305,12 +306,12 @@ static void fsl_sata_set_irq_coalescing(struct ata_host *host, (count > ICC_MIN_INT_COUNT_THRESHOLD)) ticks = ICC_SAFE_INT_TICKS; - spin_lock(&host->lock); + spin_lock_irqsave(&host->lock, flags); iowrite32((count << 24 | ticks), hcr_base + ICC); intr_coalescing_count = count; intr_coalescing_ticks = ticks; - spin_unlock(&host->lock); + spin_unlock_irqrestore(&host->lock, flags); DPRINTK("interrupt coalescing, count = 0x%x, ticks = %x\n", intr_coalescing_count, intr_coalescing_ticks); diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c index d047d92a456f..e9a4f46d962e 100644 --- a/drivers/ata/sata_highbank.c +++ b/drivers/ata/sata_highbank.c @@ -86,11 +86,11 @@ struct ecx_plat_data { #define SGPIO_SIGNALS 3 #define ECX_ACTIVITY_BITS 0x300000 -#define ECX_ACTIVITY_SHIFT 2 +#define ECX_ACTIVITY_SHIFT 0 #define ECX_LOCATE_BITS 0x80000 #define ECX_LOCATE_SHIFT 1 #define ECX_FAULT_BITS 0x400000 -#define ECX_FAULT_SHIFT 0 +#define ECX_FAULT_SHIFT 2 static inline int sgpio_bit_shift(struct ecx_plat_data *pdata, u32 port, u32 shift) { diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 99cb944a002d..4d45dba7fb8f 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -906,16 +906,10 @@ bio_pageinc(struct bio *bio) int i; bio_for_each_segment(bv, bio, i) { - page = bv->bv_page; /* Non-zero page count for non-head members of - * compound pages is no longer allowed by the kernel, - * but this has never been seen here. + * compound pages is no longer allowed by the kernel. */ - if (unlikely(PageCompound(page))) - if (compound_trans_head(page) != page) { - pr_crit("page tail used for block I/O\n"); - BUG(); - } + page = compound_trans_head(bv->bv_page); atomic_inc(&page->_count); } } @@ -924,10 +918,13 @@ static void bio_pagedec(struct bio *bio) { struct bio_vec *bv; + struct page *page; int i; - bio_for_each_segment(bv, bio, i) - atomic_dec(&bv->bv_page->_count); + bio_for_each_segment(bv, bio, i) { + page = compound_trans_head(bv->bv_page); + atomic_dec(&page->_count); + } } static void diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index 1bdb882c845b..4e5739773c33 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -581,11 +581,15 @@ struct samsung_div_clock exynos4x12_div_clks[] __initdata = { DIV(none, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4), DIV(none, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8), DIV(none, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4), - DIV(div_isp0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3), - DIV(div_isp1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3), + DIV_F(div_isp0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3, + CLK_GET_RATE_NOCACHE, 0), + DIV_F(div_isp1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3, + CLK_GET_RATE_NOCACHE, 0), DIV(none, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3), - DIV(div_mcuisp0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1, 4, 3), - DIV(div_mcuisp1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, 8, 3), + DIV_F(div_mcuisp0, "div_mcuisp0", "aclk400_mcuisp", E4X12_DIV_ISP1, + 4, 3, CLK_GET_RATE_NOCACHE, 0), + DIV_F(div_mcuisp1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, + 8, 3, CLK_GET_RATE_NOCACHE, 0), DIV(sclk_fimg2d, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4), }; @@ -863,57 +867,57 @@ struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = { GATE_DA(i2s0, "samsung-i2s.0", "i2s0", "aclk100", E4X12_GATE_IP_MAUDIO, 3, 0, 0, "iis"), GATE(fimc_isp, "isp", "aclk200", E4X12_GATE_ISP0, 0, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(fimc_drc, "drc", "aclk200", E4X12_GATE_ISP0, 1, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(fimc_fd, "fd", "aclk200", E4X12_GATE_ISP0, 2, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(fimc_lite0, "lite0", "aclk200", E4X12_GATE_ISP0, 3, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(fimc_lite1, "lite1", "aclk200", E4X12_GATE_ISP0, 4, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(mcuisp, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(gicisp, "gicisp", "aclk200", E4X12_GATE_ISP0, 7, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(smmu_isp, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(smmu_drc, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(smmu_fd, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(smmu_lite0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(smmu_lite1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(ppmuispmx, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(ppmuispx, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(mcuctl_isp, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(mpwm_isp, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(i2c0_isp, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(i2c1_isp, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(mtcadc_isp, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(pwm_isp, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(wdt_isp, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(uart_isp, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(asyncaxim, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(smmu_ispcx, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(spi0_isp, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(spi1_isp, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, - CLK_IGNORE_UNUSED, 0), + CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(g2d, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0), }; diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c index 5c205b60a82a..089d3e30e221 100644 --- a/drivers/clk/zynq/clkc.c +++ b/drivers/clk/zynq/clkc.c @@ -71,6 +71,7 @@ static DEFINE_SPINLOCK(armpll_lock); static DEFINE_SPINLOCK(ddrpll_lock); static DEFINE_SPINLOCK(iopll_lock); static DEFINE_SPINLOCK(armclk_lock); +static DEFINE_SPINLOCK(swdtclk_lock); static DEFINE_SPINLOCK(ddrclk_lock); static DEFINE_SPINLOCK(dciclk_lock); static DEFINE_SPINLOCK(gem0clk_lock); @@ -293,7 +294,7 @@ static void __init zynq_clk_setup(struct device_node *np) } clks[swdt] = clk_register_mux(NULL, clk_output_name[swdt], swdt_ext_clk_mux_parents, 2, CLK_SET_RATE_PARENT, - SLCR_SWDT_CLK_SEL, 0, 1, 0, &gem0clk_lock); + SLCR_SWDT_CLK_SEL, 0, 1, 0, &swdtclk_lock); /* DDR clocks */ clk = clk_register_divider(NULL, "ddr2x_div", "ddrpll", 0, @@ -364,8 +365,9 @@ static void __init zynq_clk_setup(struct device_node *np) CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 20, 6, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, &gem0clk_lock); - clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2, 0, - SLCR_GEM0_CLK_CTRL, 6, 1, 0, &gem0clk_lock); + clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2, + CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 6, 1, 0, + &gem0clk_lock); clks[gem0] = clk_register_gate(NULL, clk_output_name[gem0], "gem0_emio_mux", CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 0, 0, &gem0clk_lock); @@ -386,8 +388,9 @@ static void __init zynq_clk_setup(struct device_node *np) CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 20, 6, CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, &gem1clk_lock); - clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2, 0, - SLCR_GEM1_CLK_CTRL, 6, 1, 0, &gem1clk_lock); + clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2, + CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 6, 1, 0, + &gem1clk_lock); clks[gem1] = clk_register_gate(NULL, clk_output_name[gem1], "gem1_emio_mux", CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 0, 0, &gem1clk_lock); diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 19e36603b23b..3bc8414533c9 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -500,7 +500,8 @@ static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo, &status)) goto log_fail; - while (status == SDVO_CMD_STATUS_PENDING && retry--) { + while ((status == SDVO_CMD_STATUS_PENDING || + status == SDVO_CMD_STATUS_TARGET_NOT_SPECIFIED) && retry--) { udelay(15); if (!psb_intel_sdvo_read_byte(psb_intel_sdvo, SDVO_I2C_CMD_STATUS, diff --git a/drivers/gpu/drm/i915/i915_gem_dmabuf.c b/drivers/gpu/drm/i915/i915_gem_dmabuf.c index dc53a527126b..9e6578330801 100644 --- a/drivers/gpu/drm/i915/i915_gem_dmabuf.c +++ b/drivers/gpu/drm/i915/i915_gem_dmabuf.c @@ -85,9 +85,17 @@ static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, struct sg_table *sg, enum dma_data_direction dir) { + struct drm_i915_gem_object *obj = attachment->dmabuf->priv; + + mutex_lock(&obj->base.dev->struct_mutex); + dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir); sg_free_table(sg); kfree(sg); + + i915_gem_object_unpin_pages(obj); + + mutex_unlock(&obj->base.dev->struct_mutex); } static void i915_gem_dmabuf_release(struct dma_buf *dma_buf) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6f514297c483..53cddd985406 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -752,6 +752,8 @@ will not assert AGPBUSY# and will only be delivered when out of C3. */ #define INSTPM_FORCE_ORDERING (1<<7) /* GEN6+ */ +#define INSTPM_TLB_INVALIDATE (1<<9) +#define INSTPM_SYNC_FLUSH (1<<5) #define ACTHD 0x020c8 #define FW_BLC 0x020d8 #define FW_BLC2 0x020dc diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e38b45786653..be79f477a38f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10042,6 +10042,8 @@ struct intel_display_error_state { u32 power_well_driver; + int num_transcoders; + struct intel_cursor_error_state { u32 control; u32 position; @@ -10050,16 +10052,7 @@ struct intel_display_error_state { } cursor[I915_MAX_PIPES]; struct intel_pipe_error_state { - enum transcoder cpu_transcoder; - u32 conf; u32 source; - - u32 htotal; - u32 hblank; - u32 hsync; - u32 vtotal; - u32 vblank; - u32 vsync; } pipe[I915_MAX_PIPES]; struct intel_plane_error_state { @@ -10071,6 +10064,19 @@ struct intel_display_error_state { u32 surface; u32 tile_offset; } plane[I915_MAX_PIPES]; + + struct intel_transcoder_error_state { + enum transcoder cpu_transcoder; + + u32 conf; + + u32 htotal; + u32 hblank; + u32 hsync; + u32 vtotal; + u32 vblank; + u32 vsync; + } transcoder[4]; }; struct intel_display_error_state * @@ -10078,9 +10084,17 @@ intel_display_capture_error_state(struct drm_device *dev) { drm_i915_private_t *dev_priv = dev->dev_private; struct intel_display_error_state *error; - enum transcoder cpu_transcoder; + int transcoders[] = { + TRANSCODER_A, + TRANSCODER_B, + TRANSCODER_C, + TRANSCODER_EDP, + }; int i; + if (INTEL_INFO(dev)->num_pipes == 0) + return NULL; + error = kmalloc(sizeof(*error), GFP_ATOMIC); if (error == NULL) return NULL; @@ -10089,9 +10103,6 @@ intel_display_capture_error_state(struct drm_device *dev) error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER); for_each_pipe(i) { - cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, i); - error->pipe[i].cpu_transcoder = cpu_transcoder; - if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) { error->cursor[i].control = I915_READ(CURCNTR(i)); error->cursor[i].position = I915_READ(CURPOS(i)); @@ -10115,14 +10126,25 @@ intel_display_capture_error_state(struct drm_device *dev) error->plane[i].tile_offset = I915_READ(DSPTILEOFF(i)); } - error->pipe[i].conf = I915_READ(PIPECONF(cpu_transcoder)); error->pipe[i].source = I915_READ(PIPESRC(i)); - error->pipe[i].htotal = I915_READ(HTOTAL(cpu_transcoder)); - error->pipe[i].hblank = I915_READ(HBLANK(cpu_transcoder)); - error->pipe[i].hsync = I915_READ(HSYNC(cpu_transcoder)); - error->pipe[i].vtotal = I915_READ(VTOTAL(cpu_transcoder)); - error->pipe[i].vblank = I915_READ(VBLANK(cpu_transcoder)); - error->pipe[i].vsync = I915_READ(VSYNC(cpu_transcoder)); + } + + error->num_transcoders = INTEL_INFO(dev)->num_pipes; + if (HAS_DDI(dev_priv->dev)) + error->num_transcoders++; /* Account for eDP. */ + + for (i = 0; i < error->num_transcoders; i++) { + enum transcoder cpu_transcoder = transcoders[i]; + + error->transcoder[i].cpu_transcoder = cpu_transcoder; + + error->transcoder[i].conf = I915_READ(PIPECONF(cpu_transcoder)); + error->transcoder[i].htotal = I915_READ(HTOTAL(cpu_transcoder)); + error->transcoder[i].hblank = I915_READ(HBLANK(cpu_transcoder)); + error->transcoder[i].hsync = I915_READ(HSYNC(cpu_transcoder)); + error->transcoder[i].vtotal = I915_READ(VTOTAL(cpu_transcoder)); + error->transcoder[i].vblank = I915_READ(VBLANK(cpu_transcoder)); + error->transcoder[i].vsync = I915_READ(VSYNC(cpu_transcoder)); } /* In the code above we read the registers without checking if the power @@ -10144,22 +10166,16 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, { int i; + if (!error) + return; + err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes); if (HAS_POWER_WELL(dev)) err_printf(m, "PWR_WELL_CTL2: %08x\n", error->power_well_driver); for_each_pipe(i) { err_printf(m, "Pipe [%d]:\n", i); - err_printf(m, " CPU transcoder: %c\n", - transcoder_name(error->pipe[i].cpu_transcoder)); - err_printf(m, " CONF: %08x\n", error->pipe[i].conf); err_printf(m, " SRC: %08x\n", error->pipe[i].source); - err_printf(m, " HTOTAL: %08x\n", error->pipe[i].htotal); - err_printf(m, " HBLANK: %08x\n", error->pipe[i].hblank); - err_printf(m, " HSYNC: %08x\n", error->pipe[i].hsync); - err_printf(m, " VTOTAL: %08x\n", error->pipe[i].vtotal); - err_printf(m, " VBLANK: %08x\n", error->pipe[i].vblank); - err_printf(m, " VSYNC: %08x\n", error->pipe[i].vsync); err_printf(m, "Plane [%d]:\n", i); err_printf(m, " CNTR: %08x\n", error->plane[i].control); @@ -10180,5 +10196,17 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " POS: %08x\n", error->cursor[i].position); err_printf(m, " BASE: %08x\n", error->cursor[i].base); } + + for (i = 0; i < error->num_transcoders; i++) { + err_printf(m, " CPU transcoder: %c\n", + transcoder_name(error->transcoder[i].cpu_transcoder)); + err_printf(m, " CONF: %08x\n", error->transcoder[i].conf); + err_printf(m, " HTOTAL: %08x\n", error->transcoder[i].htotal); + err_printf(m, " HBLANK: %08x\n", error->transcoder[i].hblank); + err_printf(m, " HSYNC: %08x\n", error->transcoder[i].hsync); + err_printf(m, " VTOTAL: %08x\n", error->transcoder[i].vtotal); + err_printf(m, " VBLANK: %08x\n", error->transcoder[i].vblank); + err_printf(m, " VSYNC: %08x\n", error->transcoder[i].vsync); + } } #endif diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 664118d8c1d6..079ef0129e74 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -968,6 +968,18 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring) I915_WRITE(mmio, (u32)ring->status_page.gfx_addr); POSTING_READ(mmio); + + /* Flush the TLB for this page */ + if (INTEL_INFO(dev)->gen >= 6) { + u32 reg = RING_INSTPM(ring->mmio_base); + I915_WRITE(reg, + _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE | + INSTPM_SYNC_FLUSH)); + if (wait_for((I915_READ(reg) & INSTPM_SYNC_FLUSH) == 0, + 1000)) + DRM_ERROR("%s: wait for SyncFlush to complete for TLB invalidation timed out\n", + ring->name); + } } static int diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c index d8291724dbd4..7a4e0891c5f8 100644 --- a/drivers/gpu/drm/nouveau/core/core/mm.c +++ b/drivers/gpu/drm/nouveau/core/core/mm.c @@ -98,6 +98,8 @@ nouveau_mm_head(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min, u32 splitoff; u32 s, e; + BUG_ON(!type); + list_for_each_entry(this, &mm->free, fl_entry) { e = this->offset + this->length; s = this->offset; @@ -162,6 +164,8 @@ nouveau_mm_tail(struct nouveau_mm *mm, u8 type, u32 size_max, u32 size_min, struct nouveau_mm_node *prev, *this, *next; u32 mask = align - 1; + BUG_ON(!type); + list_for_each_entry_reverse(this, &mm->free, fl_entry) { u32 e = this->offset + this->length; u32 s = this->offset; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h index d5502267c30f..9d2cd2006250 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h @@ -20,8 +20,8 @@ nouveau_mc(void *obj) return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC]; } -#define nouveau_mc_create(p,e,o,d) \ - nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nouveau_mc_create(p,e,o,m,d) \ + nouveau_mc_create_((p), (e), (o), (m), sizeof(**d), (void **)d) #define nouveau_mc_destroy(p) ({ \ struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc)); \ }) @@ -33,7 +33,8 @@ nouveau_mc(void *obj) }) int nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, void **); + struct nouveau_oclass *, const struct nouveau_mc_intr *, + int, void **); void _nouveau_mc_dtor(struct nouveau_object *); int _nouveau_mc_init(struct nouveau_object *); int _nouveau_mc_fini(struct nouveau_object *, bool); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c index 19e3a9a63a02..ab7ef0ac9e34 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c @@ -40,15 +40,15 @@ nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, return ret; switch (pfb914 & 0x00000003) { - case 0x00000000: pfb->ram->type = NV_MEM_TYPE_DDR1; break; - case 0x00000001: pfb->ram->type = NV_MEM_TYPE_DDR2; break; - case 0x00000002: pfb->ram->type = NV_MEM_TYPE_GDDR3; break; + case 0x00000000: ram->type = NV_MEM_TYPE_DDR1; break; + case 0x00000001: ram->type = NV_MEM_TYPE_DDR2; break; + case 0x00000002: ram->type = NV_MEM_TYPE_GDDR3; break; case 0x00000003: break; } - pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; - pfb->ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - pfb->ram->tags = nv_rd32(pfb, 0x100320); + ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; + ram->tags = nv_rd32(pfb, 0x100320); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c index 7192aa6e5577..63a6aab86028 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c @@ -38,8 +38,8 @@ nv4e_ram_create(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - pfb->ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; - pfb->ram->type = NV_MEM_TYPE_STOLEN; + ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->type = NV_MEM_TYPE_STOLEN; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c index bcca883018f4..cce65cc56514 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c @@ -30,8 +30,9 @@ struct nvc0_ltcg_priv { struct nouveau_ltcg base; u32 part_nr; u32 subp_nr; - struct nouveau_mm tags; u32 num_tags; + u32 tag_base; + struct nouveau_mm tags; struct nouveau_mm_node *tag_ram; }; @@ -117,10 +118,6 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) u32 tag_size, tag_margin, tag_align; int ret; - nv_wr32(priv, 0x17e8d8, priv->part_nr); - if (nv_device(pfb)->card_type >= NV_E0) - nv_wr32(priv, 0x17e000, priv->part_nr); - /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ priv->num_tags = (pfb->ram->size >> 17) / 4; if (priv->num_tags > (1 << 17)) @@ -142,7 +139,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) tag_size += tag_align; tag_size = (tag_size + 0xfff) >> 12; /* round up */ - ret = nouveau_mm_tail(&pfb->vram, 0, tag_size, tag_size, 1, + ret = nouveau_mm_tail(&pfb->vram, 1, tag_size, tag_size, 1, &priv->tag_ram); if (ret) { priv->num_tags = 0; @@ -152,7 +149,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) tag_base += tag_align - 1; ret = do_div(tag_base, tag_align); - nv_wr32(priv, 0x17e8d4, tag_base); + priv->tag_base = tag_base; } ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1); @@ -182,8 +179,6 @@ nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, } priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28; - nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ - ret = nvc0_ltcg_init_tag_ram(pfb, priv); if (ret) return ret; @@ -209,13 +204,32 @@ nvc0_ltcg_dtor(struct nouveau_object *object) nouveau_ltcg_destroy(ltcg); } +static int +nvc0_ltcg_init(struct nouveau_object *object) +{ + struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object; + struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + int ret; + + ret = nouveau_ltcg_init(ltcg); + if (ret) + return ret; + + nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ + nv_wr32(priv, 0x17e8d8, priv->part_nr); + if (nv_device(ltcg)->card_type >= NV_E0) + nv_wr32(priv, 0x17e000, priv->part_nr); + nv_wr32(priv, 0x17e8d4, priv->tag_base); + return 0; +} + struct nouveau_oclass nvc0_ltcg_oclass = { .handle = NV_SUBDEV(LTCG, 0xc0), .ofuncs = &(struct nouveau_ofuncs) { .ctor = nvc0_ltcg_ctor, .dtor = nvc0_ltcg_dtor, - .init = _nouveau_ltcg_init, + .init = nvc0_ltcg_init, .fini = _nouveau_ltcg_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c index 1c0330b8c9a4..ec9cd6f10f91 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c @@ -80,7 +80,9 @@ _nouveau_mc_dtor(struct nouveau_object *object) int nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, int length, void **pobject) + struct nouveau_oclass *oclass, + const struct nouveau_mc_intr *intr_map, + int length, void **pobject) { struct nouveau_device *device = nv_device(parent); struct nouveau_mc *pmc; @@ -92,6 +94,8 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + pmc->intr_map = intr_map; + ret = request_irq(device->pdev->irq, nouveau_mc_intr, IRQF_SHARED, "nouveau", pmc); if (ret < 0) diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c index 8c769715227b..64aa4edb0d9d 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c @@ -50,12 +50,11 @@ nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv04_mc_priv *priv; int ret; - ret = nouveau_mc_create(parent, engine, oclass, &priv); + ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.intr_map = nv04_mc_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c index 51919371810f..d9891782bf28 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c @@ -36,12 +36,11 @@ nv44_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv44_mc_priv *priv; int ret; - ret = nouveau_mc_create(parent, engine, oclass, &priv); + ret = nouveau_mc_create(parent, engine, oclass, nv04_mc_intr, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.intr_map = nv04_mc_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c index f25fc5fc7dd1..2b1afe225db8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c @@ -53,12 +53,11 @@ nv50_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv50_mc_priv *priv; int ret; - ret = nouveau_mc_create(parent, engine, oclass, &priv); + ret = nouveau_mc_create(parent, engine, oclass, nv50_mc_intr, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.intr_map = nv50_mc_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c index e82fd21b5041..0d57b4d3e001 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c @@ -54,12 +54,11 @@ nv98_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nv98_mc_priv *priv; int ret; - ret = nouveau_mc_create(parent, engine, oclass, &priv); + ret = nouveau_mc_create(parent, engine, oclass, nv98_mc_intr, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.intr_map = nv98_mc_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c index c5da3babbc62..104175c5a2dd 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c @@ -57,12 +57,11 @@ nvc0_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvc0_mc_priv *priv; int ret; - ret = nouveau_mc_create(parent, engine, oclass, &priv); + ret = nouveau_mc_create(parent, engine, oclass, nvc0_mc_intr, &priv); *pobject = nv_object(priv); if (ret) return ret; - priv->base.intr_map = nvc0_mc_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 0782bd2f1e04..6a13ffb53bdb 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -606,6 +606,24 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) regp->ramdac_a34 = 0x1; } +static int +nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) +{ + struct nv04_display *disp = nv04_display(crtc->dev); + struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + int ret; + + ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); + if (ret == 0) { + if (disp->image[nv_crtc->index]) + nouveau_bo_unpin(disp->image[nv_crtc->index]); + nouveau_bo_ref(nvfb->nvbo, &disp->image[nv_crtc->index]); + } + + return ret; +} + /** * Sets up registers for the given mode/adjusted_mode pair. * @@ -622,10 +640,15 @@ nv_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_device *dev = crtc->dev; struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nouveau_drm *drm = nouveau_drm(dev); + int ret; NV_DEBUG(drm, "CTRC mode on CRTC %d:\n", nv_crtc->index); drm_mode_debug_printmodeline(adjusted_mode); + ret = nv_crtc_swap_fbs(crtc, old_fb); + if (ret) + return ret; + /* unlock must come after turning off FP_TG_CONTROL in output_prepare */ nv_lock_vga_crtc_shadow(dev, nv_crtc->index, -1); @@ -722,6 +745,7 @@ static void nv_crtc_commit(struct drm_crtc *crtc) static void nv_crtc_destroy(struct drm_crtc *crtc) { + struct nv04_display *disp = nv04_display(crtc->dev); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); if (!nv_crtc) @@ -729,6 +753,10 @@ static void nv_crtc_destroy(struct drm_crtc *crtc) drm_crtc_cleanup(crtc); + if (disp->image[nv_crtc->index]) + nouveau_bo_unpin(disp->image[nv_crtc->index]); + nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]); + nouveau_bo_unmap(nv_crtc->cursor.nvbo); nouveau_bo_unpin(nv_crtc->cursor.nvbo); nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); @@ -754,6 +782,16 @@ nv_crtc_gamma_load(struct drm_crtc *crtc) } static void +nv_crtc_disable(struct drm_crtc *crtc) +{ + struct nv04_display *disp = nv04_display(crtc->dev); + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + if (disp->image[nv_crtc->index]) + nouveau_bo_unpin(disp->image[nv_crtc->index]); + nouveau_bo_ref(NULL, &disp->image[nv_crtc->index]); +} + +static void nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start, uint32_t size) { @@ -791,7 +829,6 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, struct drm_framebuffer *drm_fb; struct nouveau_framebuffer *fb; int arb_burst, arb_lwm; - int ret; NV_DEBUG(drm, "index %d\n", nv_crtc->index); @@ -801,10 +838,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, return 0; } - /* If atomic, we want to switch to the fb we were passed, so - * now we update pointers to do that. (We don't pin; just - * assume we're already pinned and update the base address.) + * now we update pointers to do that. */ if (atomic) { drm_fb = passed_fb; @@ -812,17 +847,6 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, } else { drm_fb = crtc->fb; fb = nouveau_framebuffer(crtc->fb); - /* If not atomic, we can go ahead and pin, and unpin the - * old fb we were passed. - */ - ret = nouveau_bo_pin(fb->nvbo, TTM_PL_FLAG_VRAM); - if (ret) - return ret; - - if (passed_fb) { - struct nouveau_framebuffer *ofb = nouveau_framebuffer(passed_fb); - nouveau_bo_unpin(ofb->nvbo); - } } nv_crtc->fb.offset = fb->nvbo->bo.offset; @@ -877,6 +901,9 @@ static int nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_framebuffer *old_fb) { + int ret = nv_crtc_swap_fbs(crtc, old_fb); + if (ret) + return ret; return nv04_crtc_do_mode_set_base(crtc, old_fb, x, y, false); } @@ -1027,6 +1054,7 @@ static const struct drm_crtc_helper_funcs nv04_crtc_helper_funcs = { .mode_set_base = nv04_crtc_mode_set_base, .mode_set_base_atomic = nv04_crtc_mode_set_base_atomic, .load_lut = nv_crtc_gamma_load, + .disable = nv_crtc_disable, }; int diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h index a0a031dad13f..9928187f0a7d 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h @@ -81,6 +81,7 @@ struct nv04_display { uint32_t saved_vga_font[4][16384]; uint32_t dac_users[4]; struct nouveau_object *core; + struct nouveau_bo *image[2]; }; static inline struct nv04_display * diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 907d20ef6d4d..a03e75deacaf 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -577,6 +577,9 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, ret = nv50_display_flip_next(crtc, fb, chan, 0); if (ret) goto fail_unreserve; + } else { + struct nv04_display *dispnv04 = nv04_display(dev); + nouveau_bo_ref(new_bo, &dispnv04->image[nouveau_crtc(crtc)->index]); } ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c index 3af5bcd0b203..625f80d53dc2 100644 --- a/drivers/gpu/drm/nouveau/nv40_pm.c +++ b/drivers/gpu/drm/nouveau/nv40_pm.c @@ -131,7 +131,7 @@ nv40_calc_pll(struct drm_device *dev, u32 reg, struct nvbios_pll *pll, if (clk < pll->vco1.max_freq) pll->vco2.max_freq = 0; - pclk->pll_calc(pclk, pll, clk, &coef); + ret = pclk->pll_calc(pclk, pll, clk, &coef); if (ret == 0) return -ERANGE; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 274b8e1b889f..9f19259667df 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -2163,7 +2163,7 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v); WREG32(reg, tmp_); \ } while (0) #define WREG32_AND(reg, and) WREG32_P(reg, 0, and) -#define WREG32_OR(reg, or) WREG32_P(reg, or, ~or) +#define WREG32_OR(reg, or) WREG32_P(reg, or, ~(or)) #define WREG32_PLL_P(reg, val, mask) \ do { \ uint32_t tmp_ = RREG32_PLL(reg); \ diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index f1c15754e73c..b79f4f5cdd62 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -356,6 +356,14 @@ static int radeon_uvd_cs_msg(struct radeon_cs_parser *p, struct radeon_bo *bo, return -EINVAL; } + if (bo->tbo.sync_obj) { + r = radeon_fence_wait(bo->tbo.sync_obj, false); + if (r) { + DRM_ERROR("Failed waiting for UVD message (%d)!\n", r); + return r; + } + } + r = radeon_bo_kmap(bo, &ptr); if (r) { DRM_ERROR("Failed mapping the UVD message (%d)!\n", r); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index bcc68ec204ad..f5e92cfcc140 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -744,10 +744,10 @@ static void rv770_init_golden_registers(struct radeon_device *rdev) (const u32)ARRAY_SIZE(r7xx_golden_dyn_gpr_registers)); radeon_program_register_sequence(rdev, rv730_golden_registers, - (const u32)ARRAY_SIZE(rv770_golden_registers)); + (const u32)ARRAY_SIZE(rv730_golden_registers)); radeon_program_register_sequence(rdev, rv730_mgcg_init, - (const u32)ARRAY_SIZE(rv770_mgcg_init)); + (const u32)ARRAY_SIZE(rv730_mgcg_init)); break; case CHIP_RV710: radeon_program_register_sequence(rdev, @@ -758,18 +758,18 @@ static void rv770_init_golden_registers(struct radeon_device *rdev) (const u32)ARRAY_SIZE(r7xx_golden_dyn_gpr_registers)); radeon_program_register_sequence(rdev, rv710_golden_registers, - (const u32)ARRAY_SIZE(rv770_golden_registers)); + (const u32)ARRAY_SIZE(rv710_golden_registers)); radeon_program_register_sequence(rdev, rv710_mgcg_init, - (const u32)ARRAY_SIZE(rv770_mgcg_init)); + (const u32)ARRAY_SIZE(rv710_mgcg_init)); break; case CHIP_RV740: radeon_program_register_sequence(rdev, rv740_golden_registers, - (const u32)ARRAY_SIZE(rv770_golden_registers)); + (const u32)ARRAY_SIZE(rv740_golden_registers)); radeon_program_register_sequence(rdev, rv740_mgcg_init, - (const u32)ARRAY_SIZE(rv770_mgcg_init)); + (const u32)ARRAY_SIZE(rv740_mgcg_init)); break; default: break; diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 5f4749e60b04..c1cd5698b8ae 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -232,7 +232,8 @@ static int adjd_s311_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - ret = adjd_s311_read_data(indio_dev, chan->address, val); + ret = adjd_s311_read_data(indio_dev, + ADJD_S311_DATA_REG(chan->address), val); if (ret < 0) return ret; return IIO_VAL_INT; diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c index dc112a7137fe..4296155090b2 100644 --- a/drivers/md/dm-cache-policy-mq.c +++ b/drivers/md/dm-cache-policy-mq.c @@ -959,23 +959,21 @@ out: return r; } -static void remove_mapping(struct mq_policy *mq, dm_oblock_t oblock) +static void mq_remove_mapping(struct dm_cache_policy *p, dm_oblock_t oblock) { - struct entry *e = hash_lookup(mq, oblock); + struct mq_policy *mq = to_mq_policy(p); + struct entry *e; + + mutex_lock(&mq->lock); + + e = hash_lookup(mq, oblock); BUG_ON(!e || !e->in_cache); del(mq, e); e->in_cache = false; push(mq, e); -} -static void mq_remove_mapping(struct dm_cache_policy *p, dm_oblock_t oblock) -{ - struct mq_policy *mq = to_mq_policy(p); - - mutex_lock(&mq->lock); - remove_mapping(mq, oblock); mutex_unlock(&mq->lock); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 07f257d44a1e..e48cb339c0c6 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3714,11 +3714,17 @@ static int bond_neigh_init(struct neighbour *n) * The bonding ndo_neigh_setup is called at init time beofre any * slave exists. So we must declare proxy setup function which will * be used at run time to resolve the actual slave neigh param setup. + * + * It's also called by master devices (such as vlans) to setup their + * underlying devices. In that case - do nothing, we're already set up from + * our init. */ static int bond_neigh_setup(struct net_device *dev, struct neigh_parms *parms) { - parms->neigh_setup = bond_neigh_init; + /* modify only our neigh_parms */ + if (parms->dev == dev) + parms->neigh_setup = bond_neigh_init; return 0; } diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c index 25723d8ee201..925ab8ec9329 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb.c @@ -649,7 +649,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len) if ((mc->ptr + rec_len) > mc->end) goto decode_failed; - memcpy(cf->data, mc->ptr, rec_len); + memcpy(cf->data, mc->ptr, cf->can_dlc); mc->ptr += rec_len; } diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c index f1b121ee5525..55d79cb53a79 100644 --- a/drivers/net/ethernet/arc/emac_main.c +++ b/drivers/net/ethernet/arc/emac_main.c @@ -199,7 +199,7 @@ static int arc_emac_rx(struct net_device *ndev, int budget) struct arc_emac_priv *priv = netdev_priv(ndev); unsigned int work_done; - for (work_done = 0; work_done <= budget; work_done++) { + for (work_done = 0; work_done < budget; work_done++) { unsigned int *last_rx_bd = &priv->last_rx_bd; struct net_device_stats *stats = &priv->stats; struct buffer_state *rx_buff = &priv->rx_buff[*last_rx_bd]; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index d80e34b8285f..00b88cbfde25 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1333,6 +1333,8 @@ enum { BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN, BNX2X_SP_RTNL_VFPF_STORM_RX_MODE, BNX2X_SP_RTNL_HYPERVISOR_VLAN, + BNX2X_SP_RTNL_TX_STOP, + BNX2X_SP_RTNL_TX_RESUME, }; struct bnx2x_prev_path_list { @@ -1502,6 +1504,7 @@ struct bnx2x { #define BC_SUPPORTS_DCBX_MSG_NON_PMF (1 << 21) #define IS_VF_FLAG (1 << 22) #define INTERRUPTS_ENABLED_FLAG (1 << 23) +#define BC_SUPPORTS_RMMOD_CMD (1 << 24) #define BP_NOMCP(bp) ((bp)->flags & NO_MCP_FLAG) @@ -1830,6 +1833,8 @@ struct bnx2x { int fp_array_size; u32 dump_preset_idx; + bool stats_started; + struct semaphore stats_sema; }; /* Tx queues may be less or equal to Rx queues */ @@ -2451,4 +2456,6 @@ enum bnx2x_pci_bus_speed { BNX2X_PCI_LINK_SPEED_5000 = 5000, BNX2X_PCI_LINK_SPEED_8000 = 8000 }; + +void bnx2x_set_local_cmng(struct bnx2x *bp); #endif /* bnx2x.h */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index 0c94df47e0e8..fcf2761d8828 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -30,10 +30,8 @@ #include "bnx2x_dcb.h" /* forward declarations of dcbx related functions */ -static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp); static void bnx2x_pfc_set_pfc(struct bnx2x *bp); static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp); -static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp); static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp, u32 *set_configuration_ets_pg, u32 *pri_pg_tbl); @@ -425,30 +423,52 @@ static void bnx2x_pfc_set_pfc(struct bnx2x *bp) bnx2x_pfc_clear(bp); } -static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp) +int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp) { struct bnx2x_func_state_params func_params = {NULL}; + int rc; func_params.f_obj = &bp->func_obj; func_params.cmd = BNX2X_F_CMD_TX_STOP; + __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags); + __set_bit(RAMROD_RETRY, &func_params.ramrod_flags); + DP(BNX2X_MSG_DCB, "STOP TRAFFIC\n"); - return bnx2x_func_state_change(bp, &func_params); + + rc = bnx2x_func_state_change(bp, &func_params); + if (rc) { + BNX2X_ERR("Unable to hold traffic for HW configuration\n"); + bnx2x_panic(); + } + + return rc; } -static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp) +int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp) { struct bnx2x_func_state_params func_params = {NULL}; struct bnx2x_func_tx_start_params *tx_params = &func_params.params.tx_start; + int rc; func_params.f_obj = &bp->func_obj; func_params.cmd = BNX2X_F_CMD_TX_START; + __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags); + __set_bit(RAMROD_RETRY, &func_params.ramrod_flags); + bnx2x_dcbx_fw_struct(bp, tx_params); DP(BNX2X_MSG_DCB, "START TRAFFIC\n"); - return bnx2x_func_state_change(bp, &func_params); + + rc = bnx2x_func_state_change(bp, &func_params); + if (rc) { + BNX2X_ERR("Unable to resume traffic after HW configuration\n"); + bnx2x_panic(); + } + + return rc; } static void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp) @@ -744,7 +764,9 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) if (IS_MF(bp)) bnx2x_link_sync_notify(bp); - bnx2x_dcbx_stop_hw_tx(bp); + set_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state); + + schedule_delayed_work(&bp->sp_rtnl_task, 0); return; } @@ -753,7 +775,13 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) bnx2x_pfc_set_pfc(bp); bnx2x_dcbx_update_ets_params(bp); - bnx2x_dcbx_resume_hw_tx(bp); + + /* ets may affect cmng configuration: reinit it in hw */ + bnx2x_set_local_cmng(bp); + + set_bit(BNX2X_SP_RTNL_TX_RESUME, &bp->sp_rtnl_state); + + schedule_delayed_work(&bp->sp_rtnl_task, 0); return; case BNX2X_DCBX_STATE_TX_RELEASED: @@ -2363,21 +2391,24 @@ static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid, case DCB_FEATCFG_ATTR_PG: if (bp->dcbx_local_feat.ets.enabled) *flags |= DCB_FEATCFG_ENABLE; - if (bp->dcbx_error & DCBX_LOCAL_ETS_ERROR) + if (bp->dcbx_error & (DCBX_LOCAL_ETS_ERROR | + DCBX_REMOTE_MIB_ERROR)) *flags |= DCB_FEATCFG_ERROR; break; case DCB_FEATCFG_ATTR_PFC: if (bp->dcbx_local_feat.pfc.enabled) *flags |= DCB_FEATCFG_ENABLE; if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR | - DCBX_LOCAL_PFC_MISMATCH)) + DCBX_LOCAL_PFC_MISMATCH | + DCBX_REMOTE_MIB_ERROR)) *flags |= DCB_FEATCFG_ERROR; break; case DCB_FEATCFG_ATTR_APP: if (bp->dcbx_local_feat.app.enabled) *flags |= DCB_FEATCFG_ENABLE; if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR | - DCBX_LOCAL_APP_MISMATCH)) + DCBX_LOCAL_APP_MISMATCH | + DCBX_REMOTE_MIB_ERROR)) *flags |= DCB_FEATCFG_ERROR; break; default: diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h index 125bd1b6586f..804b8f64463e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h @@ -199,4 +199,7 @@ extern const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops; int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall); #endif /* BCM_DCBNL */ +int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp); +int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp); + #endif /* BNX2X_DCB_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 5018e52ae2ad..32767f6aa33f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -1300,6 +1300,9 @@ struct drv_func_mb { #define DRV_MSG_CODE_EEE_RESULTS_ACK 0xda000000 + #define DRV_MSG_CODE_RMMOD 0xdb000000 + #define REQ_BC_VER_4_RMMOD_CMD 0x0007080f + #define DRV_MSG_CODE_SET_MF_BW 0xe0000000 #define REQ_BC_VER_4_SET_MF_BW 0x00060202 #define DRV_MSG_CODE_SET_MF_BW_ACK 0xe1000000 @@ -1372,6 +1375,8 @@ struct drv_func_mb { #define FW_MSG_CODE_EEE_RESULS_ACK 0xda100000 + #define FW_MSG_CODE_RMMOD_ACK 0xdb100000 + #define FW_MSG_CODE_SET_MF_BW_SENT 0xe0000000 #define FW_MSG_CODE_SET_MF_BW_DONE 0xe1000000 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index e06186c305d8..8bdc8b973007 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -2261,6 +2261,23 @@ static void bnx2x_set_requested_fc(struct bnx2x *bp) bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; } +static void bnx2x_init_dropless_fc(struct bnx2x *bp) +{ + u32 pause_enabled = 0; + + if (!CHIP_IS_E1(bp) && bp->dropless_fc && bp->link_vars.link_up) { + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) + pause_enabled = 1; + + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_ETH_PAUSE_ENABLED_OFFSET(BP_PORT(bp)), + pause_enabled); + } + + DP(NETIF_MSG_IFUP | NETIF_MSG_LINK, "dropless_fc is %s\n", + pause_enabled ? "enabled" : "disabled"); +} + int bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode) { int rc, cfx_idx = bnx2x_get_link_cfg_idx(bp); @@ -2294,6 +2311,8 @@ int bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode) bnx2x_release_phy_lock(bp); + bnx2x_init_dropless_fc(bp); + bnx2x_calc_fc_adv(bp); if (bp->link_vars.link_up) { @@ -2315,6 +2334,8 @@ void bnx2x_link_set(struct bnx2x *bp) bnx2x_phy_init(&bp->link_params, &bp->link_vars); bnx2x_release_phy_lock(bp); + bnx2x_init_dropless_fc(bp); + bnx2x_calc_fc_adv(bp); } else BNX2X_ERR("Bootcode is missing - can not set link\n"); @@ -2476,7 +2497,7 @@ static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type) input.port_rate = bp->link_vars.line_speed; - if (cmng_type == CMNG_FNS_MINMAX) { + if (cmng_type == CMNG_FNS_MINMAX && input.port_rate) { int vn; /* read mf conf from shmem */ @@ -2533,6 +2554,21 @@ static void storm_memset_cmng(struct bnx2x *bp, } } +/* init cmng mode in HW according to local configuration */ +void bnx2x_set_local_cmng(struct bnx2x *bp) +{ + int cmng_fns = bnx2x_get_cmng_fns_mode(bp); + + if (cmng_fns != CMNG_FNS_NONE) { + bnx2x_cmng_fns_init(bp, false, cmng_fns); + storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp)); + } else { + /* rate shaping and fairness are disabled */ + DP(NETIF_MSG_IFUP, + "single function mode without fairness\n"); + } +} + /* This function is called upon link interrupt */ static void bnx2x_link_attn(struct bnx2x *bp) { @@ -2541,20 +2577,9 @@ static void bnx2x_link_attn(struct bnx2x *bp) bnx2x_link_update(&bp->link_params, &bp->link_vars); - if (bp->link_vars.link_up) { + bnx2x_init_dropless_fc(bp); - /* dropless flow control */ - if (!CHIP_IS_E1(bp) && bp->dropless_fc) { - int port = BP_PORT(bp); - u32 pause_enabled = 0; - - if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) - pause_enabled = 1; - - REG_WR(bp, BAR_USTRORM_INTMEM + - USTORM_ETH_PAUSE_ENABLED_OFFSET(port), - pause_enabled); - } + if (bp->link_vars.link_up) { if (bp->link_vars.mac_type != MAC_TYPE_EMAC) { struct host_port_stats *pstats; @@ -2568,17 +2593,8 @@ static void bnx2x_link_attn(struct bnx2x *bp) bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP); } - if (bp->link_vars.link_up && bp->link_vars.line_speed) { - int cmng_fns = bnx2x_get_cmng_fns_mode(bp); - - if (cmng_fns != CMNG_FNS_NONE) { - bnx2x_cmng_fns_init(bp, false, cmng_fns); - storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp)); - } else - /* rate shaping and fairness are disabled */ - DP(NETIF_MSG_IFUP, - "single function mode without fairness\n"); - } + if (bp->link_vars.link_up && bp->link_vars.line_speed) + bnx2x_set_local_cmng(bp); __bnx2x_link_report(bp); @@ -9639,6 +9655,12 @@ sp_rtnl_not_reset: &bp->sp_rtnl_state)) bnx2x_pf_set_vfs_vlan(bp); + if (test_and_clear_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state)) + bnx2x_dcbx_stop_hw_tx(bp); + + if (test_and_clear_bit(BNX2X_SP_RTNL_TX_RESUME, &bp->sp_rtnl_state)) + bnx2x_dcbx_resume_hw_tx(bp); + /* work which needs rtnl lock not-taken (as it takes the lock itself and * can be called from other contexts as well) */ @@ -10362,6 +10384,10 @@ static void bnx2x_get_common_hwinfo(struct bnx2x *bp) bp->flags |= (val >= REQ_BC_VER_4_DCBX_ADMIN_MSG_NON_PMF) ? BC_SUPPORTS_DCBX_MSG_NON_PMF : 0; + + bp->flags |= (val >= REQ_BC_VER_4_RMMOD_CMD) ? + BC_SUPPORTS_RMMOD_CMD : 0; + boot_mode = SHMEM_RD(bp, dev_info.port_feature_config[BP_PORT(bp)].mba_config) & PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK; @@ -11137,6 +11163,9 @@ static bool bnx2x_get_dropless_info(struct bnx2x *bp) int tmp; u32 cfg; + if (IS_VF(bp)) + return 0; + if (IS_MF(bp) && !CHIP_IS_E1x(bp)) { /* Take function: tmp = func */ tmp = BP_ABS_FUNC(bp); @@ -11524,6 +11553,7 @@ static int bnx2x_init_bp(struct bnx2x *bp) mutex_init(&bp->port.phy_mutex); mutex_init(&bp->fw_mb_mutex); spin_lock_init(&bp->stats_lock); + sema_init(&bp->stats_sema, 1); INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task); INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task); @@ -12817,13 +12847,17 @@ static void __bnx2x_remove(struct pci_dev *pdev, bnx2x_dcbnl_update_applist(bp, true); #endif + if (IS_PF(bp) && + !BP_NOMCP(bp) && + (bp->flags & BC_SUPPORTS_RMMOD_CMD)) + bnx2x_fw_command(bp, DRV_MSG_CODE_RMMOD, 0); + /* Close the interface - either directly or implicitly */ if (remove_netdev) { unregister_netdev(dev); } else { rtnl_lock(); - if (netif_running(dev)) - bnx2x_close(dev); + dev_close(dev); rtnl_unlock(); } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 95861efb5051..ad83f4b48777 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -1747,11 +1747,8 @@ void bnx2x_iov_init_dq(struct bnx2x *bp) void bnx2x_iov_init_dmae(struct bnx2x *bp) { - DP(BNX2X_MSG_IOV, "SRIOV is %s\n", IS_SRIOV(bp) ? "ON" : "OFF"); - if (!IS_SRIOV(bp)) - return; - - REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0); + if (pci_find_ext_capability(bp->pdev, PCI_EXT_CAP_ID_SRIOV)) + REG_WR(bp, DMAE_REG_BACKWARD_COMP_EN, 0); } static int bnx2x_vf_bus(struct bnx2x *bp, int vfid) @@ -3084,8 +3081,9 @@ void bnx2x_disable_sriov(struct bnx2x *bp) pci_disable_sriov(bp->pdev); } -static int bnx2x_vf_ndo_sanity(struct bnx2x *bp, int vfidx, - struct bnx2x_virtf *vf) +static int bnx2x_vf_ndo_prep(struct bnx2x *bp, int vfidx, + struct bnx2x_virtf **vf, + struct pf_vf_bulletin_content **bulletin) { if (bp->state != BNX2X_STATE_OPEN) { BNX2X_ERR("vf ndo called though PF is down\n"); @@ -3103,12 +3101,22 @@ static int bnx2x_vf_ndo_sanity(struct bnx2x *bp, int vfidx, return -EINVAL; } - if (!vf) { + /* init members */ + *vf = BP_VF(bp, vfidx); + *bulletin = BP_VF_BULLETIN(bp, vfidx); + + if (!*vf) { BNX2X_ERR("vf ndo called but vf was null. vfidx was %d\n", vfidx); return -EINVAL; } + if (!*bulletin) { + BNX2X_ERR("vf ndo called but Bulletin Board struct is null. vfidx was %d\n", + vfidx); + return -EINVAL; + } + return 0; } @@ -3116,17 +3124,19 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx, struct ifla_vf_info *ivi) { struct bnx2x *bp = netdev_priv(dev); - struct bnx2x_virtf *vf = BP_VF(bp, vfidx); - struct bnx2x_vlan_mac_obj *mac_obj = &bnx2x_vfq(vf, 0, mac_obj); - struct bnx2x_vlan_mac_obj *vlan_obj = &bnx2x_vfq(vf, 0, vlan_obj); - struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx); + struct bnx2x_virtf *vf = NULL; + struct pf_vf_bulletin_content *bulletin = NULL; + struct bnx2x_vlan_mac_obj *mac_obj; + struct bnx2x_vlan_mac_obj *vlan_obj; int rc; - /* sanity */ - rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf); + /* sanity and init */ + rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin); if (rc) return rc; - if (!mac_obj || !vlan_obj || !bulletin) { + mac_obj = &bnx2x_vfq(vf, 0, mac_obj); + vlan_obj = &bnx2x_vfq(vf, 0, vlan_obj); + if (!mac_obj || !vlan_obj) { BNX2X_ERR("VF partially initialized\n"); return -EINVAL; } @@ -3183,11 +3193,11 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac) { struct bnx2x *bp = netdev_priv(dev); int rc, q_logical_state; - struct bnx2x_virtf *vf = BP_VF(bp, vfidx); - struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx); + struct bnx2x_virtf *vf = NULL; + struct pf_vf_bulletin_content *bulletin = NULL; - /* sanity */ - rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf); + /* sanity and init */ + rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin); if (rc) return rc; if (!is_valid_ether_addr(mac)) { @@ -3249,11 +3259,11 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) { struct bnx2x *bp = netdev_priv(dev); int rc, q_logical_state; - struct bnx2x_virtf *vf = BP_VF(bp, vfidx); - struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vfidx); + struct bnx2x_virtf *vf = NULL; + struct pf_vf_bulletin_content *bulletin = NULL; - /* sanity */ - rc = bnx2x_vf_ndo_sanity(bp, vfidx, vf); + /* sanity and init */ + rc = bnx2x_vf_ndo_prep(bp, vfidx, &vf, &bulletin); if (rc) return rc; @@ -3463,7 +3473,7 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp) alloc_mem_err: BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping, sizeof(struct bnx2x_vf_mbx_msg)); - BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->vf2pf_mbox_mapping, + BNX2X_PCI_FREE(bp->vf2pf_mbox, bp->pf2vf_bulletin_mapping, sizeof(union pf_vf_bulletin)); return -ENOMEM; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c index 98366abd02bd..d63d1327b051 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c @@ -221,7 +221,8 @@ static int bnx2x_stats_comp(struct bnx2x *bp) * Statistics service functions */ -static void bnx2x_stats_pmf_update(struct bnx2x *bp) +/* should be called under stats_sema */ +static void __bnx2x_stats_pmf_update(struct bnx2x *bp) { struct dmae_command *dmae; u32 opcode; @@ -518,7 +519,8 @@ static void bnx2x_func_stats_init(struct bnx2x *bp) *stats_comp = 0; } -static void bnx2x_stats_start(struct bnx2x *bp) +/* should be called under stats_sema */ +static void __bnx2x_stats_start(struct bnx2x *bp) { /* vfs travel through here as part of the statistics FSM, but no action * is required @@ -534,13 +536,34 @@ static void bnx2x_stats_start(struct bnx2x *bp) bnx2x_hw_stats_post(bp); bnx2x_storm_stats_post(bp); + + bp->stats_started = true; +} + +static void bnx2x_stats_start(struct bnx2x *bp) +{ + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); + __bnx2x_stats_start(bp); + up(&bp->stats_sema); } static void bnx2x_stats_pmf_start(struct bnx2x *bp) { + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); bnx2x_stats_comp(bp); - bnx2x_stats_pmf_update(bp); - bnx2x_stats_start(bp); + __bnx2x_stats_pmf_update(bp); + __bnx2x_stats_start(bp); + up(&bp->stats_sema); +} + +static void bnx2x_stats_pmf_update(struct bnx2x *bp) +{ + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); + __bnx2x_stats_pmf_update(bp); + up(&bp->stats_sema); } static void bnx2x_stats_restart(struct bnx2x *bp) @@ -550,8 +573,11 @@ static void bnx2x_stats_restart(struct bnx2x *bp) */ if (IS_VF(bp)) return; + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); bnx2x_stats_comp(bp); - bnx2x_stats_start(bp); + __bnx2x_stats_start(bp); + up(&bp->stats_sema); } static void bnx2x_bmac_stats_update(struct bnx2x *bp) @@ -888,9 +914,7 @@ static int bnx2x_storm_stats_validate_counters(struct bnx2x *bp) /* Make sure we use the value of the counter * used for sending the last stats ramrod. */ - spin_lock_bh(&bp->stats_lock); cur_stats_counter = bp->stats_counter - 1; - spin_unlock_bh(&bp->stats_lock); /* are storm stats valid? */ if (le16_to_cpu(counters->xstats_counter) != cur_stats_counter) { @@ -1227,12 +1251,18 @@ static void bnx2x_stats_update(struct bnx2x *bp) { u32 *stats_comp = bnx2x_sp(bp, stats_comp); - if (bnx2x_edebug_stats_stopped(bp)) + /* we run update from timer context, so give up + * if somebody is in the middle of transition + */ + if (down_trylock(&bp->stats_sema)) return; + if (bnx2x_edebug_stats_stopped(bp) || !bp->stats_started) + goto out; + if (IS_PF(bp)) { if (*stats_comp != DMAE_COMP_VAL) - return; + goto out; if (bp->port.pmf) bnx2x_hw_stats_update(bp); @@ -1242,7 +1272,7 @@ static void bnx2x_stats_update(struct bnx2x *bp) BNX2X_ERR("storm stats were not updated for 3 times\n"); bnx2x_panic(); } - return; + goto out; } } else { /* vf doesn't collect HW statistics, and doesn't get completions @@ -1256,7 +1286,7 @@ static void bnx2x_stats_update(struct bnx2x *bp) /* vf is done */ if (IS_VF(bp)) - return; + goto out; if (netif_msg_timer(bp)) { struct bnx2x_eth_stats *estats = &bp->eth_stats; @@ -1267,6 +1297,9 @@ static void bnx2x_stats_update(struct bnx2x *bp) bnx2x_hw_stats_post(bp); bnx2x_storm_stats_post(bp); + +out: + up(&bp->stats_sema); } static void bnx2x_port_stats_stop(struct bnx2x *bp) @@ -1332,6 +1365,11 @@ static void bnx2x_stats_stop(struct bnx2x *bp) { int update = 0; + if (down_timeout(&bp->stats_sema, HZ/10)) + BNX2X_ERR("Unable to acquire stats lock\n"); + + bp->stats_started = false; + bnx2x_stats_comp(bp); if (bp->port.pmf) @@ -1348,6 +1386,8 @@ static void bnx2x_stats_stop(struct bnx2x *bp) bnx2x_hw_stats_post(bp); bnx2x_stats_comp(bp); } + + up(&bp->stats_sema); } static void bnx2x_stats_do_nothing(struct bnx2x *bp) @@ -1376,15 +1416,17 @@ static const struct { void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) { enum bnx2x_stats_state state; + void (*action)(struct bnx2x *bp); if (unlikely(bp->panic)) return; spin_lock_bh(&bp->stats_lock); state = bp->stats_state; bp->stats_state = bnx2x_stats_stm[state][event].next_state; + action = bnx2x_stats_stm[state][event].action; spin_unlock_bh(&bp->stats_lock); - bnx2x_stats_stm[state][event].action(bp); + action(bp); if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp)) DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n", diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index ddebc7a5dda0..0da2214ef1b9 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -17796,8 +17796,10 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, done: if (state == pci_channel_io_perm_failure) { - tg3_napi_enable(tp); - dev_close(netdev); + if (netdev) { + tg3_napi_enable(tp); + dev_close(netdev); + } err = PCI_ERS_RESULT_DISCONNECT; } else { pci_disable_device(pdev); @@ -17827,7 +17829,8 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev) rtnl_lock(); if (pci_enable_device(pdev)) { - netdev_err(netdev, "Cannot re-enable PCI device after reset.\n"); + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset.\n"); goto done; } @@ -17835,7 +17838,7 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev) pci_restore_state(pdev); pci_save_state(pdev); - if (!netif_running(netdev)) { + if (!netdev || !netif_running(netdev)) { rc = PCI_ERS_RESULT_RECOVERED; goto done; } @@ -17847,7 +17850,7 @@ static pci_ers_result_t tg3_io_slot_reset(struct pci_dev *pdev) rc = PCI_ERS_RESULT_RECOVERED; done: - if (rc != PCI_ERS_RESULT_RECOVERED && netif_running(netdev)) { + if (rc != PCI_ERS_RESULT_RECOVERED && netdev && netif_running(netdev)) { tg3_napi_enable(tp); dev_close(netdev); } diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c index 687ec4a8bb48..9c89dc8fe105 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c @@ -455,11 +455,6 @@ static int alloc_pg_chunk(struct adapter *adapter, struct sge_fl *q, q->pg_chunk.offset = 0; mapping = pci_map_page(adapter->pdev, q->pg_chunk.page, 0, q->alloc_size, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(adapter->pdev, mapping))) { - __free_pages(q->pg_chunk.page, order); - q->pg_chunk.page = NULL; - return -EIO; - } q->pg_chunk.mapping = mapping; } sd->pg_chunk = q->pg_chunk; @@ -954,75 +949,40 @@ static inline unsigned int calc_tx_descs(const struct sk_buff *skb) return flits_to_desc(flits); } - -/* map_skb - map a packet main body and its page fragments - * @pdev: the PCI device - * @skb: the packet - * @addr: placeholder to save the mapped addresses - * - * map the main body of an sk_buff and its page fragments, if any. - */ -static int map_skb(struct pci_dev *pdev, const struct sk_buff *skb, - dma_addr_t *addr) -{ - const skb_frag_t *fp, *end; - const struct skb_shared_info *si; - - *addr = pci_map_single(pdev, skb->data, skb_headlen(skb), - PCI_DMA_TODEVICE); - if (pci_dma_mapping_error(pdev, *addr)) - goto out_err; - - si = skb_shinfo(skb); - end = &si->frags[si->nr_frags]; - - for (fp = si->frags; fp < end; fp++) { - *++addr = skb_frag_dma_map(&pdev->dev, fp, 0, skb_frag_size(fp), - DMA_TO_DEVICE); - if (pci_dma_mapping_error(pdev, *addr)) - goto unwind; - } - return 0; - -unwind: - while (fp-- > si->frags) - dma_unmap_page(&pdev->dev, *--addr, skb_frag_size(fp), - DMA_TO_DEVICE); - - pci_unmap_single(pdev, addr[-1], skb_headlen(skb), PCI_DMA_TODEVICE); -out_err: - return -ENOMEM; -} - /** - * write_sgl - populate a scatter/gather list for a packet + * make_sgl - populate a scatter/gather list for a packet * @skb: the packet * @sgp: the SGL to populate * @start: start address of skb main body data to include in the SGL * @len: length of skb main body data to include in the SGL - * @addr: the list of the mapped addresses + * @pdev: the PCI device * - * Copies the scatter/gather list for the buffers that make up a packet + * Generates a scatter/gather list for the buffers that make up a packet * and returns the SGL size in 8-byte words. The caller must size the SGL * appropriately. */ -static inline unsigned int write_sgl(const struct sk_buff *skb, +static inline unsigned int make_sgl(const struct sk_buff *skb, struct sg_ent *sgp, unsigned char *start, - unsigned int len, const dma_addr_t *addr) + unsigned int len, struct pci_dev *pdev) { - unsigned int i, j = 0, k = 0, nfrags; + dma_addr_t mapping; + unsigned int i, j = 0, nfrags; if (len) { + mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE); sgp->len[0] = cpu_to_be32(len); - sgp->addr[j++] = cpu_to_be64(addr[k++]); + sgp->addr[0] = cpu_to_be64(mapping); + j = 1; } nfrags = skb_shinfo(skb)->nr_frags; for (i = 0; i < nfrags; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + mapping = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag), + DMA_TO_DEVICE); sgp->len[j] = cpu_to_be32(skb_frag_size(frag)); - sgp->addr[j] = cpu_to_be64(addr[k++]); + sgp->addr[j] = cpu_to_be64(mapping); j ^= 1; if (j == 0) ++sgp; @@ -1178,7 +1138,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, const struct port_info *pi, unsigned int pidx, unsigned int gen, struct sge_txq *q, unsigned int ndesc, - unsigned int compl, const dma_addr_t *addr) + unsigned int compl) { unsigned int flits, sgl_flits, cntrl, tso_info; struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1]; @@ -1236,7 +1196,7 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, } sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; - sgl_flits = write_sgl(skb, sgp, skb->data, skb_headlen(skb), addr); + sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev); write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen, htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl), @@ -1267,7 +1227,6 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) struct netdev_queue *txq; struct sge_qset *qs; struct sge_txq *q; - dma_addr_t addr[MAX_SKB_FRAGS + 1]; /* * The chip min packet length is 9 octets but play safe and reject @@ -1296,11 +1255,6 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_BUSY; } - if (unlikely(map_skb(adap->pdev, skb, addr) < 0)) { - dev_kfree_skb(skb); - return NETDEV_TX_OK; - } - q->in_use += ndesc; if (unlikely(credits - ndesc < q->stop_thres)) { t3_stop_tx_queue(txq, qs, q); @@ -1358,7 +1312,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) if (likely(!skb_shared(skb))) skb_orphan(skb); - write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl, addr); + write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl); check_ring_tx_db(adap, q); return NETDEV_TX_OK; } @@ -1623,8 +1577,7 @@ static void setup_deferred_unmapping(struct sk_buff *skb, struct pci_dev *pdev, */ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, struct sge_txq *q, unsigned int pidx, - unsigned int gen, unsigned int ndesc, - const dma_addr_t *addr) + unsigned int gen, unsigned int ndesc) { unsigned int sgl_flits, flits; struct work_request_hdr *from; @@ -1645,9 +1598,9 @@ static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb, flits = skb_transport_offset(skb) / 8; sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl; - sgl_flits = write_sgl(skb, sgp, skb_transport_header(skb), - skb_tail_pointer(skb) - - skb_transport_header(skb), addr); + sgl_flits = make_sgl(skb, sgp, skb_transport_header(skb), + skb->tail - skb->transport_header, + adap->pdev); if (need_skb_unmap()) { setup_deferred_unmapping(skb, adap->pdev, sgp, sgl_flits); skb->destructor = deferred_unmap_destructor; @@ -1705,11 +1658,6 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); goto again; } - if (map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) { - spin_unlock(&q->lock); - return NET_XMIT_SUCCESS; - } - gen = q->gen; q->in_use += ndesc; pidx = q->pidx; @@ -1720,7 +1668,7 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); } spin_unlock(&q->lock); - write_ofld_wr(adap, skb, q, pidx, gen, ndesc, (dma_addr_t *)skb->head); + write_ofld_wr(adap, skb, q, pidx, gen, ndesc); check_ring_tx_db(adap, q); return NET_XMIT_SUCCESS; } @@ -1738,7 +1686,6 @@ static void restart_offloadq(unsigned long data) struct sge_txq *q = &qs->txq[TXQ_OFLD]; const struct port_info *pi = netdev_priv(qs->netdev); struct adapter *adap = pi->adapter; - unsigned int written = 0; spin_lock(&q->lock); again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); @@ -1758,14 +1705,10 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); break; } - if (map_skb(adap->pdev, skb, (dma_addr_t *)skb->head)) - break; - gen = q->gen; q->in_use += ndesc; pidx = q->pidx; q->pidx += ndesc; - written += ndesc; if (q->pidx >= q->size) { q->pidx -= q->size; q->gen ^= 1; @@ -1773,8 +1716,7 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); __skb_unlink(skb, &q->sendq); spin_unlock(&q->lock); - write_ofld_wr(adap, skb, q, pidx, gen, ndesc, - (dma_addr_t *)skb->head); + write_ofld_wr(adap, skb, q, pidx, gen, ndesc); spin_lock(&q->lock); } spin_unlock(&q->lock); @@ -1784,9 +1726,8 @@ again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK); set_bit(TXQ_LAST_PKT_DB, &q->flags); #endif wmb(); - if (likely(written)) - t3_write_reg(adap, A_SG_KDOORBELL, - F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); + t3_write_reg(adap, A_SG_KDOORBELL, + F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id)); } /** diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 6e6e0a117ee2..8ec5d74ad44d 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -3048,6 +3048,9 @@ int be_cmd_get_func_config(struct be_adapter *adapter) adapter->max_event_queues = le16_to_cpu(desc->eq_count); adapter->if_cap_flags = le32_to_cpu(desc->cap_flags); + + /* Clear flags that driver is not interested in */ + adapter->if_cap_flags &= BE_IF_CAP_FLAGS_WANT; } err: mutex_unlock(&adapter->mbox_lock); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 5228d88c5a02..1b3b9e886412 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -563,6 +563,12 @@ enum be_if_flags { BE_IF_FLAGS_MULTICAST = 0x1000 }; +#define BE_IF_CAP_FLAGS_WANT (BE_IF_FLAGS_RSS | BE_IF_FLAGS_PROMISCUOUS |\ + BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_VLAN_PROMISCUOUS |\ + BE_IF_FLAGS_VLAN | BE_IF_FLAGS_MCAST_PROMISCUOUS |\ + BE_IF_FLAGS_PASS_L3L4_ERRORS | BE_IF_FLAGS_MULTICAST |\ + BE_IF_FLAGS_UNTAGGED) + /* An RX interface is an object with one or more MAC addresses and * filtering capabilities. */ struct be_cmd_req_if_create { diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 181edb522450..4559c35eea13 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -2563,8 +2563,8 @@ static int be_close(struct net_device *netdev) /* Wait for all pending tx completions to arrive so that * all tx skbs are freed. */ - be_tx_compl_clean(adapter); netif_tx_disable(netdev); + be_tx_compl_clean(adapter); be_rx_qs_destroy(adapter); diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index c896079728e1..ef94a591f9e5 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c @@ -931,17 +931,20 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base) } /* Allocate and setup a new buffer for receiving */ -static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, - struct sk_buff *skb, unsigned int bufsize) +static int skge_rx_setup(struct skge_port *skge, struct skge_element *e, + struct sk_buff *skb, unsigned int bufsize) { struct skge_rx_desc *rd = e->desc; - u64 map; + dma_addr_t map; map = pci_map_single(skge->hw->pdev, skb->data, bufsize, PCI_DMA_FROMDEVICE); - rd->dma_lo = map; - rd->dma_hi = map >> 32; + if (pci_dma_mapping_error(skge->hw->pdev, map)) + return -1; + + rd->dma_lo = lower_32_bits(map); + rd->dma_hi = upper_32_bits(map); e->skb = skb; rd->csum1_start = ETH_HLEN; rd->csum2_start = ETH_HLEN; @@ -953,6 +956,7 @@ static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize; dma_unmap_addr_set(e, mapaddr, map); dma_unmap_len_set(e, maplen, bufsize); + return 0; } /* Resume receiving using existing skb, @@ -1014,7 +1018,10 @@ static int skge_rx_fill(struct net_device *dev) return -ENOMEM; skb_reserve(skb, NET_IP_ALIGN); - skge_rx_setup(skge, e, skb, skge->rx_buf_size); + if (skge_rx_setup(skge, e, skb, skge->rx_buf_size) < 0) { + dev_kfree_skb(skb); + return -EIO; + } } while ((e = e->next) != ring->start); ring->to_clean = ring->start; @@ -2544,7 +2551,7 @@ static int skge_up(struct net_device *dev) BUG_ON(skge->dma & 7); - if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) { + if (upper_32_bits(skge->dma) != upper_32_bits(skge->dma + skge->mem_size)) { dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n"); err = -EINVAL; goto free_pci_mem; @@ -2729,7 +2736,7 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, struct skge_tx_desc *td; int i; u32 control, len; - u64 map; + dma_addr_t map; if (skb_padto(skb, ETH_ZLEN)) return NETDEV_TX_OK; @@ -2743,11 +2750,14 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, e->skb = skb; len = skb_headlen(skb); map = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(hw->pdev, map)) + goto mapping_error; + dma_unmap_addr_set(e, mapaddr, map); dma_unmap_len_set(e, maplen, len); - td->dma_lo = map; - td->dma_hi = map >> 32; + td->dma_lo = lower_32_bits(map); + td->dma_hi = upper_32_bits(map); if (skb->ip_summed == CHECKSUM_PARTIAL) { const int offset = skb_checksum_start_offset(skb); @@ -2778,14 +2788,16 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, map = skb_frag_dma_map(&hw->pdev->dev, frag, 0, skb_frag_size(frag), DMA_TO_DEVICE); + if (dma_mapping_error(&hw->pdev->dev, map)) + goto mapping_unwind; e = e->next; e->skb = skb; tf = e->desc; BUG_ON(tf->control & BMU_OWN); - tf->dma_lo = map; - tf->dma_hi = (u64) map >> 32; + tf->dma_lo = lower_32_bits(map); + tf->dma_hi = upper_32_bits(map); dma_unmap_addr_set(e, mapaddr, map); dma_unmap_len_set(e, maplen, skb_frag_size(frag)); @@ -2815,6 +2827,26 @@ static netdev_tx_t skge_xmit_frame(struct sk_buff *skb, } return NETDEV_TX_OK; + +mapping_unwind: + e = skge->tx_ring.to_use; + pci_unmap_single(hw->pdev, + dma_unmap_addr(e, mapaddr), + dma_unmap_len(e, maplen), + PCI_DMA_TODEVICE); + while (i-- > 0) { + e = e->next; + pci_unmap_page(hw->pdev, + dma_unmap_addr(e, mapaddr), + dma_unmap_len(e, maplen), + PCI_DMA_TODEVICE); + } + +mapping_error: + if (net_ratelimit()) + dev_warn(&hw->pdev->dev, "%s: tx mapping error\n", dev->name); + dev_kfree_skb(skb); + return NETDEV_TX_OK; } @@ -3045,11 +3077,13 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, pci_dma_sync_single_for_cpu(skge->hw->pdev, dma_unmap_addr(e, mapaddr), - len, PCI_DMA_FROMDEVICE); + dma_unmap_len(e, maplen), + PCI_DMA_FROMDEVICE); skb_copy_from_linear_data(e->skb, skb->data, len); pci_dma_sync_single_for_device(skge->hw->pdev, dma_unmap_addr(e, mapaddr), - len, PCI_DMA_FROMDEVICE); + dma_unmap_len(e, maplen), + PCI_DMA_FROMDEVICE); skge_rx_reuse(e, skge->rx_buf_size); } else { struct sk_buff *nskb; @@ -3058,13 +3092,17 @@ static struct sk_buff *skge_rx_get(struct net_device *dev, if (!nskb) goto resubmit; + if (skge_rx_setup(skge, e, nskb, skge->rx_buf_size) < 0) { + dev_kfree_skb(nskb); + goto resubmit; + } + pci_unmap_single(skge->hw->pdev, dma_unmap_addr(e, mapaddr), dma_unmap_len(e, maplen), PCI_DMA_FROMDEVICE); skb = e->skb; prefetch(skb->data); - skge_rx_setup(skge, e, nskb, skge->rx_buf_size); } skb_put(skb, len); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index c571de85d0f9..5472cbd34028 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -46,7 +46,7 @@ #include "mlx5_core.h" enum { - CMD_IF_REV = 4, + CMD_IF_REV = 5, }; enum { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eq.c b/drivers/net/ethernet/mellanox/mlx5/core/eq.c index c02cbcfd0fb8..443cc4d7b024 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eq.c @@ -268,7 +268,7 @@ static int mlx5_eq_int(struct mlx5_core_dev *dev, struct mlx5_eq *eq) case MLX5_EVENT_TYPE_PAGE_REQUEST: { u16 func_id = be16_to_cpu(eqe->data.req_pages.func_id); - s16 npages = be16_to_cpu(eqe->data.req_pages.num_pages); + s32 npages = be32_to_cpu(eqe->data.req_pages.num_pages); mlx5_core_dbg(dev, "page request for func 0x%x, napges %d\n", func_id, npages); mlx5_core_req_pages_handler(dev, func_id, npages); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 72a5222447f5..f012658b6a92 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -113,7 +113,7 @@ int mlx5_cmd_query_hca_cap(struct mlx5_core_dev *dev, caps->log_max_srq = out->hca_cap.log_max_srqs & 0x1f; caps->local_ca_ack_delay = out->hca_cap.local_ca_ack_delay & 0x1f; caps->log_max_mcg = out->hca_cap.log_max_mcg; - caps->max_qp_mcg = be16_to_cpu(out->hca_cap.max_qp_mcg); + caps->max_qp_mcg = be32_to_cpu(out->hca_cap.max_qp_mcg) & 0xffffff; caps->max_ra_res_qp = 1 << (out->hca_cap.log_max_ra_res_qp & 0x3f); caps->max_ra_req_qp = 1 << (out->hca_cap.log_max_ra_req_qp & 0x3f); caps->max_srq_wqes = 1 << out->hca_cap.log_max_srq_sz; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/health.c b/drivers/net/ethernet/mellanox/mlx5/core/health.c index 748f10a155c4..3e6670c4a7cd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/health.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/health.c @@ -55,33 +55,9 @@ enum { }; static DEFINE_SPINLOCK(health_lock); - static LIST_HEAD(health_list); static struct work_struct health_work; -static health_handler_t reg_handler; -int mlx5_register_health_report_handler(health_handler_t handler) -{ - spin_lock_irq(&health_lock); - if (reg_handler) { - spin_unlock_irq(&health_lock); - return -EEXIST; - } - reg_handler = handler; - spin_unlock_irq(&health_lock); - - return 0; -} -EXPORT_SYMBOL(mlx5_register_health_report_handler); - -void mlx5_unregister_health_report_handler(void) -{ - spin_lock_irq(&health_lock); - reg_handler = NULL; - spin_unlock_irq(&health_lock); -} -EXPORT_SYMBOL(mlx5_unregister_health_report_handler); - static void health_care(struct work_struct *work) { struct mlx5_core_health *health, *n; @@ -98,11 +74,8 @@ static void health_care(struct work_struct *work) priv = container_of(health, struct mlx5_priv, health); dev = container_of(priv, struct mlx5_core_dev, priv); mlx5_core_warn(dev, "handling bad device here\n"); + /* nothing yet */ spin_lock_irq(&health_lock); - if (reg_handler) - reg_handler(dev->pdev, health->health, - sizeof(health->health)); - list_del_init(&health->list); spin_unlock_irq(&health_lock); } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c index 4a3e137931a3..3a2408d44820 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/pagealloc.c @@ -43,10 +43,16 @@ enum { MLX5_PAGES_TAKE = 2 }; +enum { + MLX5_BOOT_PAGES = 1, + MLX5_INIT_PAGES = 2, + MLX5_POST_INIT_PAGES = 3 +}; + struct mlx5_pages_req { struct mlx5_core_dev *dev; u32 func_id; - s16 npages; + s32 npages; struct work_struct work; }; @@ -64,27 +70,23 @@ struct mlx5_query_pages_inbox { struct mlx5_query_pages_outbox { struct mlx5_outbox_hdr hdr; - __be16 num_boot_pages; + __be16 rsvd; __be16 func_id; - __be16 init_pages; - __be16 num_pages; + __be32 num_pages; }; struct mlx5_manage_pages_inbox { struct mlx5_inbox_hdr hdr; - __be16 rsvd0; + __be16 rsvd; __be16 func_id; - __be16 rsvd1; - __be16 num_entries; - u8 rsvd2[16]; + __be32 num_entries; __be64 pas[0]; }; struct mlx5_manage_pages_outbox { struct mlx5_outbox_hdr hdr; - u8 rsvd0[2]; - __be16 num_entries; - u8 rsvd1[20]; + __be32 num_entries; + u8 rsvd[4]; __be64 pas[0]; }; @@ -146,7 +148,7 @@ static struct page *remove_page(struct mlx5_core_dev *dev, u64 addr) } static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id, - s16 *pages, s16 *init_pages, u16 *boot_pages) + s32 *npages, int boot) { struct mlx5_query_pages_inbox in; struct mlx5_query_pages_outbox out; @@ -155,6 +157,8 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id, memset(&in, 0, sizeof(in)); memset(&out, 0, sizeof(out)); in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_PAGES); + in.hdr.opmod = boot ? cpu_to_be16(MLX5_BOOT_PAGES) : cpu_to_be16(MLX5_INIT_PAGES); + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); if (err) return err; @@ -162,15 +166,7 @@ static int mlx5_cmd_query_pages(struct mlx5_core_dev *dev, u16 *func_id, if (out.hdr.status) return mlx5_cmd_status_to_err(&out.hdr); - if (pages) - *pages = be16_to_cpu(out.num_pages); - - if (init_pages) - *init_pages = be16_to_cpu(out.init_pages); - - if (boot_pages) - *boot_pages = be16_to_cpu(out.num_boot_pages); - + *npages = be32_to_cpu(out.num_pages); *func_id = be16_to_cpu(out.func_id); return err; @@ -224,7 +220,7 @@ static int give_pages(struct mlx5_core_dev *dev, u16 func_id, int npages, in->hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); in->hdr.opmod = cpu_to_be16(MLX5_PAGES_GIVE); in->func_id = cpu_to_be16(func_id); - in->num_entries = cpu_to_be16(npages); + in->num_entries = cpu_to_be32(npages); err = mlx5_cmd_exec(dev, in, inlen, &out, sizeof(out)); mlx5_core_dbg(dev, "err %d\n", err); if (err) { @@ -292,7 +288,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_MANAGE_PAGES); in.hdr.opmod = cpu_to_be16(MLX5_PAGES_TAKE); in.func_id = cpu_to_be16(func_id); - in.num_entries = cpu_to_be16(npages); + in.num_entries = cpu_to_be32(npages); mlx5_core_dbg(dev, "npages %d, outlen %d\n", npages, outlen); err = mlx5_cmd_exec(dev, &in, sizeof(in), out, outlen); if (err) { @@ -306,7 +302,7 @@ static int reclaim_pages(struct mlx5_core_dev *dev, u32 func_id, int npages, goto out_free; } - num_claimed = be16_to_cpu(out->num_entries); + num_claimed = be32_to_cpu(out->num_entries); if (nclaimed) *nclaimed = num_claimed; @@ -345,7 +341,7 @@ static void pages_work_handler(struct work_struct *work) } void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id, - s16 npages) + s32 npages) { struct mlx5_pages_req *req; @@ -364,20 +360,18 @@ void mlx5_core_req_pages_handler(struct mlx5_core_dev *dev, u16 func_id, int mlx5_satisfy_startup_pages(struct mlx5_core_dev *dev, int boot) { - u16 uninitialized_var(boot_pages); - s16 uninitialized_var(init_pages); u16 uninitialized_var(func_id); + s32 uninitialized_var(npages); int err; - err = mlx5_cmd_query_pages(dev, &func_id, NULL, &init_pages, - &boot_pages); + err = mlx5_cmd_query_pages(dev, &func_id, &npages, boot); if (err) return err; + mlx5_core_dbg(dev, "requested %d %s pages for func_id 0x%x\n", + npages, boot ? "boot" : "init", func_id); - mlx5_core_dbg(dev, "requested %d init pages and %d boot pages for func_id 0x%x\n", - init_pages, boot_pages, func_id); - return give_pages(dev, func_id, boot ? boot_pages : init_pages, 0); + return give_pages(dev, func_id, npages, 0); } static int optimal_reclaimed_pages(void) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 92da9980a0a0..9d4bb7f83904 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -3266,6 +3266,11 @@ int qlcnic_83xx_interrupt_test(struct net_device *netdev) u8 val; int ret, max_sds_rings = adapter->max_sds_rings; + if (test_bit(__QLCNIC_RESETTING, &adapter->state)) { + netdev_info(netdev, "Device is resetting\n"); + return -EBUSY; + } + if (qlcnic_get_diag_lock(adapter)) { netdev_info(netdev, "Device in diagnostics mode\n"); return -EBUSY; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 9f4b8d5f0865..345d987aede4 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -629,7 +629,8 @@ int qlcnic_83xx_idc_reattach_driver(struct qlcnic_adapter *adapter) return -EIO; } - qlcnic_set_drv_version(adapter); + if (adapter->portnum == 0) + qlcnic_set_drv_version(adapter); qlcnic_83xx_idc_attach_driver(adapter); return 0; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index ee013fcc3322..bc05d016c859 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -2165,7 +2165,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_out_disable_mbx_intr; - qlcnic_set_drv_version(adapter); + if (adapter->portnum == 0) + qlcnic_set_drv_version(adapter); pci_set_drvdata(pdev, adapter); @@ -3085,7 +3086,8 @@ done: adapter->fw_fail_cnt = 0; adapter->flags &= ~QLCNIC_FW_HANG; clear_bit(__QLCNIC_RESETTING, &adapter->state); - qlcnic_set_drv_version(adapter); + if (adapter->portnum == 0) + qlcnic_set_drv_version(adapter); if (!qlcnic_clr_drv_state(adapter)) qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index 10ed82b3baca..660c3f5b2237 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -170,9 +170,9 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter, if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) { err = qlcnic_get_beacon_state(adapter, &h_beacon_state); - if (!err) { - dev_info(&adapter->pdev->dev, - "Failed to get current beacon state\n"); + if (err) { + netdev_err(adapter->netdev, + "Failed to get current beacon state\n"); } else { if (h_beacon_state == QLCNIC_BEACON_DISABLE) ahw->beacon_state = 0; diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 6f35f8404d68..d2e591955bdd 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -524,6 +524,7 @@ rx_status_loop: PCI_DMA_FROMDEVICE); if (dma_mapping_error(&cp->pdev->dev, new_mapping)) { dev->stats.rx_dropped++; + kfree_skb(new_skb); goto rx_next; } diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index b5eb4195fc99..85e5c97191dd 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -7088,7 +7088,7 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) RTL_W8(Cfg9346, Cfg9346_Unlock); RTL_W8(Config1, RTL_R8(Config1) | PMEnable); - RTL_W8(Config5, RTL_R8(Config5) & PMEStatus); + RTL_W8(Config5, RTL_R8(Config5) & (BWF | MWF | UWF | LanWake | PMEStatus)); if ((RTL_R8(Config3) & (LinkUp | MagicPacket)) != 0) tp->features |= RTL_FEATURE_WOL; if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0) diff --git a/drivers/net/ethernet/sfc/filter.c b/drivers/net/ethernet/sfc/filter.c index 2a469b27a506..30d744235d27 100644 --- a/drivers/net/ethernet/sfc/filter.c +++ b/drivers/net/ethernet/sfc/filter.c @@ -675,7 +675,7 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec, BUILD_BUG_ON(EFX_FILTER_INDEX_UC_DEF != 0); BUILD_BUG_ON(EFX_FILTER_INDEX_MC_DEF != EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF); - rep_index = spec->type - EFX_FILTER_INDEX_UC_DEF; + rep_index = spec->type - EFX_FILTER_UC_DEF; ins_index = rep_index; spin_lock_bh(&state->lock); diff --git a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c index c9d942a5c335..1ef9d8a555aa 100644 --- a/drivers/net/ethernet/stmicro/stmmac/ring_mode.c +++ b/drivers/net/ethernet/stmicro/stmmac/ring_mode.c @@ -33,10 +33,15 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum) struct stmmac_priv *priv = (struct stmmac_priv *)p; unsigned int txsize = priv->dma_tx_size; unsigned int entry = priv->cur_tx % txsize; - struct dma_desc *desc = priv->dma_tx + entry; + struct dma_desc *desc; unsigned int nopaged_len = skb_headlen(skb); unsigned int bmax, len; + if (priv->extend_desc) + desc = (struct dma_desc *)(priv->dma_etx + entry); + else + desc = priv->dma_tx + entry; + if (priv->plat->enh_desc) bmax = BUF_SIZE_8KiB; else @@ -54,7 +59,11 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum) STMMAC_RING_MODE); wmb(); entry = (++priv->cur_tx) % txsize; - desc = priv->dma_tx + entry; + + if (priv->extend_desc) + desc = (struct dma_desc *)(priv->dma_etx + entry); + else + desc = priv->dma_tx + entry; desc->des2 = dma_map_single(priv->device, skb->data + bmax, len, DMA_TO_DEVICE); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index f2ccb36e8685..0a9bb9d30c3f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -939,15 +939,20 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN, GFP_KERNEL); - if (unlikely(skb == NULL)) { + if (!skb) { pr_err("%s: Rx init fails; skb is NULL\n", __func__); - return 1; + return -ENOMEM; } skb_reserve(skb, NET_IP_ALIGN); priv->rx_skbuff[i] = skb; priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, priv->dma_buf_sz, DMA_FROM_DEVICE); + if (dma_mapping_error(priv->device, priv->rx_skbuff_dma[i])) { + pr_err("%s: DMA mapping error\n", __func__); + dev_kfree_skb_any(skb); + return -EINVAL; + } p->des2 = priv->rx_skbuff_dma[i]; @@ -958,6 +963,16 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, return 0; } +static void stmmac_free_rx_buffers(struct stmmac_priv *priv, int i) +{ + if (priv->rx_skbuff[i]) { + dma_unmap_single(priv->device, priv->rx_skbuff_dma[i], + priv->dma_buf_sz, DMA_FROM_DEVICE); + dev_kfree_skb_any(priv->rx_skbuff[i]); + } + priv->rx_skbuff[i] = NULL; +} + /** * init_dma_desc_rings - init the RX/TX descriptor rings * @dev: net device structure @@ -965,13 +980,14 @@ static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p, * and allocates the socket buffers. It suppors the chained and ring * modes. */ -static void init_dma_desc_rings(struct net_device *dev) +static int init_dma_desc_rings(struct net_device *dev) { int i; struct stmmac_priv *priv = netdev_priv(dev); unsigned int txsize = priv->dma_tx_size; unsigned int rxsize = priv->dma_rx_size; unsigned int bfsize = 0; + int ret = -ENOMEM; /* Set the max buffer size according to the DESC mode * and the MTU. Note that RING mode allows 16KiB bsize. @@ -992,34 +1008,60 @@ static void init_dma_desc_rings(struct net_device *dev) dma_extended_desc), &priv->dma_rx_phy, GFP_KERNEL); + if (!priv->dma_erx) + goto err_dma; + priv->dma_etx = dma_alloc_coherent(priv->device, txsize * sizeof(struct dma_extended_desc), &priv->dma_tx_phy, GFP_KERNEL); - if ((!priv->dma_erx) || (!priv->dma_etx)) - return; + if (!priv->dma_etx) { + dma_free_coherent(priv->device, priv->dma_rx_size * + sizeof(struct dma_extended_desc), + priv->dma_erx, priv->dma_rx_phy); + goto err_dma; + } } else { priv->dma_rx = dma_alloc_coherent(priv->device, rxsize * sizeof(struct dma_desc), &priv->dma_rx_phy, GFP_KERNEL); + if (!priv->dma_rx) + goto err_dma; + priv->dma_tx = dma_alloc_coherent(priv->device, txsize * sizeof(struct dma_desc), &priv->dma_tx_phy, GFP_KERNEL); - if ((!priv->dma_rx) || (!priv->dma_tx)) - return; + if (!priv->dma_tx) { + dma_free_coherent(priv->device, priv->dma_rx_size * + sizeof(struct dma_desc), + priv->dma_rx, priv->dma_rx_phy); + goto err_dma; + } } priv->rx_skbuff_dma = kmalloc_array(rxsize, sizeof(dma_addr_t), GFP_KERNEL); + if (!priv->rx_skbuff_dma) + goto err_rx_skbuff_dma; + priv->rx_skbuff = kmalloc_array(rxsize, sizeof(struct sk_buff *), GFP_KERNEL); + if (!priv->rx_skbuff) + goto err_rx_skbuff; + priv->tx_skbuff_dma = kmalloc_array(txsize, sizeof(dma_addr_t), GFP_KERNEL); + if (!priv->tx_skbuff_dma) + goto err_tx_skbuff_dma; + priv->tx_skbuff = kmalloc_array(txsize, sizeof(struct sk_buff *), GFP_KERNEL); + if (!priv->tx_skbuff) + goto err_tx_skbuff; + if (netif_msg_probe(priv)) { pr_debug("(%s) dma_rx_phy=0x%08x dma_tx_phy=0x%08x\n", __func__, (u32) priv->dma_rx_phy, (u32) priv->dma_tx_phy); @@ -1034,8 +1076,9 @@ static void init_dma_desc_rings(struct net_device *dev) else p = priv->dma_rx + i; - if (stmmac_init_rx_buffers(priv, p, i)) - break; + ret = stmmac_init_rx_buffers(priv, p, i); + if (ret) + goto err_init_rx_buffers; if (netif_msg_probe(priv)) pr_debug("[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i], @@ -1081,20 +1124,44 @@ static void init_dma_desc_rings(struct net_device *dev) if (netif_msg_hw(priv)) stmmac_display_rings(priv); + + return 0; +err_init_rx_buffers: + while (--i >= 0) + stmmac_free_rx_buffers(priv, i); + kfree(priv->tx_skbuff); +err_tx_skbuff: + kfree(priv->tx_skbuff_dma); +err_tx_skbuff_dma: + kfree(priv->rx_skbuff); +err_rx_skbuff: + kfree(priv->rx_skbuff_dma); +err_rx_skbuff_dma: + if (priv->extend_desc) { + dma_free_coherent(priv->device, priv->dma_tx_size * + sizeof(struct dma_extended_desc), + priv->dma_etx, priv->dma_tx_phy); + dma_free_coherent(priv->device, priv->dma_rx_size * + sizeof(struct dma_extended_desc), + priv->dma_erx, priv->dma_rx_phy); + } else { + dma_free_coherent(priv->device, + priv->dma_tx_size * sizeof(struct dma_desc), + priv->dma_tx, priv->dma_tx_phy); + dma_free_coherent(priv->device, + priv->dma_rx_size * sizeof(struct dma_desc), + priv->dma_rx, priv->dma_rx_phy); + } +err_dma: + return ret; } static void dma_free_rx_skbufs(struct stmmac_priv *priv) { int i; - for (i = 0; i < priv->dma_rx_size; i++) { - if (priv->rx_skbuff[i]) { - dma_unmap_single(priv->device, priv->rx_skbuff_dma[i], - priv->dma_buf_sz, DMA_FROM_DEVICE); - dev_kfree_skb_any(priv->rx_skbuff[i]); - } - priv->rx_skbuff[i] = NULL; - } + for (i = 0; i < priv->dma_rx_size; i++) + stmmac_free_rx_buffers(priv, i); } static void dma_free_tx_skbufs(struct stmmac_priv *priv) @@ -1560,12 +1627,17 @@ static int stmmac_open(struct net_device *dev) priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize); priv->dma_buf_sz = STMMAC_ALIGN(buf_sz); - init_dma_desc_rings(dev); + + ret = init_dma_desc_rings(dev); + if (ret < 0) { + pr_err("%s: DMA descriptors initialization failed\n", __func__); + goto dma_desc_error; + } /* DMA initialization and SW reset */ ret = stmmac_init_dma_engine(priv); if (ret < 0) { - pr_err("%s: DMA initialization failed\n", __func__); + pr_err("%s: DMA engine initialization failed\n", __func__); goto init_error; } @@ -1672,6 +1744,7 @@ wolirq_error: init_error: free_dma_desc_resources(priv); +dma_desc_error: if (priv->phydev) phy_disconnect(priv->phydev); phy_error: diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c index 1d6dc41f755d..d01cacf8a7c2 100644 --- a/drivers/net/ethernet/via/via-velocity.c +++ b/drivers/net/ethernet/via/via-velocity.c @@ -2100,7 +2100,7 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vid); } - netif_rx(skb); + netif_receive_skb(skb); stats->rx_bytes += pkt_len; stats->rx_packets++; @@ -2884,6 +2884,7 @@ out: return ret; err_iounmap: + netif_napi_del(&vptr->napi); iounmap(regs); err_free_dev: free_netdev(netdev); @@ -2904,6 +2905,7 @@ static int velocity_remove(struct device *dev) struct velocity_info *vptr = netdev_priv(netdev); unregister_netdev(netdev); + netif_napi_del(&vptr->napi); iounmap(vptr->mac_regs); free_netdev(netdev); velocity_nics--; diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 51f2bc376101..2dcc60fb37f1 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -210,8 +210,7 @@ static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id) pci_write_config_byte(pcidev,0x42,(bTmp | 0xf0)); pci_write_config_byte(pcidev,0x5a,0xc0); WriteLPCReg(0x28, 0x70 ); - if (via_ircc_open(pcidev, &info, 0x3076) == 0) - rc=0; + rc = via_ircc_open(pcidev, &info, 0x3076); } else rc = -ENODEV; //IR not turn on } else { //Not VT1211 @@ -249,8 +248,7 @@ static int via_init_one(struct pci_dev *pcidev, const struct pci_device_id *id) info.irq=FirIRQ; info.dma=FirDRQ1; info.dma2=FirDRQ0; - if (via_ircc_open(pcidev, &info, 0x3096) == 0) - rc=0; + rc = via_ircc_open(pcidev, &info, 0x3096); } else rc = -ENODEV; //IR not turn on !!!!! }//Not VT1211 diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index d0f9c2fd1d4f..16b43bf544b7 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -739,6 +739,10 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) return -EADDRNOTAVAIL; } + if (data && data[IFLA_MACVLAN_FLAGS] && + nla_get_u16(data[IFLA_MACVLAN_FLAGS]) & ~MACVLAN_FLAG_NOPROMISC) + return -EINVAL; + if (data && data[IFLA_MACVLAN_MODE]) { switch (nla_get_u32(data[IFLA_MACVLAN_MODE])) { case MACVLAN_MODE_PRIVATE: diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index a98fb0ed6aef..ea53abb20988 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -68,6 +68,8 @@ static const struct proto_ops macvtap_socket_ops; #define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \ NETIF_F_TSO6 | NETIF_F_UFO) #define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO) +#define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG) + /* * RCU usage: * The macvtap_queue and the macvlan_dev are loosely coupled, the @@ -278,7 +280,8 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) { struct macvlan_dev *vlan = netdev_priv(dev); struct macvtap_queue *q = macvtap_get_queue(dev, skb); - netdev_features_t features; + netdev_features_t features = TAP_FEATURES; + if (!q) goto drop; @@ -287,9 +290,11 @@ static int macvtap_forward(struct net_device *dev, struct sk_buff *skb) skb->dev = dev; /* Apply the forward feature mask so that we perform segmentation - * according to users wishes. + * according to users wishes. This only works if VNET_HDR is + * enabled. */ - features = netif_skb_features(skb) & vlan->tap_features; + if (q->flags & IFF_VNET_HDR) + features |= vlan->tap_features; if (netif_needs_gso(skb, features)) { struct sk_buff *segs = __skb_gso_segment(skb, features, false); @@ -818,10 +823,13 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; } - if (vlan) + if (vlan) { + local_bh_disable(); macvlan_start_xmit(skb, vlan->dev); - else + local_bh_enable(); + } else { kfree_skb(skb); + } rcu_read_unlock(); return total_len; @@ -912,8 +920,11 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, done: rcu_read_lock(); vlan = rcu_dereference(q->vlan); - if (vlan) + if (vlan) { + preempt_disable(); macvlan_count_rx(vlan, copied - vnet_hdr_len, ret == 0, 0); + preempt_enable(); + } rcu_read_unlock(); return ret ? ret : copied; @@ -1058,8 +1069,7 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg) /* tap_features are the same as features on tun/tap and * reflect user expectations. */ - vlan->tap_features = vlan->dev->features & - (feature_mask | ~TUN_OFFLOADS); + vlan->tap_features = feature_mask; vlan->set_features = features; netdev_update_features(vlan->dev); @@ -1155,10 +1165,6 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd, TUN_F_TSO_ECN | TUN_F_UFO)) return -EINVAL; - /* TODO: only accept frames with the features that - got enabled for forwarded frames */ - if (!(q->flags & IFF_VNET_HDR)) - return -EINVAL; rtnl_lock(); ret = set_offload(q, arg); rtnl_unlock(); diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c index 8e7af8354342..138de837977f 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -23,7 +23,7 @@ #define RTL821x_INER_INIT 0x6400 #define RTL821x_INSR 0x13 -#define RTL8211E_INER_LINK_STAT 0x10 +#define RTL8211E_INER_LINK_STATUS 0x400 MODULE_DESCRIPTION("Realtek PHY driver"); MODULE_AUTHOR("Johnson Leung"); @@ -57,7 +57,7 @@ static int rtl8211e_config_intr(struct phy_device *phydev) if (phydev->interrupts == PHY_INTERRUPT_ENABLED) err = phy_write(phydev, RTL821x_INER, - RTL8211E_INER_LINK_STAT); + RTL8211E_INER_LINK_STATUS); else err = phy_write(phydev, RTL821x_INER, 0); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index db690a372260..71af122edf2d 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1074,8 +1074,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, u32 rxhash; if (!(tun->flags & TUN_NO_PI)) { - if ((len -= sizeof(pi)) > total_len) + if (len < sizeof(pi)) return -EINVAL; + len -= sizeof(pi); if (memcpy_fromiovecend((void *)&pi, iv, 0, sizeof(pi))) return -EFAULT; @@ -1083,8 +1084,9 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, } if (tun->flags & TUN_VNET_HDR) { - if ((len -= tun->vnet_hdr_sz) > total_len) + if (len < tun->vnet_hdr_sz) return -EINVAL; + len -= tun->vnet_hdr_sz; if (memcpy_fromiovecend((void *)&gso, iv, offset, sizeof(gso))) return -EFAULT; diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index cba1d46e672e..86292e6aaf49 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -2816,13 +2816,16 @@ exit: static int hso_get_config_data(struct usb_interface *interface) { struct usb_device *usbdev = interface_to_usbdev(interface); - u8 config_data[17]; + u8 *config_data = kmalloc(17, GFP_KERNEL); u32 if_num = interface->altsetting->desc.bInterfaceNumber; s32 result; + if (!config_data) + return -ENOMEM; if (usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x86, 0xC0, 0, 0, config_data, 17, USB_CTRL_SET_TIMEOUT) != 0x11) { + kfree(config_data); return -EIO; } @@ -2873,6 +2876,7 @@ static int hso_get_config_data(struct usb_interface *interface) if (config_data[16] & 0x1) result |= HSO_INFO_CRC_BUG; + kfree(config_data); return result; } @@ -2886,6 +2890,11 @@ static int hso_probe(struct usb_interface *interface, struct hso_shared_int *shared_int; struct hso_device *tmp_dev = NULL; + if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) { + dev_err(&interface->dev, "Not our interface\n"); + return -ENODEV; + } + if_num = interface->altsetting->desc.bInterfaceNumber; /* Get the interface/port specification from either driver_info or from @@ -2895,10 +2904,6 @@ static int hso_probe(struct usb_interface *interface, else port_spec = hso_get_config_data(interface); - if (interface->cur_altsetting->desc.bInterfaceClass != 0xFF) { - dev_err(&interface->dev, "Not our interface\n"); - return -ENODEV; - } /* Check if we need to switch to alt interfaces prior to port * configuration */ if (interface->num_altsetting > 1) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index f4c6db419ddb..767f7af3bd40 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1386,7 +1386,7 @@ static int vxlan_open(struct net_device *dev) return -ENOTCONN; if (IN_MULTICAST(ntohl(vxlan->default_dst.remote_ip)) && - ! vxlan_group_used(vn, vxlan->default_dst.remote_ip)) { + vxlan_group_used(vn, vxlan->default_dst.remote_ip)) { vxlan_sock_hold(vs); dev_hold(dev); queue_work(vxlan_wq, &vxlan->igmp_join); @@ -1793,8 +1793,6 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head) struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); - flush_workqueue(vxlan_wq); - spin_lock(&vn->sock_lock); hlist_del_rcu(&vxlan->hlist); spin_unlock(&vn->sock_lock); diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c index 7365674366f4..010b252be584 100644 --- a/drivers/net/wireless/cw1200/sta.c +++ b/drivers/net/wireless/cw1200/sta.c @@ -1406,11 +1406,8 @@ static void cw1200_do_unjoin(struct cw1200_common *priv) if (!priv->join_status) goto done; - if (priv->join_status > CW1200_JOIN_STATUS_IBSS) { - wiphy_err(priv->hw->wiphy, "Unexpected: join status: %d\n", - priv->join_status); - BUG_ON(1); - } + if (priv->join_status == CW1200_JOIN_STATUS_AP) + goto done; cancel_work_sync(&priv->update_filtering_work); cancel_work_sync(&priv->set_beacon_wakeup_period_work); diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index ac074731335a..e5090309824e 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -523,9 +523,9 @@ static int prism2_ioctl_giwaplist(struct net_device *dev, data->length = prism2_ap_get_sta_qual(local, addr, qual, IW_MAX_AP, 1); - memcpy(extra, &addr, sizeof(struct sockaddr) * data->length); + memcpy(extra, addr, sizeof(struct sockaddr) * data->length); data->flags = 1; /* has quality information */ - memcpy(extra + sizeof(struct sockaddr) * data->length, &qual, + memcpy(extra + sizeof(struct sockaddr) * data->length, qual, sizeof(struct iw_quality) * data->length); kfree(addr); diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index b9b2bb51e605..f2ed62e37340 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -4460,12 +4460,12 @@ il4965_irq_tasklet(struct il_priv *il) * is killed. Hence update the killswitch state here. The * rfkill handler will care about restarting if needed. */ - if (!test_bit(S_ALIVE, &il->status)) { - if (hw_rf_kill) - set_bit(S_RFKILL, &il->status); - else - clear_bit(S_RFKILL, &il->status); + if (hw_rf_kill) { + set_bit(S_RFKILL, &il->status); + } else { + clear_bit(S_RFKILL, &il->status); wiphy_rfkill_set_hw_state(il->hw->wiphy, hw_rf_kill); + il_force_reset(il, true); } handled |= CSR_INT_BIT_RF_KILL; @@ -5334,6 +5334,9 @@ il4965_alive_start(struct il_priv *il) il->active_rate = RATES_MASK; + il_power_update_mode(il, true); + D_INFO("Updated power mode\n"); + if (il_is_associated(il)) { struct il_rxon_cmd *active_rxon = (struct il_rxon_cmd *)&il->active; @@ -5364,9 +5367,6 @@ il4965_alive_start(struct il_priv *il) D_INFO("ALIVE processing complete.\n"); wake_up(&il->wait_command_queue); - il_power_update_mode(il, true); - D_INFO("Updated power mode\n"); - return; restart: diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 3195aad440dd..b03e22ef5462 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -4660,6 +4660,7 @@ il_force_reset(struct il_priv *il, bool external) return 0; } +EXPORT_SYMBOL(il_force_reset); int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 822f1a00efbb..319387263e12 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1068,7 +1068,10 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) + if (!test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status)) + return; + + if (ctx->vif) ieee80211_chswitch_done(ctx->vif, is_success); } diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index a70c7b9d9bad..ff8cc75c189d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -97,8 +97,6 @@ #define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800) -#define APMG_RTC_INT_STT_RFKILL (0x10000000) - /* Device system time */ #define DEVICE_SYSTEM_TIME_REG 0xA0206C diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index ad9bbca99213..7fd6fbfbc1b3 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -138,6 +138,20 @@ static void iwl_mvm_roc_finished(struct iwl_mvm *mvm) schedule_work(&mvm->roc_done_wk); } +static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + const char *errmsg) +{ + if (vif->type != NL80211_IFTYPE_STATION) + return false; + if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) + return false; + if (errmsg) + IWL_ERR(mvm, "%s\n", errmsg); + ieee80211_connection_loss(vif); + return true; +} + /* * Handles a FW notification for an event that is known to the driver. * @@ -163,8 +177,13 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * P2P Device discoveribility, while there are other higher priority * events in the system). */ - WARN_ONCE(!le32_to_cpu(notif->status), - "Failed to schedule time event\n"); + if (WARN_ONCE(!le32_to_cpu(notif->status), + "Failed to schedule time event\n")) { + if (iwl_mvm_te_check_disconnect(mvm, te_data->vif, NULL)) { + iwl_mvm_te_clear_data(mvm, te_data); + return; + } + } if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_END) { IWL_DEBUG_TE(mvm, @@ -180,14 +199,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * By now, we should have finished association * and know the dtim period. */ - if (te_data->vif->type == NL80211_IFTYPE_STATION && - (!te_data->vif->bss_conf.assoc || - !te_data->vif->bss_conf.dtim_period)) { - IWL_ERR(mvm, - "No assocation and the time event is over already...\n"); - ieee80211_connection_loss(te_data->vif); - } - + iwl_mvm_te_check_disconnect(mvm, te_data->vif, + "No assocation and the time event is over already..."); iwl_mvm_te_clear_data(mvm, te_data); } else if (le32_to_cpu(notif->action) & TE_NOTIF_HOST_EVENT_START) { te_data->running = true; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index f600e68a410a..fd848cd1583e 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -888,14 +888,6 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); if (hw_rfkill) { - /* - * Clear the interrupt in APMG if the NIC is going down. - * Note that when the NIC exits RFkill (else branch), we - * can't access prph and the NIC will be reset in - * start_hw anyway. - */ - iwl_write_prph(trans, APMG_RTC_INT_STT_REG, - APMG_RTC_INT_STT_RFKILL); set_bit(STATUS_RFKILL, &trans_pcie->status); if (test_and_clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 96cfcdd39079..390e2f058aff 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1502,16 +1502,16 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, spin_lock_init(&trans_pcie->reg_lock); init_waitqueue_head(&trans_pcie->ucode_write_waitq); - /* W/A - seems to solve weird behavior. We need to remove this if we - * don't want to stay in L1 all the time. This wastes a lot of power */ - pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | - PCIE_LINK_STATE_CLKPM); - if (pci_enable_device(pdev)) { err = -ENODEV; goto out_no_pci; } + /* W/A - seems to solve weird behavior. We need to remove this if we + * don't want to stay in L1 all the time. This wastes a lot of power */ + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | + PCIE_LINK_STATE_CLKPM); + pci_set_master(pdev); err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36)); diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index 4941f201d6c8..b8ba1f925e75 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -98,10 +98,12 @@ static int zd1201_fw_upload(struct usb_device *dev, int apfw) goto exit; err = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), 0x4, - USB_DIR_IN | 0x40, 0,0, &ret, sizeof(ret), ZD1201_FW_TIMEOUT); + USB_DIR_IN | 0x40, 0, 0, buf, sizeof(ret), ZD1201_FW_TIMEOUT); if (err < 0) goto exit; + memcpy(&ret, buf, sizeof(ret)); + if (ret & 0x80) { err = -EIO; goto exit; diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 6bb7cf2de556..b10ba00cc3e6 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -392,6 +392,8 @@ static void __unflatten_device_tree(struct boot_param_header *blob, mem = (unsigned long) dt_alloc(size + 4, __alignof__(struct device_node)); + memset((void *)mem, 0, size); + ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef); pr_debug(" unflattening %lx...\n", mem); diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c index c47fd1e5450b..94716c779800 100644 --- a/drivers/pinctrl/pinctrl-sunxi.c +++ b/drivers/pinctrl/pinctrl-sunxi.c @@ -278,6 +278,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, { struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); struct sunxi_pinctrl_group *g = &pctl->groups[group]; + unsigned long flags; u32 val, mask; u16 strength; u8 dlevel; @@ -295,22 +296,35 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, * 3: 40mA */ dlevel = strength / 10 - 1; + + spin_lock_irqsave(&pctl->lock, flags); + val = readl(pctl->membase + sunxi_dlevel_reg(g->pin)); mask = DLEVEL_PINS_MASK << sunxi_dlevel_offset(g->pin); writel((val & ~mask) | dlevel << sunxi_dlevel_offset(g->pin), pctl->membase + sunxi_dlevel_reg(g->pin)); + + spin_unlock_irqrestore(&pctl->lock, flags); break; case PIN_CONFIG_BIAS_PULL_UP: + spin_lock_irqsave(&pctl->lock, flags); + val = readl(pctl->membase + sunxi_pull_reg(g->pin)); mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin); writel((val & ~mask) | 1 << sunxi_pull_offset(g->pin), pctl->membase + sunxi_pull_reg(g->pin)); + + spin_unlock_irqrestore(&pctl->lock, flags); break; case PIN_CONFIG_BIAS_PULL_DOWN: + spin_lock_irqsave(&pctl->lock, flags); + val = readl(pctl->membase + sunxi_pull_reg(g->pin)); mask = PULL_PINS_MASK << sunxi_pull_offset(g->pin); writel((val & ~mask) | 2 << sunxi_pull_offset(g->pin), pctl->membase + sunxi_pull_reg(g->pin)); + + spin_unlock_irqrestore(&pctl->lock, flags); break; default: break; @@ -360,11 +374,17 @@ static void sunxi_pmx_set(struct pinctrl_dev *pctldev, u8 config) { struct sunxi_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); + unsigned long flags; + u32 val, mask; + + spin_lock_irqsave(&pctl->lock, flags); - u32 val = readl(pctl->membase + sunxi_mux_reg(pin)); - u32 mask = MUX_PINS_MASK << sunxi_mux_offset(pin); + val = readl(pctl->membase + sunxi_mux_reg(pin)); + mask = MUX_PINS_MASK << sunxi_mux_offset(pin); writel((val & ~mask) | config << sunxi_mux_offset(pin), pctl->membase + sunxi_mux_reg(pin)); + + spin_unlock_irqrestore(&pctl->lock, flags); } static int sunxi_pmx_enable(struct pinctrl_dev *pctldev, @@ -464,8 +484,21 @@ static void sunxi_pinctrl_gpio_set(struct gpio_chip *chip, struct sunxi_pinctrl *pctl = dev_get_drvdata(chip->dev); u32 reg = sunxi_data_reg(offset); u8 index = sunxi_data_offset(offset); + unsigned long flags; + u32 regval; + + spin_lock_irqsave(&pctl->lock, flags); + + regval = readl(pctl->membase + reg); - writel((value & DATA_PINS_MASK) << index, pctl->membase + reg); + if (value) + regval |= BIT(index); + else + regval &= ~(BIT(index)); + + writel(regval, pctl->membase + reg); + + spin_unlock_irqrestore(&pctl->lock, flags); } static int sunxi_pinctrl_gpio_of_xlate(struct gpio_chip *gc, @@ -526,6 +559,8 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d, struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); u32 reg = sunxi_irq_cfg_reg(d->hwirq); u8 index = sunxi_irq_cfg_offset(d->hwirq); + unsigned long flags; + u32 regval; u8 mode; switch (type) { @@ -548,7 +583,13 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d, return -EINVAL; } - writel((mode & IRQ_CFG_IRQ_MASK) << index, pctl->membase + reg); + spin_lock_irqsave(&pctl->lock, flags); + + regval = readl(pctl->membase + reg); + regval &= ~IRQ_CFG_IRQ_MASK; + writel(regval | (mode << index), pctl->membase + reg); + + spin_unlock_irqrestore(&pctl->lock, flags); return 0; } @@ -560,14 +601,19 @@ static void sunxi_pinctrl_irq_mask_ack(struct irq_data *d) u8 ctrl_idx = sunxi_irq_ctrl_offset(d->hwirq); u32 status_reg = sunxi_irq_status_reg(d->hwirq); u8 status_idx = sunxi_irq_status_offset(d->hwirq); + unsigned long flags; u32 val; + spin_lock_irqsave(&pctl->lock, flags); + /* Mask the IRQ */ val = readl(pctl->membase + ctrl_reg); writel(val & ~(1 << ctrl_idx), pctl->membase + ctrl_reg); /* Clear the IRQ */ writel(1 << status_idx, pctl->membase + status_reg); + + spin_unlock_irqrestore(&pctl->lock, flags); } static void sunxi_pinctrl_irq_mask(struct irq_data *d) @@ -575,11 +621,16 @@ static void sunxi_pinctrl_irq_mask(struct irq_data *d) struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); u32 reg = sunxi_irq_ctrl_reg(d->hwirq); u8 idx = sunxi_irq_ctrl_offset(d->hwirq); + unsigned long flags; u32 val; + spin_lock_irqsave(&pctl->lock, flags); + /* Mask the IRQ */ val = readl(pctl->membase + reg); writel(val & ~(1 << idx), pctl->membase + reg); + + spin_unlock_irqrestore(&pctl->lock, flags); } static void sunxi_pinctrl_irq_unmask(struct irq_data *d) @@ -588,6 +639,7 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d) struct sunxi_desc_function *func; u32 reg = sunxi_irq_ctrl_reg(d->hwirq); u8 idx = sunxi_irq_ctrl_offset(d->hwirq); + unsigned long flags; u32 val; func = sunxi_pinctrl_desc_find_function_by_pin(pctl, @@ -597,9 +649,13 @@ static void sunxi_pinctrl_irq_unmask(struct irq_data *d) /* Change muxing to INT mode */ sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], func->muxval); + spin_lock_irqsave(&pctl->lock, flags); + /* Unmask the IRQ */ val = readl(pctl->membase + reg); writel(val | (1 << idx), pctl->membase + reg); + + spin_unlock_irqrestore(&pctl->lock, flags); } static struct irq_chip sunxi_pinctrl_irq_chip = { @@ -752,6 +808,8 @@ static int sunxi_pinctrl_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, pctl); + spin_lock_init(&pctl->lock); + pctl->membase = of_iomap(node, 0); if (!pctl->membase) return -ENOMEM; diff --git a/drivers/pinctrl/pinctrl-sunxi.h b/drivers/pinctrl/pinctrl-sunxi.h index d68047d8f699..01c494f8a14f 100644 --- a/drivers/pinctrl/pinctrl-sunxi.h +++ b/drivers/pinctrl/pinctrl-sunxi.h @@ -14,6 +14,7 @@ #define __PINCTRL_SUNXI_H #include <linux/kernel.h> +#include <linux/spinlock.h> #define PA_BASE 0 #define PB_BASE 32 @@ -407,6 +408,7 @@ struct sunxi_pinctrl { unsigned ngroups; int irq; int irq_array[SUNXI_IRQ_NUMBER]; + spinlock_t lock; struct pinctrl_dev *pctl_dev; }; diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c index 0f9f8596b300..f9119525f557 100644 --- a/drivers/platform/olpc/olpc-ec.c +++ b/drivers/platform/olpc/olpc-ec.c @@ -330,7 +330,7 @@ static int __init olpc_ec_init_module(void) return platform_driver_register(&olpc_ec_plat_driver); } -module_init(olpc_ec_init_module); +arch_initcall(olpc_ec_init_module); MODULE_AUTHOR("Andres Salomon <dilinger@queued.net>"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 97bb05edcb5a..d6970f47ae72 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -53,7 +53,6 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); #define HPWMI_ALS_QUERY 0x3 #define HPWMI_HARDWARE_QUERY 0x4 #define HPWMI_WIRELESS_QUERY 0x5 -#define HPWMI_BIOS_QUERY 0x9 #define HPWMI_HOTKEY_QUERY 0xc #define HPWMI_WIRELESS2_QUERY 0x1b #define HPWMI_POSTCODEERROR_QUERY 0x2a @@ -293,19 +292,6 @@ static int hp_wmi_tablet_state(void) return (state & 0x4) ? 1 : 0; } -static int hp_wmi_enable_hotkeys(void) -{ - int ret; - int query = 0x6e; - - ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, 1, &query, sizeof(query), - 0); - - if (ret) - return -EINVAL; - return 0; -} - static int hp_wmi_set_block(void *data, bool blocked) { enum hp_wmi_radio r = (enum hp_wmi_radio) data; @@ -1009,8 +995,6 @@ static int __init hp_wmi_init(void) err = hp_wmi_input_setup(); if (err) return err; - - hp_wmi_enable_hotkeys(); } if (bios_capable) { diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 2ac045f27f10..3a1b6bf326a8 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -2440,7 +2440,10 @@ static ssize_t sony_nc_gfx_switch_status_show(struct device *dev, if (pos < 0) return pos; - return snprintf(buffer, PAGE_SIZE, "%s\n", pos ? "speed" : "stamina"); + return snprintf(buffer, PAGE_SIZE, "%s\n", + pos == SPEED ? "speed" : + pos == STAMINA ? "stamina" : + pos == AUTO ? "auto" : "unknown"); } static int sony_nc_gfx_switch_setup(struct platform_device *pd, @@ -4320,7 +4323,8 @@ static int sony_pic_add(struct acpi_device *device) goto err_free_resources; } - if (sonypi_compat_init()) + result = sonypi_compat_init(); + if (result) goto err_remove_input; /* request io port */ diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 767fee2ab340..26019531db15 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/interrupt.h> +#include <linux/delay.h> #include <linux/rtc.h> #include <linux/slab.h> #include <linux/of_device.h> @@ -119,24 +120,39 @@ static void stmp3xxx_wdt_register(struct platform_device *rtc_pdev) } #endif /* CONFIG_STMP3XXX_RTC_WATCHDOG */ -static void stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) +static int stmp3xxx_wait_time(struct stmp3xxx_rtc_data *rtc_data) { + int timeout = 5000; /* 3ms according to i.MX28 Ref Manual */ /* - * The datasheet doesn't say which way round the - * NEW_REGS/STALE_REGS bitfields go. In fact it's 0x1=P0, - * 0x2=P1, .., 0x20=P5, 0x40=ALARM, 0x80=SECONDS + * The i.MX28 Applications Processor Reference Manual, Rev. 1, 2010 + * states: + * | The order in which registers are updated is + * | Persistent 0, 1, 2, 3, 4, 5, Alarm, Seconds. + * | (This list is in bitfield order, from LSB to MSB, as they would + * | appear in the STALE_REGS and NEW_REGS bitfields of the HW_RTC_STAT + * | register. For example, the Seconds register corresponds to + * | STALE_REGS or NEW_REGS containing 0x80.) */ - while (readl(rtc_data->io + STMP3XXX_RTC_STAT) & - (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) - cpu_relax(); + do { + if (!(readl(rtc_data->io + STMP3XXX_RTC_STAT) & + (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT))) + return 0; + udelay(1); + } while (--timeout > 0); + return (readl(rtc_data->io + STMP3XXX_RTC_STAT) & + (0x80 << STMP3XXX_RTC_STAT_STALE_SHIFT)) ? -ETIME : 0; } /* Time read/write */ static int stmp3xxx_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { + int ret; struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); - stmp3xxx_wait_time(rtc_data); + ret = stmp3xxx_wait_time(rtc_data); + if (ret) + return ret; + rtc_time_to_tm(readl(rtc_data->io + STMP3XXX_RTC_SECONDS), rtc_tm); return 0; } @@ -146,8 +162,7 @@ static int stmp3xxx_rtc_set_mmss(struct device *dev, unsigned long t) struct stmp3xxx_rtc_data *rtc_data = dev_get_drvdata(dev); writel(t, rtc_data->io + STMP3XXX_RTC_SECONDS); - stmp3xxx_wait_time(rtc_data); - return 0; + return stmp3xxx_wait_time(rtc_data); } /* interrupt(s) handler */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 1d4c8fe72752..c82fe65c4128 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -102,10 +102,13 @@ static void zfcp_erp_action_dismiss_port(struct zfcp_port *port) if (atomic_read(&port->status) & ZFCP_STATUS_COMMON_ERP_INUSE) zfcp_erp_action_dismiss(&port->erp_action); - else - shost_for_each_device(sdev, port->adapter->scsi_host) + else { + spin_lock(port->adapter->scsi_host->host_lock); + __shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) zfcp_erp_action_dismiss_lun(sdev); + spin_unlock(port->adapter->scsi_host->host_lock); + } } static void zfcp_erp_action_dismiss_adapter(struct zfcp_adapter *adapter) @@ -592,9 +595,11 @@ static void _zfcp_erp_lun_reopen_all(struct zfcp_port *port, int clear, { struct scsi_device *sdev; - shost_for_each_device(sdev, port->adapter->scsi_host) + spin_lock(port->adapter->scsi_host->host_lock); + __shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) _zfcp_erp_lun_reopen(sdev, clear, id, 0); + spin_unlock(port->adapter->scsi_host->host_lock); } static void zfcp_erp_strategy_followup_failed(struct zfcp_erp_action *act) @@ -1434,8 +1439,10 @@ void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask) atomic_set_mask(common_mask, &port->status); read_unlock_irqrestore(&adapter->port_list_lock, flags); - shost_for_each_device(sdev, adapter->scsi_host) + spin_lock_irqsave(adapter->scsi_host->host_lock, flags); + __shost_for_each_device(sdev, adapter->scsi_host) atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status); + spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags); } /** @@ -1469,11 +1476,13 @@ void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) } read_unlock_irqrestore(&adapter->port_list_lock, flags); - shost_for_each_device(sdev, adapter->scsi_host) { + spin_lock_irqsave(adapter->scsi_host->host_lock, flags); + __shost_for_each_device(sdev, adapter->scsi_host) { atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status); if (clear_counter) atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); } + spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags); } /** @@ -1487,16 +1496,19 @@ void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask) { struct scsi_device *sdev; u32 common_mask = mask & ZFCP_COMMON_FLAGS; + unsigned long flags; atomic_set_mask(mask, &port->status); if (!common_mask) return; - shost_for_each_device(sdev, port->adapter->scsi_host) + spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); + __shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status); + spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags); } /** @@ -1511,6 +1523,7 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) struct scsi_device *sdev; u32 common_mask = mask & ZFCP_COMMON_FLAGS; u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; + unsigned long flags; atomic_clear_mask(mask, &port->status); @@ -1520,13 +1533,15 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) if (clear_counter) atomic_set(&port->erp_counter, 0); - shost_for_each_device(sdev, port->adapter->scsi_host) + spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); + __shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) { atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status); if (clear_counter) atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); } + spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags); } /** diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 665e3cfaaf85..de0598eaacd2 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -224,11 +224,9 @@ int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *qdio, struct zfcp_qdio_req *q_req, static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio) { - spin_lock_irq(&qdio->req_q_lock); if (atomic_read(&qdio->req_q_free) || !(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return 1; - spin_unlock_irq(&qdio->req_q_lock); return 0; } @@ -246,9 +244,8 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) { long ret; - spin_unlock_irq(&qdio->req_q_lock); - ret = wait_event_interruptible_timeout(qdio->req_q_wq, - zfcp_qdio_sbal_check(qdio), 5 * HZ); + ret = wait_event_interruptible_lock_irq_timeout(qdio->req_q_wq, + zfcp_qdio_sbal_check(qdio), qdio->req_q_lock, 5 * HZ); if (!(atomic_read(&qdio->adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP)) return -EIO; @@ -262,7 +259,6 @@ int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio) zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdsbg_1"); } - spin_lock_irq(&qdio->req_q_lock); return -EIO; } diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 3f01bbf0609f..890639274bcf 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -27,6 +27,16 @@ static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ zfcp_sysfs_##_feat##_##_name##_show, NULL); +#define ZFCP_DEFINE_ATTR_CONST(_feat, _name, _format, _value) \ +static ssize_t zfcp_sysfs_##_feat##_##_name##_show(struct device *dev, \ + struct device_attribute *at,\ + char *buf) \ +{ \ + return sprintf(buf, _format, _value); \ +} \ +static ZFCP_DEV_ATTR(_feat, _name, S_IRUGO, \ + zfcp_sysfs_##_feat##_##_name##_show, NULL); + #define ZFCP_DEFINE_A_ATTR(_name, _format, _value) \ static ssize_t zfcp_sysfs_adapter_##_name##_show(struct device *dev, \ struct device_attribute *at,\ @@ -75,6 +85,8 @@ ZFCP_DEFINE_ATTR(zfcp_unit, unit, in_recovery, "%d\n", ZFCP_DEFINE_ATTR(zfcp_unit, unit, access_denied, "%d\n", (zfcp_unit_sdev_status(unit) & ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0); +ZFCP_DEFINE_ATTR_CONST(unit, access_shared, "%d\n", 0); +ZFCP_DEFINE_ATTR_CONST(unit, access_readonly, "%d\n", 0); static ssize_t zfcp_sysfs_port_failed_show(struct device *dev, struct device_attribute *attr, @@ -347,6 +359,8 @@ static struct attribute *zfcp_unit_attrs[] = { &dev_attr_unit_in_recovery.attr, &dev_attr_unit_status.attr, &dev_attr_unit_access_denied.attr, + &dev_attr_unit_access_shared.attr, + &dev_attr_unit_access_readonly.attr, NULL }; static struct attribute_group zfcp_unit_attr_group = { diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 48b2918e0d65..92ff027746f2 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1353,7 +1353,6 @@ config SCSI_LPFC tristate "Emulex LightPulse Fibre Channel Support" depends on PCI && SCSI select SCSI_FC_ATTRS - select GENERIC_CSUM select CRC_T10DIF help This lpfc driver supports the Emulex LightPulse diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 89cbbabaff44..f552c89abdd4 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -70,14 +70,14 @@ config SPI_ATH79 config SPI_ATMEL tristate "Atmel SPI Controller" - depends on (ARCH_AT91 || AVR32) + depends on (ARCH_AT91 || AVR32 || COMPILE_TEST) help This selects a driver for the Atmel SPI Controller, present on many AT32 (AVR32) and AT91 (ARM) chips. config SPI_BCM2835 tristate "BCM2835 SPI controller" - depends on ARCH_BCM2835 + depends on ARCH_BCM2835 || COMPILE_TEST help This selects a driver for the Broadcom BCM2835 SPI master. @@ -88,10 +88,17 @@ config SPI_BCM2835 config SPI_BFIN5XX tristate "SPI controller driver for ADI Blackfin5xx" - depends on BLACKFIN + depends on BLACKFIN && !BF60x help This is the SPI controller master driver for Blackfin 5xx processor. +config SPI_BFIN_V3 + tristate "SPI controller v3 for Blackfin" + depends on BF60x + help + This is the SPI controller v3 master driver + found on Blackfin 60x processor. + config SPI_BFIN_SPORT tristate "SPI bus via Blackfin SPORT" depends on BLACKFIN @@ -151,15 +158,22 @@ config SPI_COLDFIRE_QSPI config SPI_DAVINCI tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller" - depends on ARCH_DAVINCI + depends on ARCH_DAVINCI || ARCH_KEYSTONE select SPI_BITBANG select TI_EDMA help SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules. +config SPI_EFM32 + tristate "EFM32 SPI controller" + depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST) + select SPI_BITBANG + help + Driver for the spi controller found on Energy Micro's EFM32 SoCs. + config SPI_EP93XX tristate "Cirrus Logic EP93xx SPI controller" - depends on ARCH_EP93XX + depends on ARCH_EP93XX || COMPILE_TEST help This enables using the Cirrus EP93xx SPI controller in master mode. @@ -191,7 +205,7 @@ config SPI_GPIO config SPI_IMX tristate "Freescale i.MX SPI controllers" - depends on ARCH_MXC + depends on ARCH_MXC || COMPILE_TEST select SPI_BITBANG default m if IMX_HAVE_PLATFORM_SPI_IMX help @@ -248,6 +262,13 @@ config SPI_FSL_SPI This also enables using the Aeroflex Gaisler GRLIB SPI controller in master mode. +config SPI_FSL_DSPI + tristate "Freescale DSPI controller" + select SPI_BITBANG + help + This enables support for the Freescale DSPI controller in master + mode. VF610 platform uses the controller. + config SPI_FSL_ESPI bool "Freescale eSPI controller" depends on FSL_SOC @@ -280,20 +301,28 @@ config SPI_OMAP_UWIRE config SPI_OMAP24XX tristate "McSPI driver for OMAP" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || COMPILE_TEST help SPI master controller for OMAP24XX and later Multichannel SPI (McSPI) modules. +config SPI_TI_QSPI + tristate "DRA7xxx QSPI controller support" + depends on ARCH_OMAP2PLUS || COMPILE_TEST + help + QSPI master controller for DRA7xxx used for flash devices. + This device supports single, dual and quad read support, while + it only supports single write mode. + config SPI_OMAP_100K tristate "OMAP SPI 100K" - depends on ARCH_OMAP850 || ARCH_OMAP730 + depends on ARCH_OMAP850 || ARCH_OMAP730 || COMPILE_TEST help OMAP SPI 100K master controller for omap7xx boards. config SPI_ORION tristate "Orion SPI master" - depends on PLAT_ORION + depends on PLAT_ORION || COMPILE_TEST help This enables using the SPI master controller on the Orion chips. @@ -341,7 +370,7 @@ config SPI_PXA2XX_PCI config SPI_RSPI tristate "Renesas RSPI controller" - depends on SUPERH + depends on SUPERH && SH_DMAE_BASE help SPI driver for Renesas RSPI blocks. @@ -385,7 +414,7 @@ config SPI_SH_MSIOF config SPI_SH tristate "SuperH SPI controller" - depends on SUPERH + depends on SUPERH || COMPILE_TEST help SPI driver for SuperH SPI blocks. @@ -398,7 +427,7 @@ config SPI_SH_SCI config SPI_SH_HSPI tristate "SuperH HSPI controller" - depends on ARCH_SHMOBILE + depends on ARCH_SHMOBILE || COMPILE_TEST help SPI driver for SuperH HSPI blocks. @@ -418,7 +447,7 @@ config SPI_MXS config SPI_TEGRA114 tristate "NVIDIA Tegra114 SPI Controller" - depends on ARCH_TEGRA && TEGRA20_APB_DMA + depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST help SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller is different than the older SoCs SPI controller and also register interface @@ -426,7 +455,7 @@ config SPI_TEGRA114 config SPI_TEGRA20_SFLASH tristate "Nvidia Tegra20 Serial flash Controller" - depends on ARCH_TEGRA + depends on ARCH_TEGRA || COMPILE_TEST help SPI driver for Nvidia Tegra20 Serial flash Controller interface. The main usecase of this controller is to use spi flash as boot @@ -434,7 +463,7 @@ config SPI_TEGRA20_SFLASH config SPI_TEGRA20_SLINK tristate "Nvidia Tegra20/Tegra30 SLINK Controller" - depends on ARCH_TEGRA && TEGRA20_APB_DMA + depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST help SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. @@ -457,7 +486,7 @@ config SPI_TOPCLIFF_PCH config SPI_TXX9 tristate "Toshiba TXx9 SPI controller" - depends on GPIOLIB && CPU_TX49XX + depends on GPIOLIB && (CPU_TX49XX || COMPILE_TEST) help SPI driver for Toshiba TXx9 MIPS SoCs diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 33f9c09561e7..ab8d8644af0e 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_BCM2835) += spi-bcm2835.o obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o obj-$(CONFIG_SPI_BFIN5XX) += spi-bfin5xx.o +obj-$(CONFIG_SPI_BFIN_V3) += spi-bfin-v3.o obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o @@ -27,9 +28,11 @@ obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o +obj-$(CONFIG_SPI_EFM32) += spi-efm32.o obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o obj-$(CONFIG_SPI_FALCON) += spi-falcon.o obj-$(CONFIG_SPI_FSL_CPM) += spi-fsl-cpm.o +obj-$(CONFIG_SPI_FSL_DSPI) += spi-fsl-dspi.o obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o @@ -46,6 +49,7 @@ obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o +obj-$(CONFIG_SPI_TI_QSPI) += spi-ti-qspi.o obj-$(CONFIG_SPI_ORION) += spi-orion.o obj-$(CONFIG_SPI_PL022) += spi-pl022.o obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index 81b9adb6e766..f38855f76536 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -103,16 +103,6 @@ static void altera_spi_chipsel(struct spi_device *spi, int value) } } -static int altera_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) -{ - return 0; -} - -static int altera_spi_setup(struct spi_device *spi) -{ - return 0; -} - static inline unsigned int hw_txbyte(struct altera_spi *hw, int count) { if (hw->tx) { @@ -134,7 +124,7 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t) hw->tx = t->tx_buf; hw->rx = t->rx_buf; hw->count = 0; - hw->bytes_per_word = t->bits_per_word / 8; + hw->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8); hw->len = t->len / hw->bytes_per_word; if (hw->irq >= 0) { @@ -150,12 +140,12 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t) hw->imr &= ~ALTERA_SPI_CONTROL_IRRDY_MSK; writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); } else { - /* send the first byte */ - writel(hw_txbyte(hw, 0), hw->base + ALTERA_SPI_TXDATA); - - while (1) { + while (hw->count < hw->len) { unsigned int rxd; + writel(hw_txbyte(hw, hw->count), + hw->base + ALTERA_SPI_TXDATA); + while (!(readl(hw->base + ALTERA_SPI_STATUS) & ALTERA_SPI_STATUS_RRDY_MSK)) cpu_relax(); @@ -174,14 +164,7 @@ static int altera_spi_txrx(struct spi_device *spi, struct spi_transfer *t) } hw->count++; - - if (hw->count < hw->len) - writel(hw_txbyte(hw, hw->count), - hw->base + ALTERA_SPI_TXDATA); - else - break; } - } return hw->count * hw->bytes_per_word; @@ -217,7 +200,7 @@ static irqreturn_t altera_spi_irq(int irq, void *dev) static int altera_spi_probe(struct platform_device *pdev) { - struct altera_spi_platform_data *platp = pdev->dev.platform_data; + struct altera_spi_platform_data *platp = dev_get_platdata(&pdev->dev); struct altera_spi *hw; struct spi_master *master; struct resource *res; @@ -231,7 +214,6 @@ static int altera_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = 16; master->mode_bits = SPI_CS_HIGH; - master->setup = altera_spi_setup; hw = spi_master_get_devdata(master); platform_set_drvdata(pdev, hw); @@ -240,21 +222,16 @@ static int altera_spi_probe(struct platform_device *pdev) hw->bitbang.master = spi_master_get(master); if (!hw->bitbang.master) return err; - hw->bitbang.setup_transfer = altera_spi_setupxfer; hw->bitbang.chipselect = altera_spi_chipsel; hw->bitbang.txrx_bufs = altera_spi_txrx; /* find and map our resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - goto exit_busy; - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) - goto exit_busy; - hw->base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!hw->base) - goto exit_busy; + hw->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->base)) { + err = PTR_ERR(hw->base); + goto exit; + } /* program defaults into the registers */ hw->imr = 0; /* disable spi interrupts */ writel(hw->imr, hw->base + ALTERA_SPI_CONTROL); @@ -281,9 +258,6 @@ static int altera_spi_probe(struct platform_device *pdev) dev_info(&pdev->dev, "base %p, irq %d\n", hw->base, hw->irq); return 0; - -exit_busy: - err = -EBUSY; exit: spi_master_put(master); return err; diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 0e06407a4670..37bad952ab38 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -221,7 +221,7 @@ static int ath79_spi_probe(struct platform_device *pdev) sp = spi_master_get_devdata(master); platform_set_drvdata(pdev, sp); - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); master->setup = ath79_spi_setup; diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index ea1ec009f44d..fd7cc566095a 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -360,12 +360,12 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) gpio_set_value(asd->npcs_pin, !active); } -static void atmel_spi_lock(struct atmel_spi *as) +static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock) { spin_lock_irqsave(&as->lock, as->flags); } -static void atmel_spi_unlock(struct atmel_spi *as) +static void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock) { spin_unlock_irqrestore(&as->lock, as->flags); } @@ -629,9 +629,9 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, goto err_dma; dev_dbg(master->dev.parent, - " start dma xfer %p: len %u tx %p/%08x rx %p/%08x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); + " start dma xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", + xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma, + xfer->rx_buf, (unsigned long long)xfer->rx_dma); /* Enable relevant interrupts */ spi_writel(as, IER, SPI_BIT(OVRES)); @@ -732,9 +732,10 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master, spi_writel(as, TCR, len); dev_dbg(&msg->spi->dev, - " start xfer %p: len %u tx %p/%08x rx %p/%08x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); + " start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", + xfer, xfer->len, xfer->tx_buf, + (unsigned long long)xfer->tx_dma, xfer->rx_buf, + (unsigned long long)xfer->rx_dma); } else { xfer = as->next_transfer; remaining = as->next_remaining_bytes; @@ -771,9 +772,10 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master, spi_writel(as, TNCR, len); dev_dbg(&msg->spi->dev, - " next xfer %p: len %u tx %p/%08x rx %p/%08x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); + " next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", + xfer, xfer->len, xfer->tx_buf, + (unsigned long long)xfer->tx_dma, xfer->rx_buf, + (unsigned long long)xfer->rx_dma); ieval = SPI_BIT(ENDRX) | SPI_BIT(OVRES); } else { spi_writel(as, RNCR, 0); @@ -1579,7 +1581,9 @@ static int atmel_spi_probe(struct platform_device *pdev) goto out_unmap_regs; /* Initialize the hardware */ - clk_enable(clk); + ret = clk_prepare_enable(clk); + if (ret) + goto out_unmap_regs; spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ if (as->caps.has_wdrbt) { @@ -1609,7 +1613,7 @@ out_free_dma: spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ - clk_disable(clk); + clk_disable_unprepare(clk); free_irq(irq, master); out_unmap_regs: iounmap(as->regs); @@ -1661,7 +1665,7 @@ static int atmel_spi_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer, as->buffer_dma); - clk_disable(as->clk); + clk_disable_unprepare(as->clk); clk_put(as->clk); free_irq(as->irq, master); iounmap(as->regs); @@ -1678,7 +1682,7 @@ static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg) struct spi_master *master = platform_get_drvdata(pdev); struct atmel_spi *as = spi_master_get_devdata(master); - clk_disable(as->clk); + clk_disable_unprepare(as->clk); return 0; } @@ -1687,7 +1691,7 @@ static int atmel_spi_resume(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct atmel_spi *as = spi_master_get_devdata(master); - clk_enable(as->clk); + return clk_prepare_enable(as->clk); return 0; } diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index e1965553ab79..1d00d9b397dd 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -776,7 +776,7 @@ static int au1550_spi_probe(struct platform_device *pdev) hw = spi_master_get_devdata(master); hw->master = spi_master_get(master); - hw->pdata = pdev->dev.platform_data; + hw->pdata = dev_get_platdata(&pdev->dev); hw->dev = &pdev->dev; if (hw->pdata == NULL) { diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index a4185e492321..52c81481c5c7 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -314,7 +314,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); master->mode_bits = BCM2835_SPI_MODE_BITS; - master->bits_per_word_mask = BIT(8 - 1); + master->bits_per_word_mask = SPI_BPW_MASK(8); master->bus_num = -1; master->num_chipselect = 3; master->transfer_one_message = bcm2835_spi_transfer_one; @@ -325,12 +325,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev) init_completion(&bs->done); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "could not get memory resource\n"); - err = -ENODEV; - goto out_master_put; - } - bs->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(bs->regs)) { err = PTR_ERR(bs->regs); @@ -383,7 +377,7 @@ out_master_put: static int bcm2835_spi_remove(struct platform_device *pdev) { - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = spi_master_get(platform_get_drvdata(pdev)); struct bcm2835_spi *bs = spi_master_get_devdata(master); free_irq(bs->irq, master); diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 9fd7a39b8029..536b0e363826 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -231,24 +231,6 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first, return 0; } -static int bcm63xx_spi_prepare_transfer(struct spi_master *master) -{ - struct bcm63xx_spi *bs = spi_master_get_devdata(master); - - pm_runtime_get_sync(&bs->pdev->dev); - - return 0; -} - -static int bcm63xx_spi_unprepare_transfer(struct spi_master *master) -{ - struct bcm63xx_spi *bs = spi_master_get_devdata(master); - - pm_runtime_put(&bs->pdev->dev); - - return 0; -} - static int bcm63xx_spi_transfer_one(struct spi_master *master, struct spi_message *m) { @@ -353,20 +335,13 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) { struct resource *r; struct device *dev = &pdev->dev; - struct bcm63xx_spi_pdata *pdata = pdev->dev.platform_data; + struct bcm63xx_spi_pdata *pdata = dev_get_platdata(&pdev->dev); int irq; struct spi_master *master; struct clk *clk; struct bcm63xx_spi *bs; int ret; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) { - dev_err(dev, "no iomem\n"); - ret = -ENXIO; - goto out; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "no irq\n"); @@ -393,6 +368,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); bs->pdev = pdev; + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); bs->regs = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(bs->regs)) { ret = PTR_ERR(bs->regs); @@ -412,11 +388,10 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) master->bus_num = pdata->bus_num; master->num_chipselect = pdata->num_chipselect; - master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer; - master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer; master->transfer_one_message = bcm63xx_spi_transfer_one; master->mode_bits = MODEBITS; master->bits_per_word_mask = SPI_BPW_MASK(8); + master->auto_runtime_pm = true; bs->msg_type_shift = pdata->msg_type_shift; bs->msg_ctl_width = pdata->msg_ctl_width; bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA)); @@ -480,8 +455,7 @@ static int bcm63xx_spi_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bcm63xx_spi_suspend(struct device *dev) { - struct spi_master *master = - platform_get_drvdata(to_platform_device(dev)); + struct spi_master *master = dev_get_drvdata(dev); struct bcm63xx_spi *bs = spi_master_get_devdata(master); spi_master_suspend(master); @@ -493,8 +467,7 @@ static int bcm63xx_spi_suspend(struct device *dev) static int bcm63xx_spi_resume(struct device *dev) { - struct spi_master *master = - platform_get_drvdata(to_platform_device(dev)); + struct spi_master *master = dev_get_drvdata(dev); struct bcm63xx_spi *bs = spi_master_get_devdata(master); clk_prepare_enable(bs->clk); diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c index 07ec597f9732..91921b5f5817 100644 --- a/drivers/spi/spi-bfin-sport.c +++ b/drivers/spi/spi-bfin-sport.c @@ -756,7 +756,7 @@ static int bfin_sport_spi_probe(struct platform_device *pdev) struct bfin_sport_spi_master_data *drv_data; int status; - platform_info = dev->platform_data; + platform_info = dev_get_platdata(dev); /* Allocate master with space for drv_data */ master = spi_alloc_master(dev, sizeof(*master) + 16); diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c new file mode 100644 index 000000000000..f4bf81347d68 --- /dev/null +++ b/drivers/spi/spi-bfin-v3.c @@ -0,0 +1,965 @@ +/* + * Analog Devices SPI3 controller driver + * + * Copyright (c) 2013 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/types.h> + +#include <asm/bfin_spi3.h> +#include <asm/cacheflush.h> +#include <asm/dma.h> +#include <asm/portmux.h> + +enum bfin_spi_state { + START_STATE, + RUNNING_STATE, + DONE_STATE, + ERROR_STATE +}; + +struct bfin_spi_master; + +struct bfin_spi_transfer_ops { + void (*write) (struct bfin_spi_master *); + void (*read) (struct bfin_spi_master *); + void (*duplex) (struct bfin_spi_master *); +}; + +/* runtime info for spi master */ +struct bfin_spi_master { + /* SPI framework hookup */ + struct spi_master *master; + + /* Regs base of SPI controller */ + struct bfin_spi_regs __iomem *regs; + + /* Pin request list */ + u16 *pin_req; + + /* Message Transfer pump */ + struct tasklet_struct pump_transfers; + + /* Current message transfer state info */ + struct spi_message *cur_msg; + struct spi_transfer *cur_transfer; + struct bfin_spi_device *cur_chip; + unsigned transfer_len; + + /* transfer buffer */ + void *tx; + void *tx_end; + void *rx; + void *rx_end; + + /* dma info */ + unsigned int tx_dma; + unsigned int rx_dma; + dma_addr_t tx_dma_addr; + dma_addr_t rx_dma_addr; + unsigned long dummy_buffer; /* used in unidirectional transfer */ + unsigned long tx_dma_size; + unsigned long rx_dma_size; + int tx_num; + int rx_num; + + /* store register value for suspend/resume */ + u32 control; + u32 ssel; + + unsigned long sclk; + enum bfin_spi_state state; + + const struct bfin_spi_transfer_ops *ops; +}; + +struct bfin_spi_device { + u32 control; + u32 clock; + u32 ssel; + + u8 cs; + u16 cs_chg_udelay; /* Some devices require > 255usec delay */ + u32 cs_gpio; + u32 tx_dummy_val; /* tx value for rx only transfer */ + bool enable_dma; + const struct bfin_spi_transfer_ops *ops; +}; + +static void bfin_spi_enable(struct bfin_spi_master *drv_data) +{ + bfin_write_or(&drv_data->regs->control, SPI_CTL_EN); +} + +static void bfin_spi_disable(struct bfin_spi_master *drv_data) +{ + bfin_write_and(&drv_data->regs->control, ~SPI_CTL_EN); +} + +/* Caculate the SPI_CLOCK register value based on input HZ */ +static u32 hz_to_spi_clock(u32 sclk, u32 speed_hz) +{ + u32 spi_clock = sclk / speed_hz; + + if (spi_clock) + spi_clock--; + return spi_clock; +} + +static int bfin_spi_flush(struct bfin_spi_master *drv_data) +{ + unsigned long limit = loops_per_jiffy << 1; + + /* wait for stop and clear stat */ + while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_SPIF) && --limit) + cpu_relax(); + + bfin_write(&drv_data->regs->status, 0xFFFFFFFF); + + return limit; +} + +/* Chip select operation functions for cs_change flag */ +static void bfin_spi_cs_active(struct bfin_spi_master *drv_data, struct bfin_spi_device *chip) +{ + if (likely(chip->cs < MAX_CTRL_CS)) + bfin_write_and(&drv_data->regs->ssel, ~chip->ssel); + else + gpio_set_value(chip->cs_gpio, 0); +} + +static void bfin_spi_cs_deactive(struct bfin_spi_master *drv_data, + struct bfin_spi_device *chip) +{ + if (likely(chip->cs < MAX_CTRL_CS)) + bfin_write_or(&drv_data->regs->ssel, chip->ssel); + else + gpio_set_value(chip->cs_gpio, 1); + + /* Move delay here for consistency */ + if (chip->cs_chg_udelay) + udelay(chip->cs_chg_udelay); +} + +/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */ +static inline void bfin_spi_cs_enable(struct bfin_spi_master *drv_data, + struct bfin_spi_device *chip) +{ + if (chip->cs < MAX_CTRL_CS) + bfin_write_or(&drv_data->regs->ssel, chip->ssel >> 8); +} + +static inline void bfin_spi_cs_disable(struct bfin_spi_master *drv_data, + struct bfin_spi_device *chip) +{ + if (chip->cs < MAX_CTRL_CS) + bfin_write_and(&drv_data->regs->ssel, ~(chip->ssel >> 8)); +} + +/* stop controller and re-config current chip*/ +static void bfin_spi_restore_state(struct bfin_spi_master *drv_data) +{ + struct bfin_spi_device *chip = drv_data->cur_chip; + + /* Clear status and disable clock */ + bfin_write(&drv_data->regs->status, 0xFFFFFFFF); + bfin_write(&drv_data->regs->rx_control, 0x0); + bfin_write(&drv_data->regs->tx_control, 0x0); + bfin_spi_disable(drv_data); + + SSYNC(); + + /* Load the registers */ + bfin_write(&drv_data->regs->control, chip->control); + bfin_write(&drv_data->regs->clock, chip->clock); + + bfin_spi_enable(drv_data); + drv_data->tx_num = drv_data->rx_num = 0; + /* we always choose tx transfer initiate */ + bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN); + bfin_write(&drv_data->regs->tx_control, + SPI_TXCTL_TEN | SPI_TXCTL_TTI); + bfin_spi_cs_active(drv_data, chip); +} + +/* discard invalid rx data and empty rfifo */ +static inline void dummy_read(struct bfin_spi_master *drv_data) +{ + while (!(bfin_read(&drv_data->regs->status) & SPI_STAT_RFE)) + bfin_read(&drv_data->regs->rfifo); +} + +static void bfin_spi_u8_write(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->tx < drv_data->tx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++))); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + bfin_read(&drv_data->regs->rfifo); + } +} + +static void bfin_spi_u8_read(struct bfin_spi_master *drv_data) +{ + u32 tx_val = drv_data->cur_chip->tx_dummy_val; + + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, tx_val); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo); + } +} + +static void bfin_spi_u8_duplex(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u8 *)(drv_data->tx++))); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u8 *)(drv_data->rx++) = bfin_read(&drv_data->regs->rfifo); + } +} + +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u8 = { + .write = bfin_spi_u8_write, + .read = bfin_spi_u8_read, + .duplex = bfin_spi_u8_duplex, +}; + +static void bfin_spi_u16_write(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->tx < drv_data->tx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx)); + drv_data->tx += 2; + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + bfin_read(&drv_data->regs->rfifo); + } +} + +static void bfin_spi_u16_read(struct bfin_spi_master *drv_data) +{ + u32 tx_val = drv_data->cur_chip->tx_dummy_val; + + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, tx_val); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + drv_data->rx += 2; + } +} + +static void bfin_spi_u16_duplex(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u16 *)drv_data->tx)); + drv_data->tx += 2; + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u16 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + drv_data->rx += 2; + } +} + +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u16 = { + .write = bfin_spi_u16_write, + .read = bfin_spi_u16_read, + .duplex = bfin_spi_u16_duplex, +}; + +static void bfin_spi_u32_write(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->tx < drv_data->tx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx)); + drv_data->tx += 4; + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + bfin_read(&drv_data->regs->rfifo); + } +} + +static void bfin_spi_u32_read(struct bfin_spi_master *drv_data) +{ + u32 tx_val = drv_data->cur_chip->tx_dummy_val; + + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, tx_val); + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + drv_data->rx += 4; + } +} + +static void bfin_spi_u32_duplex(struct bfin_spi_master *drv_data) +{ + dummy_read(drv_data); + while (drv_data->rx < drv_data->rx_end) { + bfin_write(&drv_data->regs->tfifo, (*(u32 *)drv_data->tx)); + drv_data->tx += 4; + while (bfin_read(&drv_data->regs->status) & SPI_STAT_RFE) + cpu_relax(); + *(u32 *)drv_data->rx = bfin_read(&drv_data->regs->rfifo); + drv_data->rx += 4; + } +} + +static const struct bfin_spi_transfer_ops bfin_bfin_spi_transfer_ops_u32 = { + .write = bfin_spi_u32_write, + .read = bfin_spi_u32_read, + .duplex = bfin_spi_u32_duplex, +}; + + +/* test if there is more transfer to be done */ +static void bfin_spi_next_transfer(struct bfin_spi_master *drv) +{ + struct spi_message *msg = drv->cur_msg; + struct spi_transfer *t = drv->cur_transfer; + + /* Move to next transfer */ + if (t->transfer_list.next != &msg->transfers) { + drv->cur_transfer = list_entry(t->transfer_list.next, + struct spi_transfer, transfer_list); + drv->state = RUNNING_STATE; + } else { + drv->state = DONE_STATE; + drv->cur_transfer = NULL; + } +} + +static void bfin_spi_giveback(struct bfin_spi_master *drv_data) +{ + struct bfin_spi_device *chip = drv_data->cur_chip; + + bfin_spi_cs_deactive(drv_data, chip); + spi_finalize_current_message(drv_data->master); +} + +static int bfin_spi_setup_transfer(struct bfin_spi_master *drv) +{ + struct spi_transfer *t = drv->cur_transfer; + u32 cr, cr_width; + + if (t->tx_buf) { + drv->tx = (void *)t->tx_buf; + drv->tx_end = drv->tx + t->len; + } else { + drv->tx = NULL; + } + + if (t->rx_buf) { + drv->rx = t->rx_buf; + drv->rx_end = drv->rx + t->len; + } else { + drv->rx = NULL; + } + + drv->transfer_len = t->len; + + /* bits per word setup */ + switch (t->bits_per_word) { + case 8: + cr_width = SPI_CTL_SIZE08; + drv->ops = &bfin_bfin_spi_transfer_ops_u8; + break; + case 16: + cr_width = SPI_CTL_SIZE16; + drv->ops = &bfin_bfin_spi_transfer_ops_u16; + break; + case 32: + cr_width = SPI_CTL_SIZE32; + drv->ops = &bfin_bfin_spi_transfer_ops_u32; + break; + default: + return -EINVAL; + } + cr = bfin_read(&drv->regs->control) & ~SPI_CTL_SIZE; + cr |= cr_width; + bfin_write(&drv->regs->control, cr); + + /* speed setup */ + bfin_write(&drv->regs->clock, + hz_to_spi_clock(drv->sclk, t->speed_hz)); + return 0; +} + +static int bfin_spi_dma_xfer(struct bfin_spi_master *drv_data) +{ + struct spi_transfer *t = drv_data->cur_transfer; + struct spi_message *msg = drv_data->cur_msg; + struct bfin_spi_device *chip = drv_data->cur_chip; + u32 dma_config; + unsigned long word_count, word_size; + void *tx_buf, *rx_buf; + + switch (t->bits_per_word) { + case 8: + dma_config = WDSIZE_8 | PSIZE_8; + word_count = drv_data->transfer_len; + word_size = 1; + break; + case 16: + dma_config = WDSIZE_16 | PSIZE_16; + word_count = drv_data->transfer_len / 2; + word_size = 2; + break; + default: + dma_config = WDSIZE_32 | PSIZE_32; + word_count = drv_data->transfer_len / 4; + word_size = 4; + break; + } + + if (!drv_data->rx) { + tx_buf = drv_data->tx; + rx_buf = &drv_data->dummy_buffer; + drv_data->tx_dma_size = drv_data->transfer_len; + drv_data->rx_dma_size = sizeof(drv_data->dummy_buffer); + set_dma_x_modify(drv_data->tx_dma, word_size); + set_dma_x_modify(drv_data->rx_dma, 0); + } else if (!drv_data->tx) { + drv_data->dummy_buffer = chip->tx_dummy_val; + tx_buf = &drv_data->dummy_buffer; + rx_buf = drv_data->rx; + drv_data->tx_dma_size = sizeof(drv_data->dummy_buffer); + drv_data->rx_dma_size = drv_data->transfer_len; + set_dma_x_modify(drv_data->tx_dma, 0); + set_dma_x_modify(drv_data->rx_dma, word_size); + } else { + tx_buf = drv_data->tx; + rx_buf = drv_data->rx; + drv_data->tx_dma_size = drv_data->rx_dma_size + = drv_data->transfer_len; + set_dma_x_modify(drv_data->tx_dma, word_size); + set_dma_x_modify(drv_data->rx_dma, word_size); + } + + drv_data->tx_dma_addr = dma_map_single(&msg->spi->dev, + (void *)tx_buf, + drv_data->tx_dma_size, + DMA_TO_DEVICE); + if (dma_mapping_error(&msg->spi->dev, + drv_data->tx_dma_addr)) + return -ENOMEM; + + drv_data->rx_dma_addr = dma_map_single(&msg->spi->dev, + (void *)rx_buf, + drv_data->rx_dma_size, + DMA_FROM_DEVICE); + if (dma_mapping_error(&msg->spi->dev, + drv_data->rx_dma_addr)) { + dma_unmap_single(&msg->spi->dev, + drv_data->tx_dma_addr, + drv_data->tx_dma_size, + DMA_TO_DEVICE); + return -ENOMEM; + } + + dummy_read(drv_data); + set_dma_x_count(drv_data->tx_dma, word_count); + set_dma_x_count(drv_data->rx_dma, word_count); + set_dma_start_addr(drv_data->tx_dma, drv_data->tx_dma_addr); + set_dma_start_addr(drv_data->rx_dma, drv_data->rx_dma_addr); + dma_config |= DMAFLOW_STOP | RESTART | DI_EN; + set_dma_config(drv_data->tx_dma, dma_config); + set_dma_config(drv_data->rx_dma, dma_config | WNR); + enable_dma(drv_data->tx_dma); + enable_dma(drv_data->rx_dma); + SSYNC(); + + bfin_write(&drv_data->regs->rx_control, SPI_RXCTL_REN | SPI_RXCTL_RDR_NE); + SSYNC(); + bfin_write(&drv_data->regs->tx_control, + SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF); + + return 0; +} + +static int bfin_spi_pio_xfer(struct bfin_spi_master *drv_data) +{ + struct spi_message *msg = drv_data->cur_msg; + + if (!drv_data->rx) { + /* write only half duplex */ + drv_data->ops->write(drv_data); + if (drv_data->tx != drv_data->tx_end) + return -EIO; + } else if (!drv_data->tx) { + /* read only half duplex */ + drv_data->ops->read(drv_data); + if (drv_data->rx != drv_data->rx_end) + return -EIO; + } else { + /* full duplex mode */ + drv_data->ops->duplex(drv_data); + if (drv_data->tx != drv_data->tx_end) + return -EIO; + } + + if (!bfin_spi_flush(drv_data)) + return -EIO; + msg->actual_length += drv_data->transfer_len; + tasklet_schedule(&drv_data->pump_transfers); + return 0; +} + +static void bfin_spi_pump_transfers(unsigned long data) +{ + struct bfin_spi_master *drv_data = (struct bfin_spi_master *)data; + struct spi_message *msg = NULL; + struct spi_transfer *t = NULL; + struct bfin_spi_device *chip = NULL; + int ret; + + /* Get current state information */ + msg = drv_data->cur_msg; + t = drv_data->cur_transfer; + chip = drv_data->cur_chip; + + /* Handle for abort */ + if (drv_data->state == ERROR_STATE) { + msg->status = -EIO; + bfin_spi_giveback(drv_data); + return; + } + + if (drv_data->state == RUNNING_STATE) { + if (t->delay_usecs) + udelay(t->delay_usecs); + if (t->cs_change) + bfin_spi_cs_deactive(drv_data, chip); + bfin_spi_next_transfer(drv_data); + t = drv_data->cur_transfer; + } + /* Handle end of message */ + if (drv_data->state == DONE_STATE) { + msg->status = 0; + bfin_spi_giveback(drv_data); + return; + } + + if ((t->len == 0) || (t->tx_buf == NULL && t->rx_buf == NULL)) { + /* Schedule next transfer tasklet */ + tasklet_schedule(&drv_data->pump_transfers); + return; + } + + ret = bfin_spi_setup_transfer(drv_data); + if (ret) { + msg->status = ret; + bfin_spi_giveback(drv_data); + } + + bfin_write(&drv_data->regs->status, 0xFFFFFFFF); + bfin_spi_cs_active(drv_data, chip); + drv_data->state = RUNNING_STATE; + + if (chip->enable_dma) + ret = bfin_spi_dma_xfer(drv_data); + else + ret = bfin_spi_pio_xfer(drv_data); + if (ret) { + msg->status = ret; + bfin_spi_giveback(drv_data); + } +} + +static int bfin_spi_transfer_one_message(struct spi_master *master, + struct spi_message *m) +{ + struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + + drv_data->cur_msg = m; + drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); + bfin_spi_restore_state(drv_data); + + drv_data->state = START_STATE; + drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next, + struct spi_transfer, transfer_list); + + tasklet_schedule(&drv_data->pump_transfers); + return 0; +} + +#define MAX_SPI_SSEL 7 + +static const u16 ssel[][MAX_SPI_SSEL] = { + {P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3, + P_SPI0_SSEL4, P_SPI0_SSEL5, + P_SPI0_SSEL6, P_SPI0_SSEL7}, + + {P_SPI1_SSEL1, P_SPI1_SSEL2, P_SPI1_SSEL3, + P_SPI1_SSEL4, P_SPI1_SSEL5, + P_SPI1_SSEL6, P_SPI1_SSEL7}, + + {P_SPI2_SSEL1, P_SPI2_SSEL2, P_SPI2_SSEL3, + P_SPI2_SSEL4, P_SPI2_SSEL5, + P_SPI2_SSEL6, P_SPI2_SSEL7}, +}; + +static int bfin_spi_setup(struct spi_device *spi) +{ + struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master); + struct bfin_spi_device *chip = spi_get_ctldata(spi); + u32 bfin_ctl_reg = SPI_CTL_ODM | SPI_CTL_PSSE; + int ret = -EINVAL; + + if (!chip) { + struct bfin_spi3_chip *chip_info = spi->controller_data; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { + dev_err(&spi->dev, "can not allocate chip data\n"); + return -ENOMEM; + } + if (chip_info) { + if (chip_info->control & ~bfin_ctl_reg) { + dev_err(&spi->dev, + "do not set bits that the SPI framework manages\n"); + goto error; + } + chip->control = chip_info->control; + chip->cs_chg_udelay = chip_info->cs_chg_udelay; + chip->tx_dummy_val = chip_info->tx_dummy_val; + chip->enable_dma = chip_info->enable_dma; + } + chip->cs = spi->chip_select; + if (chip->cs < MAX_CTRL_CS) { + chip->ssel = (1 << chip->cs) << 8; + ret = peripheral_request(ssel[spi->master->bus_num] + [chip->cs-1], dev_name(&spi->dev)); + if (ret) { + dev_err(&spi->dev, "peripheral_request() error\n"); + goto error; + } + } else { + chip->cs_gpio = chip->cs - MAX_CTRL_CS; + ret = gpio_request_one(chip->cs_gpio, GPIOF_OUT_INIT_HIGH, + dev_name(&spi->dev)); + if (ret) { + dev_err(&spi->dev, "gpio_request_one() error\n"); + goto error; + } + } + spi_set_ctldata(spi, chip); + } + + /* force a default base state */ + chip->control &= bfin_ctl_reg; + + if (spi->mode & SPI_CPOL) + chip->control |= SPI_CTL_CPOL; + if (spi->mode & SPI_CPHA) + chip->control |= SPI_CTL_CPHA; + if (spi->mode & SPI_LSB_FIRST) + chip->control |= SPI_CTL_LSBF; + chip->control |= SPI_CTL_MSTR; + /* we choose software to controll cs */ + chip->control &= ~SPI_CTL_ASSEL; + + chip->clock = hz_to_spi_clock(drv_data->sclk, spi->max_speed_hz); + + bfin_spi_cs_enable(drv_data, chip); + bfin_spi_cs_deactive(drv_data, chip); + + return 0; +error: + if (chip) { + kfree(chip); + spi_set_ctldata(spi, NULL); + } + + return ret; +} + +static void bfin_spi_cleanup(struct spi_device *spi) +{ + struct bfin_spi_device *chip = spi_get_ctldata(spi); + struct bfin_spi_master *drv_data = spi_master_get_devdata(spi->master); + + if (!chip) + return; + + if (chip->cs < MAX_CTRL_CS) { + peripheral_free(ssel[spi->master->bus_num] + [chip->cs-1]); + bfin_spi_cs_disable(drv_data, chip); + } else { + gpio_free(chip->cs_gpio); + } + + kfree(chip); + spi_set_ctldata(spi, NULL); +} + +static irqreturn_t bfin_spi_tx_dma_isr(int irq, void *dev_id) +{ + struct bfin_spi_master *drv_data = dev_id; + u32 dma_stat = get_dma_curr_irqstat(drv_data->tx_dma); + + clear_dma_irqstat(drv_data->tx_dma); + if (dma_stat & DMA_DONE) { + drv_data->tx_num++; + } else { + dev_err(&drv_data->master->dev, + "spi tx dma error: %d\n", dma_stat); + if (drv_data->tx) + drv_data->state = ERROR_STATE; + } + bfin_write_and(&drv_data->regs->tx_control, ~SPI_TXCTL_TDR_NF); + return IRQ_HANDLED; +} + +static irqreturn_t bfin_spi_rx_dma_isr(int irq, void *dev_id) +{ + struct bfin_spi_master *drv_data = dev_id; + struct spi_message *msg = drv_data->cur_msg; + u32 dma_stat = get_dma_curr_irqstat(drv_data->rx_dma); + + clear_dma_irqstat(drv_data->rx_dma); + if (dma_stat & DMA_DONE) { + drv_data->rx_num++; + /* we may fail on tx dma */ + if (drv_data->state != ERROR_STATE) + msg->actual_length += drv_data->transfer_len; + } else { + drv_data->state = ERROR_STATE; + dev_err(&drv_data->master->dev, + "spi rx dma error: %d\n", dma_stat); + } + bfin_write(&drv_data->regs->tx_control, 0); + bfin_write(&drv_data->regs->rx_control, 0); + if (drv_data->rx_num != drv_data->tx_num) + dev_dbg(&drv_data->master->dev, + "dma interrupt missing: tx=%d,rx=%d\n", + drv_data->tx_num, drv_data->rx_num); + tasklet_schedule(&drv_data->pump_transfers); + return IRQ_HANDLED; +} + +static int bfin_spi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct bfin_spi3_master *info = dev_get_platdata(dev); + struct spi_master *master; + struct bfin_spi_master *drv_data; + struct resource *mem, *res; + unsigned int tx_dma, rx_dma; + unsigned long sclk; + int ret; + + if (!info) { + dev_err(dev, "platform data missing!\n"); + return -ENODEV; + } + + sclk = get_sclk1(); + if (!sclk) { + dev_err(dev, "can not get sclk1\n"); + return -ENXIO; + } + + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!res) { + dev_err(dev, "can not get tx dma resource\n"); + return -ENXIO; + } + tx_dma = res->start; + + res = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!res) { + dev_err(dev, "can not get rx dma resource\n"); + return -ENXIO; + } + rx_dma = res->start; + + /* allocate master with space for drv_data */ + master = spi_alloc_master(dev, sizeof(*drv_data)); + if (!master) { + dev_err(dev, "can not alloc spi_master\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, master); + + /* the mode bits supported by this driver */ + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; + + master->bus_num = pdev->id; + master->num_chipselect = info->num_chipselect; + master->cleanup = bfin_spi_cleanup; + master->setup = bfin_spi_setup; + master->transfer_one_message = bfin_spi_transfer_one_message; + master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + + drv_data = spi_master_get_devdata(master); + drv_data->master = master; + drv_data->tx_dma = tx_dma; + drv_data->rx_dma = rx_dma; + drv_data->pin_req = info->pin_req; + drv_data->sclk = sclk; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + drv_data->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(drv_data->regs)) { + ret = PTR_ERR(drv_data->regs); + goto err_put_master; + } + + /* request tx and rx dma */ + ret = request_dma(tx_dma, "SPI_TX_DMA"); + if (ret) { + dev_err(dev, "can not request SPI TX DMA channel\n"); + goto err_put_master; + } + set_dma_callback(tx_dma, bfin_spi_tx_dma_isr, drv_data); + + ret = request_dma(rx_dma, "SPI_RX_DMA"); + if (ret) { + dev_err(dev, "can not request SPI RX DMA channel\n"); + goto err_free_tx_dma; + } + set_dma_callback(drv_data->rx_dma, bfin_spi_rx_dma_isr, drv_data); + + /* request CLK, MOSI and MISO */ + ret = peripheral_request_list(drv_data->pin_req, "bfin-spi3"); + if (ret < 0) { + dev_err(dev, "can not request spi pins\n"); + goto err_free_rx_dma; + } + + bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA); + bfin_write(&drv_data->regs->ssel, 0x0000FE00); + bfin_write(&drv_data->regs->delay, 0x0); + + tasklet_init(&drv_data->pump_transfers, + bfin_spi_pump_transfers, (unsigned long)drv_data); + /* register with the SPI framework */ + ret = spi_register_master(master); + if (ret) { + dev_err(dev, "can not register spi master\n"); + goto err_free_peripheral; + } + + return ret; + +err_free_peripheral: + peripheral_free_list(drv_data->pin_req); +err_free_rx_dma: + free_dma(rx_dma); +err_free_tx_dma: + free_dma(tx_dma); +err_put_master: + spi_master_put(master); + + return ret; +} + +static int bfin_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + + bfin_spi_disable(drv_data); + + peripheral_free_list(drv_data->pin_req); + free_dma(drv_data->rx_dma); + free_dma(drv_data->tx_dma); + + spi_unregister_master(drv_data->master); + return 0; +} + +#ifdef CONFIG_PM +static int bfin_spi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + + spi_master_suspend(master); + + drv_data->control = bfin_read(&drv_data->regs->control); + drv_data->ssel = bfin_read(&drv_data->regs->ssel); + + bfin_write(&drv_data->regs->control, SPI_CTL_MSTR | SPI_CTL_CPHA); + bfin_write(&drv_data->regs->ssel, 0x0000FE00); + dma_disable_irq(drv_data->rx_dma); + dma_disable_irq(drv_data->tx_dma); + + return 0; +} + +static int bfin_spi_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct bfin_spi_master *drv_data = spi_master_get_devdata(master); + int ret = 0; + + /* bootrom may modify spi and dma status when resume in spi boot mode */ + disable_dma(drv_data->rx_dma); + + dma_enable_irq(drv_data->rx_dma); + dma_enable_irq(drv_data->tx_dma); + bfin_write(&drv_data->regs->control, drv_data->control); + bfin_write(&drv_data->regs->ssel, drv_data->ssel); + + ret = spi_master_resume(master); + if (ret) { + free_dma(drv_data->rx_dma); + free_dma(drv_data->tx_dma); + } + + return ret; +} +#endif +static const struct dev_pm_ops bfin_spi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(bfin_spi_suspend, bfin_spi_resume) +}; + +MODULE_ALIAS("platform:bfin-spi3"); +static struct platform_driver bfin_spi_driver = { + .driver = { + .name = "bfin-spi3", + .owner = THIS_MODULE, + .pm = &bfin_spi_pm_ops, + }, + .remove = bfin_spi_remove, +}; + +module_platform_driver_probe(bfin_spi_driver, bfin_spi_probe); + +MODULE_DESCRIPTION("Analog Devices SPI3 controller driver"); +MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c index 59a73424419c..45bdf73d6868 100644 --- a/drivers/spi/spi-bfin5xx.c +++ b/drivers/spi/spi-bfin5xx.c @@ -1271,7 +1271,7 @@ static int bfin_spi_probe(struct platform_device *pdev) struct resource *res; int status = 0; - platform_info = dev->platform_data; + platform_info = dev_get_platdata(dev); /* Allocate master with space for drv_data */ master = spi_alloc_master(dev, sizeof(*drv_data)); diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index a63d7da3bfe2..e3946e44e076 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -255,150 +255,140 @@ static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t) * Drivers can provide word-at-a-time i/o primitives, or provide * transfer-at-a-time ones to leverage dma or fifo hardware. */ -static void bitbang_work(struct work_struct *work) + +static int spi_bitbang_prepare_hardware(struct spi_master *spi) { - struct spi_bitbang *bitbang = - container_of(work, struct spi_bitbang, work); + struct spi_bitbang *bitbang; unsigned long flags; - struct spi_message *m, *_m; + + bitbang = spi_master_get_devdata(spi); spin_lock_irqsave(&bitbang->lock, flags); bitbang->busy = 1; - list_for_each_entry_safe(m, _m, &bitbang->queue, queue) { - struct spi_device *spi; - unsigned nsecs; - struct spi_transfer *t = NULL; - unsigned tmp; - unsigned cs_change; - int status; - int do_setup = -1; - - list_del(&m->queue); - spin_unlock_irqrestore(&bitbang->lock, flags); - - /* FIXME this is made-up ... the correct value is known to - * word-at-a-time bitbang code, and presumably chipselect() - * should enforce these requirements too? - */ - nsecs = 100; + spin_unlock_irqrestore(&bitbang->lock, flags); - spi = m->spi; - tmp = 0; - cs_change = 1; - status = 0; + return 0; +} - list_for_each_entry (t, &m->transfers, transfer_list) { - - /* override speed or wordsize? */ - if (t->speed_hz || t->bits_per_word) - do_setup = 1; - - /* init (-1) or override (1) transfer params */ - if (do_setup != 0) { - status = bitbang->setup_transfer(spi, t); - if (status < 0) - break; - if (do_setup == -1) - do_setup = 0; - } - - /* set up default clock polarity, and activate chip; - * this implicitly updates clock and spi modes as - * previously recorded for this device via setup(). - * (and also deselects any other chip that might be - * selected ...) - */ - if (cs_change) { - bitbang->chipselect(spi, BITBANG_CS_ACTIVE); - ndelay(nsecs); - } - cs_change = t->cs_change; - if (!t->tx_buf && !t->rx_buf && t->len) { - status = -EINVAL; - break; - } +static int spi_bitbang_transfer_one(struct spi_master *master, + struct spi_message *m) +{ + struct spi_bitbang *bitbang; + unsigned nsecs; + struct spi_transfer *t = NULL; + unsigned cs_change; + int status; + int do_setup = -1; + struct spi_device *spi = m->spi; + + bitbang = spi_master_get_devdata(master); + + /* FIXME this is made-up ... the correct value is known to + * word-at-a-time bitbang code, and presumably chipselect() + * should enforce these requirements too? + */ + nsecs = 100; - /* transfer data. the lower level code handles any - * new dma mappings it needs. our caller always gave - * us dma-safe buffers. - */ - if (t->len) { - /* REVISIT dma API still needs a designated - * DMA_ADDR_INVALID; ~0 might be better. - */ - if (!m->is_dma_mapped) - t->rx_dma = t->tx_dma = 0; - status = bitbang->txrx_bufs(spi, t); - } - if (status > 0) - m->actual_length += status; - if (status != t->len) { - /* always report some kind of error */ - if (status >= 0) - status = -EREMOTEIO; + cs_change = 1; + status = 0; + + list_for_each_entry (t, &m->transfers, transfer_list) { + + /* override speed or wordsize? */ + if (t->speed_hz || t->bits_per_word) + do_setup = 1; + + /* init (-1) or override (1) transfer params */ + if (do_setup != 0) { + status = bitbang->setup_transfer(spi, t); + if (status < 0) break; - } - status = 0; - - /* protocol tweaks before next transfer */ - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) { - /* sometimes a short mid-message deselect of the chip - * may be needed to terminate a mode or command - */ - ndelay(nsecs); - bitbang->chipselect(spi, BITBANG_CS_INACTIVE); - ndelay(nsecs); - } + if (do_setup == -1) + do_setup = 0; } - m->status = status; - m->complete(m->context); + /* set up default clock polarity, and activate chip; + * this implicitly updates clock and spi modes as + * previously recorded for this device via setup(). + * (and also deselects any other chip that might be + * selected ...) + */ + if (cs_change) { + bitbang->chipselect(spi, BITBANG_CS_ACTIVE); + ndelay(nsecs); + } + cs_change = t->cs_change; + if (!t->tx_buf && !t->rx_buf && t->len) { + status = -EINVAL; + break; + } - /* normally deactivate chipselect ... unless no error and - * cs_change has hinted that the next message will probably - * be for this chip too. + /* transfer data. the lower level code handles any + * new dma mappings it needs. our caller always gave + * us dma-safe buffers. */ - if (!(status == 0 && cs_change)) { + if (t->len) { + /* REVISIT dma API still needs a designated + * DMA_ADDR_INVALID; ~0 might be better. + */ + if (!m->is_dma_mapped) + t->rx_dma = t->tx_dma = 0; + status = bitbang->txrx_bufs(spi, t); + } + if (status > 0) + m->actual_length += status; + if (status != t->len) { + /* always report some kind of error */ + if (status >= 0) + status = -EREMOTEIO; + break; + } + status = 0; + + /* protocol tweaks before next transfer */ + if (t->delay_usecs) + udelay(t->delay_usecs); + + if (cs_change && !list_is_last(&t->transfer_list, &m->transfers)) { + /* sometimes a short mid-message deselect of the chip + * may be needed to terminate a mode or command + */ ndelay(nsecs); bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ndelay(nsecs); } + } + + m->status = status; - spin_lock_irqsave(&bitbang->lock, flags); + /* normally deactivate chipselect ... unless no error and + * cs_change has hinted that the next message will probably + * be for this chip too. + */ + if (!(status == 0 && cs_change)) { + ndelay(nsecs); + bitbang->chipselect(spi, BITBANG_CS_INACTIVE); + ndelay(nsecs); } - bitbang->busy = 0; - spin_unlock_irqrestore(&bitbang->lock, flags); + + spi_finalize_current_message(master); + + return status; } -/** - * spi_bitbang_transfer - default submit to transfer queue - */ -int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m) +static int spi_bitbang_unprepare_hardware(struct spi_master *spi) { - struct spi_bitbang *bitbang; + struct spi_bitbang *bitbang; unsigned long flags; - int status = 0; - m->actual_length = 0; - m->status = -EINPROGRESS; - - bitbang = spi_master_get_devdata(spi->master); + bitbang = spi_master_get_devdata(spi); spin_lock_irqsave(&bitbang->lock, flags); - if (!spi->max_speed_hz) - status = -ENETDOWN; - else { - list_add_tail(&m->queue, &bitbang->queue); - queue_work(bitbang->workqueue, &bitbang->work); - } + bitbang->busy = 0; spin_unlock_irqrestore(&bitbang->lock, flags); - return status; + return 0; } -EXPORT_SYMBOL_GPL(spi_bitbang_transfer); /*----------------------------------------------------------------------*/ @@ -428,20 +418,22 @@ EXPORT_SYMBOL_GPL(spi_bitbang_transfer); int spi_bitbang_start(struct spi_bitbang *bitbang) { struct spi_master *master = bitbang->master; - int status; if (!master || !bitbang->chipselect) return -EINVAL; - INIT_WORK(&bitbang->work, bitbang_work); spin_lock_init(&bitbang->lock); - INIT_LIST_HEAD(&bitbang->queue); if (!master->mode_bits) master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags; - if (!master->transfer) - master->transfer = spi_bitbang_transfer; + if (master->transfer || master->transfer_one_message) + return -EINVAL; + + master->prepare_transfer_hardware = spi_bitbang_prepare_hardware; + master->unprepare_transfer_hardware = spi_bitbang_unprepare_hardware; + master->transfer_one_message = spi_bitbang_transfer_one; + if (!bitbang->txrx_bufs) { bitbang->use_dma = 0; bitbang->txrx_bufs = spi_bitbang_bufs; @@ -452,34 +444,12 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) master->setup = spi_bitbang_setup; master->cleanup = spi_bitbang_cleanup; } - } else if (!master->setup) - return -EINVAL; - if (master->transfer == spi_bitbang_transfer && - !bitbang->setup_transfer) - return -EINVAL; - - /* this task is the only thing to touch the SPI bits */ - bitbang->busy = 0; - bitbang->workqueue = create_singlethread_workqueue( - dev_name(master->dev.parent)); - if (bitbang->workqueue == NULL) { - status = -EBUSY; - goto err1; } /* driver may get busy before register() returns, especially * if someone registered boardinfo for devices */ - status = spi_register_master(master); - if (status < 0) - goto err2; - - return status; - -err2: - destroy_workqueue(bitbang->workqueue); -err1: - return status; + return spi_register_master(master); } EXPORT_SYMBOL_GPL(spi_bitbang_start); @@ -490,10 +460,6 @@ int spi_bitbang_stop(struct spi_bitbang *bitbang) { spi_unregister_master(bitbang->master); - WARN_ON(!list_empty(&bitbang->queue)); - - destroy_workqueue(bitbang->workqueue); - return 0; } EXPORT_SYMBOL_GPL(spi_bitbang_stop); diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 17965fe225cc..5655acf55bfe 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -239,11 +239,8 @@ static int spi_clps711x_probe(struct platform_device *pdev) } dev_err(&pdev->dev, "Failed to register master\n"); - devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw); clk_out: - devm_clk_put(&pdev->dev, hw->spi_clk); - err_out: while (--i >= 0) if (gpio_is_valid(hw->chipselect[i])) @@ -261,13 +258,10 @@ static int spi_clps711x_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct spi_clps711x_data *hw = spi_master_get_devdata(master); - devm_free_irq(&pdev->dev, IRQ_SSEOTI, hw); - for (i = 0; i < master->num_chipselect; i++) if (gpio_is_valid(hw->chipselect[i])) gpio_free(hw->chipselect[i]); - devm_clk_put(&pdev->dev, hw->spi_clk); spi_unregister_master(master); kfree(master); diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 0631b9d4a5de..cc5b75d10c38 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -354,24 +354,6 @@ static int mcfqspi_transfer_one_message(struct spi_master *master, } -static int mcfqspi_prepare_transfer_hw(struct spi_master *master) -{ - struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - - pm_runtime_get_sync(mcfqspi->dev); - - return 0; -} - -static int mcfqspi_unprepare_transfer_hw(struct spi_master *master) -{ - struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - - pm_runtime_put_sync(mcfqspi->dev); - - return 0; -} - static int mcfqspi_setup(struct spi_device *spi) { if (spi->chip_select >= spi->master->num_chipselect) { @@ -400,7 +382,7 @@ static int mcfqspi_probe(struct platform_device *pdev) struct mcfqspi_platform_data *pdata; int status; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); if (!pdata) { dev_dbg(&pdev->dev, "platform data is missing\n"); return -ENOENT; @@ -473,8 +455,7 @@ static int mcfqspi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); master->setup = mcfqspi_setup; master->transfer_one_message = mcfqspi_transfer_one_message; - master->prepare_transfer_hardware = mcfqspi_prepare_transfer_hw; - master->unprepare_transfer_hardware = mcfqspi_unprepare_transfer_hw; + master->auto_runtime_pm = true; platform_set_drvdata(pdev, master); @@ -558,7 +539,7 @@ static int mcfqspi_resume(struct device *dev) #ifdef CONFIG_PM_RUNTIME static int mcfqspi_runtime_suspend(struct device *dev) { - struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); + struct mcfqspi *mcfqspi = dev_get_drvdata(dev); clk_disable(mcfqspi->clk); @@ -567,7 +548,7 @@ static int mcfqspi_runtime_suspend(struct device *dev) static int mcfqspi_runtime_resume(struct device *dev) { - struct mcfqspi *mcfqspi = platform_get_drvdata(to_platform_device(dev)); + struct mcfqspi *mcfqspi = dev_get_drvdata(dev); clk_enable(mcfqspi->clk); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 707966bd5610..8fbfe2483ffd 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -872,8 +872,8 @@ static int davinci_spi_probe(struct platform_device *pdev) goto free_master; } - if (pdev->dev.platform_data) { - pdata = pdev->dev.platform_data; + if (dev_get_platdata(&pdev->dev)) { + pdata = dev_get_platdata(&pdev->dev); dspi->pdata = *pdata; } else { /* update dspi pdata with that from the DT */ diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c new file mode 100644 index 000000000000..7d84418a01d8 --- /dev/null +++ b/drivers/spi/spi-efm32.c @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2012-2013 Uwe Kleine-Koenig for Pengutronix + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License version 2 as published by the + * Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of_gpio.h> +#include <linux/platform_data/efm32-spi.h> + +#define DRIVER_NAME "efm32-spi" + +#define MASK_VAL(mask, val) ((val << __ffs(mask)) & mask) + +#define REG_CTRL 0x00 +#define REG_CTRL_SYNC 0x0001 +#define REG_CTRL_CLKPOL 0x0100 +#define REG_CTRL_CLKPHA 0x0200 +#define REG_CTRL_MSBF 0x0400 +#define REG_CTRL_TXBIL 0x1000 + +#define REG_FRAME 0x04 +#define REG_FRAME_DATABITS__MASK 0x000f +#define REG_FRAME_DATABITS(n) ((n) - 3) + +#define REG_CMD 0x0c +#define REG_CMD_RXEN 0x0001 +#define REG_CMD_RXDIS 0x0002 +#define REG_CMD_TXEN 0x0004 +#define REG_CMD_TXDIS 0x0008 +#define REG_CMD_MASTEREN 0x0010 + +#define REG_STATUS 0x10 +#define REG_STATUS_TXENS 0x0002 +#define REG_STATUS_TXC 0x0020 +#define REG_STATUS_TXBL 0x0040 +#define REG_STATUS_RXDATAV 0x0080 + +#define REG_CLKDIV 0x14 + +#define REG_RXDATAX 0x18 +#define REG_RXDATAX_RXDATA__MASK 0x01ff +#define REG_RXDATAX_PERR 0x4000 +#define REG_RXDATAX_FERR 0x8000 + +#define REG_TXDATA 0x34 + +#define REG_IF 0x40 +#define REG_IF_TXBL 0x0002 +#define REG_IF_RXDATAV 0x0004 + +#define REG_IFS 0x44 +#define REG_IFC 0x48 +#define REG_IEN 0x4c + +#define REG_ROUTE 0x54 +#define REG_ROUTE_RXPEN 0x0001 +#define REG_ROUTE_TXPEN 0x0002 +#define REG_ROUTE_CLKPEN 0x0008 +#define REG_ROUTE_LOCATION__MASK 0x0700 +#define REG_ROUTE_LOCATION(n) MASK_VAL(REG_ROUTE_LOCATION__MASK, (n)) + +struct efm32_spi_ddata { + struct spi_bitbang bitbang; + + spinlock_t lock; + + struct clk *clk; + void __iomem *base; + unsigned int rxirq, txirq; + struct efm32_spi_pdata pdata; + + /* irq data */ + struct completion done; + const u8 *tx_buf; + u8 *rx_buf; + unsigned tx_len, rx_len; + + /* chip selects */ + unsigned csgpio[]; +}; + +#define ddata_to_dev(ddata) (&(ddata->bitbang.master->dev)) +#define efm32_spi_vdbg(ddata, format, arg...) \ + dev_vdbg(ddata_to_dev(ddata), format, ##arg) + +static void efm32_spi_write32(struct efm32_spi_ddata *ddata, + u32 value, unsigned offset) +{ + writel_relaxed(value, ddata->base + offset); +} + +static u32 efm32_spi_read32(struct efm32_spi_ddata *ddata, unsigned offset) +{ + return readl_relaxed(ddata->base + offset); +} + +static void efm32_spi_chipselect(struct spi_device *spi, int is_on) +{ + struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master); + int value = !(spi->mode & SPI_CS_HIGH) == !(is_on == BITBANG_CS_ACTIVE); + + gpio_set_value(ddata->csgpio[spi->chip_select], value); +} + +static int efm32_spi_setup_transfer(struct spi_device *spi, + struct spi_transfer *t) +{ + struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master); + + unsigned bpw = t->bits_per_word ?: spi->bits_per_word; + unsigned speed = t->speed_hz ?: spi->max_speed_hz; + unsigned long clkfreq = clk_get_rate(ddata->clk); + u32 clkdiv; + + efm32_spi_write32(ddata, REG_CTRL_SYNC | REG_CTRL_MSBF | + (spi->mode & SPI_CPHA ? REG_CTRL_CLKPHA : 0) | + (spi->mode & SPI_CPOL ? REG_CTRL_CLKPOL : 0), REG_CTRL); + + efm32_spi_write32(ddata, + REG_FRAME_DATABITS(bpw), REG_FRAME); + + if (2 * speed >= clkfreq) + clkdiv = 0; + else + clkdiv = 64 * (DIV_ROUND_UP(2 * clkfreq, speed) - 4); + + if (clkdiv > (1U << 21)) + return -EINVAL; + + efm32_spi_write32(ddata, clkdiv, REG_CLKDIV); + efm32_spi_write32(ddata, REG_CMD_MASTEREN, REG_CMD); + efm32_spi_write32(ddata, REG_CMD_RXEN | REG_CMD_TXEN, REG_CMD); + + return 0; +} + +static void efm32_spi_tx_u8(struct efm32_spi_ddata *ddata) +{ + u8 val = 0; + + if (ddata->tx_buf) { + val = *ddata->tx_buf; + ddata->tx_buf++; + } + + ddata->tx_len--; + efm32_spi_write32(ddata, val, REG_TXDATA); + efm32_spi_vdbg(ddata, "%s: tx 0x%x\n", __func__, val); +} + +static void efm32_spi_rx_u8(struct efm32_spi_ddata *ddata) +{ + u32 rxdata = efm32_spi_read32(ddata, REG_RXDATAX); + efm32_spi_vdbg(ddata, "%s: rx 0x%x\n", __func__, rxdata); + + if (ddata->rx_buf) { + *ddata->rx_buf = rxdata; + ddata->rx_buf++; + } + + ddata->rx_len--; +} + +static void efm32_spi_filltx(struct efm32_spi_ddata *ddata) +{ + while (ddata->tx_len && + ddata->tx_len + 2 > ddata->rx_len && + efm32_spi_read32(ddata, REG_STATUS) & REG_STATUS_TXBL) { + efm32_spi_tx_u8(ddata); + } +} + +static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) +{ + struct efm32_spi_ddata *ddata = spi_master_get_devdata(spi->master); + int ret = -EBUSY; + + spin_lock_irq(&ddata->lock); + + if (ddata->tx_buf || ddata->rx_buf) + goto out_unlock; + + ddata->tx_buf = t->tx_buf; + ddata->rx_buf = t->rx_buf; + ddata->tx_len = ddata->rx_len = + t->len * DIV_ROUND_UP(t->bits_per_word, 8); + + efm32_spi_filltx(ddata); + + init_completion(&ddata->done); + + efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN); + + spin_unlock_irq(&ddata->lock); + + wait_for_completion(&ddata->done); + + spin_lock_irq(&ddata->lock); + + ret = t->len - max(ddata->tx_len, ddata->rx_len); + + efm32_spi_write32(ddata, 0, REG_IEN); + ddata->tx_buf = ddata->rx_buf = NULL; + +out_unlock: + spin_unlock_irq(&ddata->lock); + + return ret; +} + +static irqreturn_t efm32_spi_rxirq(int irq, void *data) +{ + struct efm32_spi_ddata *ddata = data; + irqreturn_t ret = IRQ_NONE; + + spin_lock(&ddata->lock); + + while (ddata->rx_len > 0 && + efm32_spi_read32(ddata, REG_STATUS) & + REG_STATUS_RXDATAV) { + efm32_spi_rx_u8(ddata); + + ret = IRQ_HANDLED; + } + + if (!ddata->rx_len) { + u32 ien = efm32_spi_read32(ddata, REG_IEN); + + ien &= ~REG_IF_RXDATAV; + + efm32_spi_write32(ddata, ien, REG_IEN); + + complete(&ddata->done); + } + + spin_unlock(&ddata->lock); + + return ret; +} + +static irqreturn_t efm32_spi_txirq(int irq, void *data) +{ + struct efm32_spi_ddata *ddata = data; + + efm32_spi_vdbg(ddata, + "%s: txlen = %u, rxlen = %u, if=0x%08x, stat=0x%08x\n", + __func__, ddata->tx_len, ddata->rx_len, + efm32_spi_read32(ddata, REG_IF), + efm32_spi_read32(ddata, REG_STATUS)); + + spin_lock(&ddata->lock); + + efm32_spi_filltx(ddata); + + efm32_spi_vdbg(ddata, "%s: txlen = %u, rxlen = %u\n", + __func__, ddata->tx_len, ddata->rx_len); + + if (!ddata->tx_len) { + u32 ien = efm32_spi_read32(ddata, REG_IEN); + + ien &= ~REG_IF_TXBL; + + efm32_spi_write32(ddata, ien, REG_IEN); + efm32_spi_vdbg(ddata, "disable TXBL\n"); + } + + spin_unlock(&ddata->lock); + + return IRQ_HANDLED; +} + +static const struct efm32_spi_pdata efm32_spi_pdata_default = { + .location = 1, +}; + +static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata) +{ + u32 reg = efm32_spi_read32(ddata, REG_ROUTE); + + return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK); +} + +static int efm32_spi_probe_dt(struct platform_device *pdev, + struct spi_master *master, struct efm32_spi_ddata *ddata) +{ + struct device_node *np = pdev->dev.of_node; + u32 location; + int ret; + + if (!np) + return 1; + + ret = of_property_read_u32(np, "location", &location); + if (!ret) { + dev_dbg(&pdev->dev, "using location %u\n", location); + } else { + /* default to location configured in hardware */ + location = efm32_spi_get_configured_location(ddata); + + dev_info(&pdev->dev, "fall back to location %u\n", location); + } + + ddata->pdata.location = location; + + /* spi core takes care about the bus number using an alias */ + master->bus_num = -1; + + return 0; +} + +static int efm32_spi_probe(struct platform_device *pdev) +{ + struct efm32_spi_ddata *ddata; + struct resource *res; + int ret; + struct spi_master *master; + struct device_node *np = pdev->dev.of_node; + unsigned int num_cs, i; + + num_cs = of_gpio_named_count(np, "cs-gpios"); + + master = spi_alloc_master(&pdev->dev, + sizeof(*ddata) + num_cs * sizeof(unsigned)); + if (!master) { + dev_dbg(&pdev->dev, + "failed to allocate spi master controller\n"); + return -ENOMEM; + } + platform_set_drvdata(pdev, master); + + master->dev.of_node = pdev->dev.of_node; + + master->num_chipselect = num_cs; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); + + ddata = spi_master_get_devdata(master); + + ddata->bitbang.master = spi_master_get(master); + ddata->bitbang.chipselect = efm32_spi_chipselect; + ddata->bitbang.setup_transfer = efm32_spi_setup_transfer; + ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs; + + spin_lock_init(&ddata->lock); + + ddata->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(ddata->clk)) { + ret = PTR_ERR(ddata->clk); + dev_err(&pdev->dev, "failed to get clock: %d\n", ret); + goto err; + } + + for (i = 0; i < num_cs; ++i) { + ret = of_get_named_gpio(np, "cs-gpios", i); + if (ret < 0) { + dev_err(&pdev->dev, "failed to get csgpio#%u (%d)\n", + i, ret); + goto err; + } + ddata->csgpio[i] = ret; + dev_dbg(&pdev->dev, "csgpio#%u = %u\n", i, ddata->csgpio[i]); + ret = devm_gpio_request_one(&pdev->dev, ddata->csgpio[i], + GPIOF_OUT_INIT_LOW, DRIVER_NAME); + if (ret < 0) { + dev_err(&pdev->dev, + "failed to configure csgpio#%u (%d)\n", + i, ret); + goto err; + } + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + ret = -ENODEV; + dev_err(&pdev->dev, "failed to determine base address\n"); + goto err; + } + + if (resource_size(res) < 60) { + ret = -EINVAL; + dev_err(&pdev->dev, "memory resource too small\n"); + goto err; + } + + ddata->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ddata->base)) { + ret = PTR_ERR(ddata->base); + goto err; + } + + ret = platform_get_irq(pdev, 0); + if (ret <= 0) { + dev_err(&pdev->dev, "failed to get rx irq (%d)\n", ret); + goto err; + } + + ddata->rxirq = ret; + + ret = platform_get_irq(pdev, 1); + if (ret <= 0) + ret = ddata->rxirq + 1; + + ddata->txirq = ret; + + ret = clk_prepare_enable(ddata->clk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret); + goto err; + } + + ret = efm32_spi_probe_dt(pdev, master, ddata); + if (ret > 0) { + /* not created by device tree */ + const struct efm32_spi_pdata *pdata = + dev_get_platdata(&pdev->dev); + + if (pdata) + ddata->pdata = *pdata; + else + ddata->pdata.location = + efm32_spi_get_configured_location(ddata); + + master->bus_num = pdev->id; + + } else if (ret < 0) { + goto err_disable_clk; + } + + efm32_spi_write32(ddata, 0, REG_IEN); + efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN | + REG_ROUTE_CLKPEN | + REG_ROUTE_LOCATION(ddata->pdata.location), REG_ROUTE); + + ret = request_irq(ddata->rxirq, efm32_spi_rxirq, + 0, DRIVER_NAME " rx", ddata); + if (ret) { + dev_err(&pdev->dev, "failed to register rxirq (%d)\n", ret); + goto err_disable_clk; + } + + ret = request_irq(ddata->txirq, efm32_spi_txirq, + 0, DRIVER_NAME " tx", ddata); + if (ret) { + dev_err(&pdev->dev, "failed to register txirq (%d)\n", ret); + goto err_free_rx_irq; + } + + ret = spi_bitbang_start(&ddata->bitbang); + if (ret) { + dev_err(&pdev->dev, "spi_bitbang_start failed (%d)\n", ret); + + free_irq(ddata->txirq, ddata); +err_free_rx_irq: + free_irq(ddata->rxirq, ddata); +err_disable_clk: + clk_disable_unprepare(ddata->clk); +err: + spi_master_put(master); + kfree(master); + } + + return ret; +} + +static int efm32_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct efm32_spi_ddata *ddata = spi_master_get_devdata(master); + + efm32_spi_write32(ddata, 0, REG_IEN); + + free_irq(ddata->txirq, ddata); + free_irq(ddata->rxirq, ddata); + clk_disable_unprepare(ddata->clk); + spi_master_put(master); + kfree(master); + + return 0; +} + +static const struct of_device_id efm32_spi_dt_ids[] = { + { + .compatible = "efm32,spi", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, efm32_spi_dt_ids); + +static struct platform_driver efm32_spi_driver = { + .probe = efm32_spi_probe, + .remove = efm32_spi_remove, + + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = efm32_spi_dt_ids, + }, +}; +module_platform_driver(efm32_spi_driver); + +MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>"); +MODULE_DESCRIPTION("EFM32 SPI driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index cad30b8a1d71..d22c00a227b6 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -26,7 +26,6 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/workqueue.h> #include <linux/sched.h> #include <linux/scatterlist.h> #include <linux/spi/spi.h> @@ -70,19 +69,13 @@ /** * struct ep93xx_spi - EP93xx SPI controller structure - * @lock: spinlock that protects concurrent accesses to fields @running, - * @current_msg and @msg_queue * @pdev: pointer to platform device * @clk: clock for the controller * @regs_base: pointer to ioremap()'d registers * @sspdr_phys: physical address of the SSPDR register * @min_rate: minimum clock rate (in Hz) supported by the controller * @max_rate: maximum clock rate (in Hz) supported by the controller - * @running: is the queue running - * @wq: workqueue used by the driver - * @msg_work: work that is queued for the driver * @wait: wait here until given transfer is completed - * @msg_queue: queue for the messages * @current_msg: message that is currently processed (or %NULL if none) * @tx: current byte in transfer to transmit * @rx: current byte in transfer to receive @@ -96,30 +89,15 @@ * @tx_sgt: sg table for TX transfers * @zeropage: dummy page used as RX buffer when only TX buffer is passed in by * the client - * - * This structure holds EP93xx SPI controller specific information. When - * @running is %true, driver accepts transfer requests from protocol drivers. - * @current_msg is used to hold pointer to the message that is currently - * processed. If @current_msg is %NULL, it means that no processing is going - * on. - * - * Most of the fields are only written once and they can be accessed without - * taking the @lock. Fields that are accessed concurrently are: @current_msg, - * @running, and @msg_queue. */ struct ep93xx_spi { - spinlock_t lock; const struct platform_device *pdev; struct clk *clk; void __iomem *regs_base; unsigned long sspdr_phys; unsigned long min_rate; unsigned long max_rate; - bool running; - struct workqueue_struct *wq; - struct work_struct msg_work; struct completion wait; - struct list_head msg_queue; struct spi_message *current_msg; size_t tx; size_t rx; @@ -136,50 +114,36 @@ struct ep93xx_spi { /** * struct ep93xx_spi_chip - SPI device hardware settings * @spi: back pointer to the SPI device - * @rate: max rate in hz this chip supports - * @div_cpsr: cpsr (pre-scaler) divider - * @div_scr: scr divider - * @dss: bits per word (4 - 16 bits) * @ops: private chip operations - * - * This structure is used to store hardware register specific settings for each - * SPI device. Settings are written to hardware by function - * ep93xx_spi_chip_setup(). */ struct ep93xx_spi_chip { const struct spi_device *spi; - unsigned long rate; - u8 div_cpsr; - u8 div_scr; - u8 dss; struct ep93xx_spi_chip_ops *ops; }; /* converts bits per word to CR0.DSS value */ #define bits_per_word_to_dss(bpw) ((bpw) - 1) -static inline void -ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value) +static void ep93xx_spi_write_u8(const struct ep93xx_spi *espi, + u16 reg, u8 value) { - __raw_writeb(value, espi->regs_base + reg); + writeb(value, espi->regs_base + reg); } -static inline u8 -ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg) +static u8 ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg) { - return __raw_readb(spi->regs_base + reg); + return readb(spi->regs_base + reg); } -static inline void -ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value) +static void ep93xx_spi_write_u16(const struct ep93xx_spi *espi, + u16 reg, u16 value) { - __raw_writew(value, espi->regs_base + reg); + writew(value, espi->regs_base + reg); } -static inline u16 -ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg) +static u16 ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg) { - return __raw_readw(spi->regs_base + reg); + return readw(spi->regs_base + reg); } static int ep93xx_spi_enable(const struct ep93xx_spi *espi) @@ -230,17 +194,13 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi) /** * ep93xx_spi_calc_divisors() - calculates SPI clock divisors * @espi: ep93xx SPI controller struct - * @chip: divisors are calculated for this chip * @rate: desired SPI output clock rate - * - * Function calculates cpsr (clock pre-scaler) and scr divisors based on - * given @rate and places them to @chip->div_cpsr and @chip->div_scr. If, - * for some reason, divisors cannot be calculated nothing is stored and - * %-EINVAL is returned. + * @div_cpsr: pointer to return the cpsr (pre-scaler) divider + * @div_scr: pointer to return the scr divider */ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, - struct ep93xx_spi_chip *chip, - unsigned long rate) + unsigned long rate, + u8 *div_cpsr, u8 *div_scr) { unsigned long spi_clk_rate = clk_get_rate(espi->clk); int cpsr, scr; @@ -248,7 +208,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, /* * Make sure that max value is between values supported by the * controller. Note that minimum value is already checked in - * ep93xx_spi_transfer(). + * ep93xx_spi_transfer_one_message(). */ rate = clamp(rate, espi->min_rate, espi->max_rate); @@ -263,8 +223,8 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, for (cpsr = 2; cpsr <= 254; cpsr += 2) { for (scr = 0; scr <= 255; scr++) { if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) { - chip->div_scr = (u8)scr; - chip->div_cpsr = (u8)cpsr; + *div_scr = (u8)scr; + *div_cpsr = (u8)cpsr; return 0; } } @@ -319,73 +279,11 @@ static int ep93xx_spi_setup(struct spi_device *spi) spi_set_ctldata(spi, chip); } - if (spi->max_speed_hz != chip->rate) { - int err; - - err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz); - if (err != 0) { - spi_set_ctldata(spi, NULL); - kfree(chip); - return err; - } - chip->rate = spi->max_speed_hz; - } - - chip->dss = bits_per_word_to_dss(spi->bits_per_word); - ep93xx_spi_cs_control(spi, false); return 0; } /** - * ep93xx_spi_transfer() - queue message to be transferred - * @spi: target SPI device - * @msg: message to be transferred - * - * This function is called by SPI device drivers when they are going to transfer - * a new message. It simply puts the message in the queue and schedules - * workqueue to perform the actual transfer later on. - * - * Returns %0 on success and negative error in case of failure. - */ -static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg) -{ - struct ep93xx_spi *espi = spi_master_get_devdata(spi->master); - struct spi_transfer *t; - unsigned long flags; - - if (!msg || !msg->complete) - return -EINVAL; - - /* first validate each transfer */ - list_for_each_entry(t, &msg->transfers, transfer_list) { - if (t->speed_hz && t->speed_hz < espi->min_rate) - return -EINVAL; - } - - /* - * Now that we own the message, let's initialize it so that it is - * suitable for us. We use @msg->status to signal whether there was - * error in transfer and @msg->state is used to hold pointer to the - * current transfer (or %NULL if no active current transfer). - */ - msg->state = NULL; - msg->status = 0; - msg->actual_length = 0; - - spin_lock_irqsave(&espi->lock, flags); - if (!espi->running) { - spin_unlock_irqrestore(&espi->lock, flags); - return -ESHUTDOWN; - } - list_add_tail(&msg->queue, &espi->msg_queue); - queue_work(espi->wq, &espi->msg_work); - spin_unlock_irqrestore(&espi->lock, flags); - - return 0; -} - -/** * ep93xx_spi_cleanup() - cleans up master controller specific state * @spi: SPI device to cleanup * @@ -409,39 +307,40 @@ static void ep93xx_spi_cleanup(struct spi_device *spi) * ep93xx_spi_chip_setup() - configures hardware according to given @chip * @espi: ep93xx SPI controller struct * @chip: chip specific settings - * - * This function sets up the actual hardware registers with settings given in - * @chip. Note that no validation is done so make sure that callers validate - * settings before calling this. + * @speed_hz: transfer speed + * @bits_per_word: transfer bits_per_word */ -static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, - const struct ep93xx_spi_chip *chip) +static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, + const struct ep93xx_spi_chip *chip, + u32 speed_hz, u8 bits_per_word) { + u8 dss = bits_per_word_to_dss(bits_per_word); + u8 div_cpsr = 0; + u8 div_scr = 0; u16 cr0; + int err; - cr0 = chip->div_scr << SSPCR0_SCR_SHIFT; + err = ep93xx_spi_calc_divisors(espi, speed_hz, &div_cpsr, &div_scr); + if (err) + return err; + + cr0 = div_scr << SSPCR0_SCR_SHIFT; cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT; - cr0 |= chip->dss; + cr0 |= dss; dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n", - chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss); + chip->spi->mode, div_cpsr, div_scr, dss); dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0); - ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr); + ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr); ep93xx_spi_write_u16(espi, SSPCR0, cr0); -} - -static inline int bits_per_word(const struct ep93xx_spi *espi) -{ - struct spi_message *msg = espi->current_msg; - struct spi_transfer *t = msg->state; - return t->bits_per_word; + return 0; } static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t) { - if (bits_per_word(espi) > 8) { + if (t->bits_per_word > 8) { u16 tx_val = 0; if (t->tx_buf) @@ -460,7 +359,7 @@ static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t) static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t) { - if (bits_per_word(espi) > 8) { + if (t->bits_per_word > 8) { u16 rx_val; rx_val = ep93xx_spi_read_u16(espi, SSPDR); @@ -546,7 +445,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir) size_t len = t->len; int i, ret, nents; - if (bits_per_word(espi) > 8) + if (t->bits_per_word > 8) buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; else buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE; @@ -610,7 +509,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir) } if (WARN_ON(len)) { - dev_warn(&espi->pdev->dev, "len = %d expected 0!", len); + dev_warn(&espi->pdev->dev, "len = %zu expected 0!", len); return ERR_PTR(-EINVAL); } @@ -708,37 +607,16 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, struct spi_transfer *t) { struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi); + int err; msg->state = t; - /* - * Handle any transfer specific settings if needed. We use - * temporary chip settings here and restore original later when - * the transfer is finished. - */ - if (t->speed_hz || t->bits_per_word) { - struct ep93xx_spi_chip tmp_chip = *chip; - - if (t->speed_hz) { - int err; - - err = ep93xx_spi_calc_divisors(espi, &tmp_chip, - t->speed_hz); - if (err) { - dev_err(&espi->pdev->dev, - "failed to adjust speed\n"); - msg->status = err; - return; - } - } - - if (t->bits_per_word) - tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word); - - /* - * Set up temporary new hw settings for this transfer. - */ - ep93xx_spi_chip_setup(espi, &tmp_chip); + err = ep93xx_spi_chip_setup(espi, chip, t->speed_hz, t->bits_per_word); + if (err) { + dev_err(&espi->pdev->dev, + "failed to setup chip for transfer\n"); + msg->status = err; + return; } espi->rx = 0; @@ -783,9 +661,6 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, ep93xx_spi_cs_control(msg->spi, true); } } - - if (t->speed_hz || t->bits_per_word) - ep93xx_spi_chip_setup(espi, chip); } /* @@ -838,10 +713,8 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi, espi->fifo_level = 0; /* - * Update SPI controller registers according to spi device and assert - * the chipselect. + * Assert the chipselect. */ - ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi)); ep93xx_spi_cs_control(msg->spi, true); list_for_each_entry(t, &msg->transfers, transfer_list) { @@ -858,50 +731,29 @@ static void ep93xx_spi_process_message(struct ep93xx_spi *espi, ep93xx_spi_disable(espi); } -#define work_to_espi(work) (container_of((work), struct ep93xx_spi, msg_work)) - -/** - * ep93xx_spi_work() - EP93xx SPI workqueue worker function - * @work: work struct - * - * Workqueue worker function. This function is called when there are new - * SPI messages to be processed. Message is taken out from the queue and then - * passed to ep93xx_spi_process_message(). - * - * After message is transferred, protocol driver is notified by calling - * @msg->complete(). In case of error, @msg->status is set to negative error - * number, otherwise it contains zero (and @msg->actual_length is updated). - */ -static void ep93xx_spi_work(struct work_struct *work) +static int ep93xx_spi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) { - struct ep93xx_spi *espi = work_to_espi(work); - struct spi_message *msg; + struct ep93xx_spi *espi = spi_master_get_devdata(master); + struct spi_transfer *t; - spin_lock_irq(&espi->lock); - if (!espi->running || espi->current_msg || - list_empty(&espi->msg_queue)) { - spin_unlock_irq(&espi->lock); - return; + /* first validate each transfer */ + list_for_each_entry(t, &msg->transfers, transfer_list) { + if (t->speed_hz < espi->min_rate) + return -EINVAL; } - msg = list_first_entry(&espi->msg_queue, struct spi_message, queue); - list_del_init(&msg->queue); - espi->current_msg = msg; - spin_unlock_irq(&espi->lock); - ep93xx_spi_process_message(espi, msg); + msg->state = NULL; + msg->status = 0; + msg->actual_length = 0; - /* - * Update the current message and re-schedule ourselves if there are - * more messages in the queue. - */ - spin_lock_irq(&espi->lock); + espi->current_msg = msg; + ep93xx_spi_process_message(espi, msg); espi->current_msg = NULL; - if (espi->running && !list_empty(&espi->msg_queue)) - queue_work(espi->wq, &espi->msg_work); - spin_unlock_irq(&espi->lock); - /* notify the protocol driver that we are done with this message */ - msg->complete(msg->context); + spi_finalize_current_message(master); + + return 0; } static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id) @@ -1022,16 +874,26 @@ static int ep93xx_spi_probe(struct platform_device *pdev) int irq; int error; - info = pdev->dev.platform_data; + info = dev_get_platdata(&pdev->dev); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get irq resources\n"); + return -EBUSY; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "unable to get iomem resource\n"); + return -ENODEV; + } master = spi_alloc_master(&pdev->dev, sizeof(*espi)); - if (!master) { - dev_err(&pdev->dev, "failed to allocate spi master\n"); + if (!master) return -ENOMEM; - } master->setup = ep93xx_spi_setup; - master->transfer = ep93xx_spi_transfer; + master->transfer_one_message = ep93xx_spi_transfer_one_message; master->cleanup = ep93xx_spi_cleanup; master->bus_num = pdev->id; master->num_chipselect = info->num_chipselect; @@ -1042,14 +904,13 @@ static int ep93xx_spi_probe(struct platform_device *pdev) espi = spi_master_get_devdata(master); - espi->clk = clk_get(&pdev->dev, NULL); + espi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(espi->clk)) { dev_err(&pdev->dev, "unable to get spi clock\n"); error = PTR_ERR(espi->clk); goto fail_release_master; } - spin_lock_init(&espi->lock); init_completion(&espi->wait); /* @@ -1060,55 +921,31 @@ static int ep93xx_spi_probe(struct platform_device *pdev) espi->min_rate = clk_get_rate(espi->clk) / (254 * 256); espi->pdev = pdev; - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - error = -EBUSY; - dev_err(&pdev->dev, "failed to get irq resources\n"); - goto fail_put_clock; - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "unable to get iomem resource\n"); - error = -ENODEV; - goto fail_put_clock; - } - espi->sspdr_phys = res->start + SSPDR; espi->regs_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(espi->regs_base)) { error = PTR_ERR(espi->regs_base); - goto fail_put_clock; + goto fail_release_master; } error = devm_request_irq(&pdev->dev, irq, ep93xx_spi_interrupt, 0, "ep93xx-spi", espi); if (error) { dev_err(&pdev->dev, "failed to request irq\n"); - goto fail_put_clock; + goto fail_release_master; } if (info->use_dma && ep93xx_spi_setup_dma(espi)) dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n"); - espi->wq = create_singlethread_workqueue("ep93xx_spid"); - if (!espi->wq) { - dev_err(&pdev->dev, "unable to create workqueue\n"); - error = -ENOMEM; - goto fail_free_dma; - } - INIT_WORK(&espi->msg_work, ep93xx_spi_work); - INIT_LIST_HEAD(&espi->msg_queue); - espi->running = true; - /* make sure that the hardware is disabled */ ep93xx_spi_write_u8(espi, SSPCR1, 0); error = spi_register_master(master); if (error) { dev_err(&pdev->dev, "failed to register SPI master\n"); - goto fail_free_queue; + goto fail_free_dma; } dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n", @@ -1116,12 +953,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev) return 0; -fail_free_queue: - destroy_workqueue(espi->wq); fail_free_dma: ep93xx_spi_release_dma(espi); -fail_put_clock: - clk_put(espi->clk); fail_release_master: spi_master_put(master); @@ -1133,31 +966,7 @@ static int ep93xx_spi_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct ep93xx_spi *espi = spi_master_get_devdata(master); - spin_lock_irq(&espi->lock); - espi->running = false; - spin_unlock_irq(&espi->lock); - - destroy_workqueue(espi->wq); - - /* - * Complete remaining messages with %-ESHUTDOWN status. - */ - spin_lock_irq(&espi->lock); - while (!list_empty(&espi->msg_queue)) { - struct spi_message *msg; - - msg = list_first_entry(&espi->msg_queue, - struct spi_message, queue); - list_del_init(&msg->queue); - msg->status = -ESHUTDOWN; - spin_unlock_irq(&espi->lock); - msg->complete(msg->context); - spin_lock_irq(&espi->lock); - } - spin_unlock_irq(&espi->lock); - ep93xx_spi_release_dma(espi); - clk_put(espi->clk); spi_unregister_master(master); return 0; diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c new file mode 100644 index 000000000000..6cd07d13ecab --- /dev/null +++ b/drivers/spi/spi-fsl-dspi.c @@ -0,0 +1,557 @@ +/* + * drivers/spi/spi-fsl-dspi.c + * + * Copyright 2013 Freescale Semiconductor, Inc. + * + * Freescale DSPI driver + * This file contains a driver for the Freescale DSPI + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> +#include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_device.h> + +#define DRIVER_NAME "fsl-dspi" + +#define TRAN_STATE_RX_VOID 0x01 +#define TRAN_STATE_TX_VOID 0x02 +#define TRAN_STATE_WORD_ODD_NUM 0x04 + +#define DSPI_FIFO_SIZE 4 + +#define SPI_MCR 0x00 +#define SPI_MCR_MASTER (1 << 31) +#define SPI_MCR_PCSIS (0x3F << 16) +#define SPI_MCR_CLR_TXF (1 << 11) +#define SPI_MCR_CLR_RXF (1 << 10) + +#define SPI_TCR 0x08 + +#define SPI_CTAR(x) (0x0c + (x * 4)) +#define SPI_CTAR_FMSZ(x) (((x) & 0x0000000f) << 27) +#define SPI_CTAR_CPOL(x) ((x) << 26) +#define SPI_CTAR_CPHA(x) ((x) << 25) +#define SPI_CTAR_LSBFE(x) ((x) << 24) +#define SPI_CTAR_PCSSCR(x) (((x) & 0x00000003) << 22) +#define SPI_CTAR_PASC(x) (((x) & 0x00000003) << 20) +#define SPI_CTAR_PDT(x) (((x) & 0x00000003) << 18) +#define SPI_CTAR_PBR(x) (((x) & 0x00000003) << 16) +#define SPI_CTAR_CSSCK(x) (((x) & 0x0000000f) << 12) +#define SPI_CTAR_ASC(x) (((x) & 0x0000000f) << 8) +#define SPI_CTAR_DT(x) (((x) & 0x0000000f) << 4) +#define SPI_CTAR_BR(x) ((x) & 0x0000000f) + +#define SPI_CTAR0_SLAVE 0x0c + +#define SPI_SR 0x2c +#define SPI_SR_EOQF 0x10000000 + +#define SPI_RSER 0x30 +#define SPI_RSER_EOQFE 0x10000000 + +#define SPI_PUSHR 0x34 +#define SPI_PUSHR_CONT (1 << 31) +#define SPI_PUSHR_CTAS(x) (((x) & 0x00000007) << 28) +#define SPI_PUSHR_EOQ (1 << 27) +#define SPI_PUSHR_CTCNT (1 << 26) +#define SPI_PUSHR_PCS(x) (((1 << x) & 0x0000003f) << 16) +#define SPI_PUSHR_TXDATA(x) ((x) & 0x0000ffff) + +#define SPI_PUSHR_SLAVE 0x34 + +#define SPI_POPR 0x38 +#define SPI_POPR_RXDATA(x) ((x) & 0x0000ffff) + +#define SPI_TXFR0 0x3c +#define SPI_TXFR1 0x40 +#define SPI_TXFR2 0x44 +#define SPI_TXFR3 0x48 +#define SPI_RXFR0 0x7c +#define SPI_RXFR1 0x80 +#define SPI_RXFR2 0x84 +#define SPI_RXFR3 0x88 + +#define SPI_FRAME_BITS(bits) SPI_CTAR_FMSZ((bits) - 1) +#define SPI_FRAME_BITS_MASK SPI_CTAR_FMSZ(0xf) +#define SPI_FRAME_BITS_16 SPI_CTAR_FMSZ(0xf) +#define SPI_FRAME_BITS_8 SPI_CTAR_FMSZ(0x7) + +#define SPI_CS_INIT 0x01 +#define SPI_CS_ASSERT 0x02 +#define SPI_CS_DROP 0x04 + +struct chip_data { + u32 mcr_val; + u32 ctar_val; + u16 void_write_data; +}; + +struct fsl_dspi { + struct spi_bitbang bitbang; + struct platform_device *pdev; + + void *base; + int irq; + struct clk *clk; + + struct spi_transfer *cur_transfer; + struct chip_data *cur_chip; + size_t len; + void *tx; + void *tx_end; + void *rx; + void *rx_end; + char dataflags; + u8 cs; + u16 void_write_data; + + wait_queue_head_t waitq; + u32 waitflags; +}; + +static inline int is_double_byte_mode(struct fsl_dspi *dspi) +{ + return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK) + == SPI_FRAME_BITS(8)) ? 0 : 1; +} + +static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits) +{ + u32 temp; + + temp = readl(dspi->base + SPI_CTAR(dspi->cs)); + temp &= ~SPI_FRAME_BITS_MASK; + temp |= SPI_FRAME_BITS(bits); + writel(temp, dspi->base + SPI_CTAR(dspi->cs)); +} + +static void hz_to_spi_baud(char *pbr, char *br, int speed_hz, + unsigned long clkrate) +{ + /* Valid baud rate pre-scaler values */ + int pbr_tbl[4] = {2, 3, 5, 7}; + int brs[16] = { 2, 4, 6, 8, + 16, 32, 64, 128, + 256, 512, 1024, 2048, + 4096, 8192, 16384, 32768 }; + int temp, i = 0, j = 0; + + temp = clkrate / 2 / speed_hz; + + for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++) + for (j = 0; j < ARRAY_SIZE(brs); j++) { + if (pbr_tbl[i] * brs[j] >= temp) { + *pbr = i; + *br = j; + return; + } + } + + pr_warn("Can not find valid buad rate,speed_hz is %d,clkrate is %ld\ + ,we use the max prescaler value.\n", speed_hz, clkrate); + *pbr = ARRAY_SIZE(pbr_tbl) - 1; + *br = ARRAY_SIZE(brs) - 1; +} + +static int dspi_transfer_write(struct fsl_dspi *dspi) +{ + int tx_count = 0; + int tx_word; + u16 d16; + u8 d8; + u32 dspi_pushr = 0; + int first = 1; + + tx_word = is_double_byte_mode(dspi); + + /* If we are in word mode, but only have a single byte to transfer + * then switch to byte mode temporarily. Will switch back at the + * end of the transfer. + */ + if (tx_word && (dspi->len == 1)) { + dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; + set_bit_mode(dspi, 8); + tx_word = 0; + } + + while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) { + if (tx_word) { + if (dspi->len == 1) + break; + + if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) { + d16 = *(u16 *)dspi->tx; + dspi->tx += 2; + } else { + d16 = dspi->void_write_data; + } + + dspi_pushr = SPI_PUSHR_TXDATA(d16) | + SPI_PUSHR_PCS(dspi->cs) | + SPI_PUSHR_CTAS(dspi->cs) | + SPI_PUSHR_CONT; + + dspi->len -= 2; + } else { + if (!(dspi->dataflags & TRAN_STATE_TX_VOID)) { + + d8 = *(u8 *)dspi->tx; + dspi->tx++; + } else { + d8 = (u8)dspi->void_write_data; + } + + dspi_pushr = SPI_PUSHR_TXDATA(d8) | + SPI_PUSHR_PCS(dspi->cs) | + SPI_PUSHR_CTAS(dspi->cs) | + SPI_PUSHR_CONT; + + dspi->len--; + } + + if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) { + /* last transfer in the transfer */ + dspi_pushr |= SPI_PUSHR_EOQ; + } else if (tx_word && (dspi->len == 1)) + dspi_pushr |= SPI_PUSHR_EOQ; + + if (first) { + first = 0; + dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */ + } + + writel(dspi_pushr, dspi->base + SPI_PUSHR); + tx_count++; + } + + return tx_count * (tx_word + 1); +} + +static int dspi_transfer_read(struct fsl_dspi *dspi) +{ + int rx_count = 0; + int rx_word = is_double_byte_mode(dspi); + u16 d; + while ((dspi->rx < dspi->rx_end) + && (rx_count < DSPI_FIFO_SIZE)) { + if (rx_word) { + if ((dspi->rx_end - dspi->rx) == 1) + break; + + d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR)); + + if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) + *(u16 *)dspi->rx = d; + dspi->rx += 2; + + } else { + d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR)); + if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) + *(u8 *)dspi->rx = d; + dspi->rx++; + } + rx_count++; + } + + return rx_count; +} + +static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); + dspi->cur_transfer = t; + dspi->cur_chip = spi_get_ctldata(spi); + dspi->cs = spi->chip_select; + dspi->void_write_data = dspi->cur_chip->void_write_data; + + dspi->dataflags = 0; + dspi->tx = (void *)t->tx_buf; + dspi->tx_end = dspi->tx + t->len; + dspi->rx = t->rx_buf; + dspi->rx_end = dspi->rx + t->len; + dspi->len = t->len; + + if (!dspi->rx) + dspi->dataflags |= TRAN_STATE_RX_VOID; + + if (!dspi->tx) + dspi->dataflags |= TRAN_STATE_TX_VOID; + + writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR); + writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs)); + writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER); + + if (t->speed_hz) + writel(dspi->cur_chip->ctar_val, + dspi->base + SPI_CTAR(dspi->cs)); + + dspi_transfer_write(dspi); + + if (wait_event_interruptible(dspi->waitq, dspi->waitflags)) + dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n"); + dspi->waitflags = 0; + + return t->len - dspi->len; +} + +static void dspi_chipselect(struct spi_device *spi, int value) +{ + struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); + u32 pushr = readl(dspi->base + SPI_PUSHR); + + switch (value) { + case BITBANG_CS_ACTIVE: + pushr |= SPI_PUSHR_CONT; + case BITBANG_CS_INACTIVE: + pushr &= ~SPI_PUSHR_CONT; + } + + writel(pushr, dspi->base + SPI_PUSHR); +} + +static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) +{ + struct chip_data *chip; + struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); + unsigned char br = 0, pbr = 0, fmsz = 0; + + /* Only alloc on first setup */ + chip = spi_get_ctldata(spi); + if (chip == NULL) { + chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL); + if (!chip) + return -ENOMEM; + } + + chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS | + SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF; + if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) { + fmsz = spi->bits_per_word - 1; + } else { + pr_err("Invalid wordsize\n"); + kfree(chip); + return -ENODEV; + } + + chip->void_write_data = 0; + + hz_to_spi_baud(&pbr, &br, + spi->max_speed_hz, clk_get_rate(dspi->clk)); + + chip->ctar_val = SPI_CTAR_FMSZ(fmsz) + | SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0) + | SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0) + | SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0) + | SPI_CTAR_PBR(pbr) + | SPI_CTAR_BR(br); + + spi_set_ctldata(spi, chip); + + return 0; +} + +static int dspi_setup(struct spi_device *spi) +{ + if (!spi->max_speed_hz) + return -EINVAL; + + if (!spi->bits_per_word) + spi->bits_per_word = 8; + + return dspi_setup_transfer(spi, NULL); +} + +static irqreturn_t dspi_interrupt(int irq, void *dev_id) +{ + struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; + + writel(SPI_SR_EOQF, dspi->base + SPI_SR); + + dspi_transfer_read(dspi); + + if (!dspi->len) { + if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) + set_bit_mode(dspi, 16); + dspi->waitflags = 1; + wake_up_interruptible(&dspi->waitq); + } else { + dspi_transfer_write(dspi); + + return IRQ_HANDLED; + } + + return IRQ_HANDLED; +} + +static struct of_device_id fsl_dspi_dt_ids[] = { + { .compatible = "fsl,vf610-dspi", .data = NULL, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_dspi_dt_ids); + +#ifdef CONFIG_PM_SLEEP +static int dspi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct fsl_dspi *dspi = spi_master_get_devdata(master); + + spi_master_suspend(master); + clk_disable_unprepare(dspi->clk); + + return 0; +} + +static int dspi_resume(struct device *dev) +{ + + struct spi_master *master = dev_get_drvdata(dev); + struct fsl_dspi *dspi = spi_master_get_devdata(master); + + clk_prepare_enable(dspi->clk); + spi_master_resume(master); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops dspi_pm = { + SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume) +}; + +static int dspi_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct spi_master *master; + struct fsl_dspi *dspi; + struct resource *res; + int ret = 0, cs_num, bus_num; + + master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi)); + if (!master) + return -ENOMEM; + + dspi = spi_master_get_devdata(master); + dspi->pdev = pdev; + dspi->bitbang.master = spi_master_get(master); + dspi->bitbang.chipselect = dspi_chipselect; + dspi->bitbang.setup_transfer = dspi_setup_transfer; + dspi->bitbang.txrx_bufs = dspi_txrx_transfer; + dspi->bitbang.master->setup = dspi_setup; + dspi->bitbang.master->dev.of_node = pdev->dev.of_node; + + master->mode_bits = SPI_CPOL | SPI_CPHA; + master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) | + SPI_BPW_MASK(16); + + ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num); + if (ret < 0) { + dev_err(&pdev->dev, "can't get spi-num-chipselects\n"); + goto out_master_put; + } + master->num_chipselect = cs_num; + + ret = of_property_read_u32(np, "bus-num", &bus_num); + if (ret < 0) { + dev_err(&pdev->dev, "can't get bus-num\n"); + goto out_master_put; + } + master->bus_num = bus_num; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "can't get platform resource\n"); + ret = -EINVAL; + goto out_master_put; + } + + dspi->base = devm_ioremap_resource(&pdev->dev, res); + if (!dspi->base) { + ret = -EINVAL; + goto out_master_put; + } + + dspi->irq = platform_get_irq(pdev, 0); + if (dspi->irq < 0) { + dev_err(&pdev->dev, "can't get platform irq\n"); + ret = dspi->irq; + goto out_master_put; + } + + ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt, 0, + pdev->name, dspi); + if (ret < 0) { + dev_err(&pdev->dev, "Unable to attach DSPI interrupt\n"); + goto out_master_put; + } + + dspi->clk = devm_clk_get(&pdev->dev, "dspi"); + if (IS_ERR(dspi->clk)) { + ret = PTR_ERR(dspi->clk); + dev_err(&pdev->dev, "unable to get clock\n"); + goto out_master_put; + } + clk_prepare_enable(dspi->clk); + + init_waitqueue_head(&dspi->waitq); + platform_set_drvdata(pdev, dspi); + + ret = spi_bitbang_start(&dspi->bitbang); + if (ret != 0) { + dev_err(&pdev->dev, "Problem registering DSPI master\n"); + goto out_clk_put; + } + + pr_info(KERN_INFO "Freescale DSPI master initialized\n"); + return ret; + +out_clk_put: + clk_disable_unprepare(dspi->clk); +out_master_put: + spi_master_put(master); + platform_set_drvdata(pdev, NULL); + + return ret; +} + +static int dspi_remove(struct platform_device *pdev) +{ + struct fsl_dspi *dspi = platform_get_drvdata(pdev); + + /* Disconnect from the SPI framework */ + spi_bitbang_stop(&dspi->bitbang); + spi_master_put(dspi->bitbang.master); + + return 0; +} + +static struct platform_driver fsl_dspi_driver = { + .driver.name = DRIVER_NAME, + .driver.of_match_table = fsl_dspi_dt_ids, + .driver.owner = THIS_MODULE, + .driver.pm = &dspi_pm, + .probe = dspi_probe, + .remove = dspi_remove, +}; +module_platform_driver(fsl_dspi_driver); + +MODULE_DESCRIPTION("Freescale DSPI Controller Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 6a74d7848d93..b8f1103fe28e 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -584,7 +584,7 @@ static void fsl_espi_remove(struct mpc8xxx_spi *mspi) static struct spi_master * fsl_espi_probe(struct device *dev, struct resource *mem, unsigned int irq) { - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; struct fsl_espi_reg *reg_base; @@ -665,7 +665,7 @@ err: static int of_fsl_espi_get_chipselects(struct device *dev) { struct device_node *np = dev->of_node; - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); const u32 *prop; int len; diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index e947f2d1b2f5..0b75f26158ab 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -122,7 +122,7 @@ const char *mpc8xxx_spi_strmode(unsigned int flags) int mpc8xxx_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) { - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; int ret = 0; diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 41e89c3e3edc..bbc94294891c 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -574,7 +574,7 @@ static void fsl_spi_grlib_cs_control(struct spi_device *spi, bool on) static void fsl_spi_grlib_probe(struct device *dev) { - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master = dev_get_drvdata(dev); struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(master); struct fsl_spi_reg *reg_base = mpc8xxx_spi->reg_base; @@ -600,7 +600,7 @@ static void fsl_spi_grlib_probe(struct device *dev) static struct spi_master * fsl_spi_probe(struct device *dev, struct resource *mem, unsigned int irq) { - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct spi_master *master; struct mpc8xxx_spi *mpc8xxx_spi; struct fsl_spi_reg *reg_base; @@ -700,7 +700,8 @@ err: static void fsl_spi_cs_control(struct spi_device *spi, bool on) { struct device *dev = spi->dev.parent->parent; - struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(dev->platform_data); + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); + struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); u16 cs = spi->chip_select; int gpio = pinfo->gpios[cs]; bool alow = pinfo->alow_flags[cs]; @@ -711,7 +712,7 @@ static void fsl_spi_cs_control(struct spi_device *spi, bool on) static int of_fsl_spi_get_chipselects(struct device *dev) { struct device_node *np = dev->of_node; - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); int ngpios; int i = 0; @@ -790,7 +791,7 @@ err_alloc_flags: static int of_fsl_spi_free_chipselects(struct device *dev) { - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc8xxx_spi_probe_info *pinfo = to_of_pinfo(pdata); int i; @@ -889,7 +890,7 @@ static int plat_mpc8xxx_spi_probe(struct platform_device *pdev) int irq; struct spi_master *master; - if (!pdev->dev.platform_data) + if (!dev_get_platdata(&pdev->dev)) return -EINVAL; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index a54524cf42cc..68b69fec13a9 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -420,7 +420,7 @@ static int spi_gpio_probe(struct platform_device *pdev) if (status > 0) use_of = 1; - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); #ifdef GENERIC_BITBANG if (!pdata || !pdata->num_chipselect) return -ENODEV; @@ -506,7 +506,7 @@ static int spi_gpio_remove(struct platform_device *pdev) int status; spi_gpio = platform_get_drvdata(pdev); - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); /* stop() unregisters child devices too */ status = spi_bitbang_stop(&spi_gpio->bitbang); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 7db4f43ee4d8..15323d8bd9cf 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -619,6 +619,7 @@ static const struct of_device_id spi_imx_dt_ids[] = { { .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, spi_imx_dt_ids); static void spi_imx_chipselect(struct spi_device *spi, int is_active) { @@ -796,10 +797,11 @@ static int spi_imx_probe(struct platform_device *pdev) if (!gpio_is_valid(cs_gpio)) continue; - ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME); + ret = devm_gpio_request(&pdev->dev, spi_imx->chipselect[i], + DRIVER_NAME); if (ret) { dev_err(&pdev->dev, "can't get cs gpios\n"); - goto out_gpio_free; + goto out_master_put; } } @@ -816,50 +818,44 @@ static int spi_imx_probe(struct platform_device *pdev) (struct spi_imx_devtype_data *) pdev->id_entry->driver_data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "can't get platform resource\n"); - ret = -ENOMEM; - goto out_gpio_free; - } - - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - ret = -EBUSY; - goto out_gpio_free; - } - - spi_imx->base = ioremap(res->start, resource_size(res)); - if (!spi_imx->base) { - ret = -EINVAL; - goto out_release_mem; + spi_imx->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(spi_imx->base)) { + ret = PTR_ERR(spi_imx->base); + goto out_master_put; } spi_imx->irq = platform_get_irq(pdev, 0); if (spi_imx->irq < 0) { ret = -EINVAL; - goto out_iounmap; + goto out_master_put; } - ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx); + ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0, + DRIVER_NAME, spi_imx); if (ret) { dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret); - goto out_iounmap; + goto out_master_put; } spi_imx->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(spi_imx->clk_ipg)) { ret = PTR_ERR(spi_imx->clk_ipg); - goto out_free_irq; + goto out_master_put; } spi_imx->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(spi_imx->clk_per)) { ret = PTR_ERR(spi_imx->clk_per); - goto out_free_irq; + goto out_master_put; } - clk_prepare_enable(spi_imx->clk_per); - clk_prepare_enable(spi_imx->clk_ipg); + ret = clk_prepare_enable(spi_imx->clk_per); + if (ret) + goto out_master_put; + + ret = clk_prepare_enable(spi_imx->clk_ipg); + if (ret) + goto out_put_per; spi_imx->spi_clk = clk_get_rate(spi_imx->clk_per); @@ -879,47 +875,27 @@ static int spi_imx_probe(struct platform_device *pdev) return ret; out_clk_put: - clk_disable_unprepare(spi_imx->clk_per); clk_disable_unprepare(spi_imx->clk_ipg); -out_free_irq: - free_irq(spi_imx->irq, spi_imx); -out_iounmap: - iounmap(spi_imx->base); -out_release_mem: - release_mem_region(res->start, resource_size(res)); -out_gpio_free: - while (--i >= 0) { - if (gpio_is_valid(spi_imx->chipselect[i])) - gpio_free(spi_imx->chipselect[i]); - } +out_put_per: + clk_disable_unprepare(spi_imx->clk_per); +out_master_put: spi_master_put(master); - kfree(master); + return ret; } static int spi_imx_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - int i; spi_bitbang_stop(&spi_imx->bitbang); writel(0, spi_imx->base + MXC_CSPICTRL); - clk_disable_unprepare(spi_imx->clk_per); clk_disable_unprepare(spi_imx->clk_ipg); - free_irq(spi_imx->irq, spi_imx); - iounmap(spi_imx->base); - - for (i = 0; i < master->num_chipselect; i++) - if (gpio_is_valid(spi_imx->chipselect[i])) - gpio_free(spi_imx->chipselect[i]); - + clk_disable_unprepare(spi_imx->clk_per); spi_master_put(master); - release_mem_region(res->start, resource_size(res)); - return 0; } diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 29fce6af5145..dbc5e999a1f5 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -38,7 +38,8 @@ struct mpc512x_psc_spi { struct mpc512x_psc_fifo __iomem *fifo; unsigned int irq; u8 bits_per_word; - u32 mclk; + struct clk *clk_mclk; + u32 mclk_rate; struct completion txisrdone; }; @@ -72,6 +73,7 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) struct mpc52xx_psc __iomem *psc = mps->psc; u32 sicr; u32 ccr; + int speed; u16 bclkdiv; sicr = in_be32(&psc->sicr); @@ -95,10 +97,10 @@ static void mpc512x_psc_spi_activate_cs(struct spi_device *spi) ccr = in_be32(&psc->ccr); ccr &= 0xFF000000; - if (cs->speed_hz) - bclkdiv = (mps->mclk / cs->speed_hz) - 1; - else - bclkdiv = (mps->mclk / 1000000) - 1; /* default 1MHz */ + speed = cs->speed_hz; + if (!speed) + speed = 1000000; /* default 1MHz */ + bclkdiv = (mps->mclk_rate / speed) - 1; ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); out_be32(&psc->ccr, ccr); @@ -386,19 +388,11 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, { struct mpc52xx_psc __iomem *psc = mps->psc; struct mpc512x_psc_fifo __iomem *fifo = mps->fifo; - struct clk *spiclk; - int ret = 0; - char name[32]; u32 sicr; u32 ccr; + int speed; u16 bclkdiv; - sprintf(name, "psc%d_mclk", master->bus_num); - spiclk = clk_get(&master->dev, name); - clk_enable(spiclk); - mps->mclk = clk_get_rate(spiclk); - clk_put(spiclk); - /* Reset the PSC into a known state */ out_8(&psc->command, MPC52xx_PSC_RST_RX); out_8(&psc->command, MPC52xx_PSC_RST_TX); @@ -425,7 +419,8 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, ccr = in_be32(&psc->ccr); ccr &= 0xFF000000; - bclkdiv = (mps->mclk / 1000000) - 1; /* default 1MHz */ + speed = 1000000; /* default 1MHz */ + bclkdiv = (mps->mclk_rate / speed) - 1; ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8)); out_be32(&psc->ccr, ccr); @@ -445,7 +440,7 @@ static int mpc512x_psc_spi_port_config(struct spi_master *master, mps->bits_per_word = 8; - return ret; + return 0; } static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id) @@ -474,11 +469,14 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, u32 size, unsigned int irq, s16 bus_num) { - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc512x_psc_spi *mps; struct spi_master *master; int ret; void *tempp; + int psc_num; + char clk_name[16]; + struct clk *clk; master = spi_alloc_master(dev, sizeof *mps); if (master == NULL) @@ -521,16 +519,29 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, goto free_master; init_completion(&mps->txisrdone); + psc_num = master->bus_num; + snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num); + clk = devm_clk_get(dev, clk_name); + if (IS_ERR(clk)) + goto free_irq; + ret = clk_prepare_enable(clk); + if (ret) + goto free_irq; + mps->clk_mclk = clk; + mps->mclk_rate = clk_get_rate(clk); + ret = mpc512x_psc_spi_port_config(master, mps); if (ret < 0) - goto free_irq; + goto free_clock; ret = spi_register_master(master); if (ret < 0) - goto free_irq; + goto free_clock; return ret; +free_clock: + clk_disable_unprepare(mps->clk_mclk); free_irq: free_irq(mps->irq, mps); free_master: @@ -547,6 +558,7 @@ static int mpc512x_psc_spi_do_remove(struct device *dev) struct mpc512x_psc_spi *mps = spi_master_get_devdata(master); spi_unregister_master(master); + clk_disable_unprepare(mps->clk_mclk); free_irq(mps->irq, mps); if (mps->psc) iounmap(mps->psc); diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index fed0571d4dec..6e925dc34396 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -366,7 +366,7 @@ static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id) static int mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, u32 size, unsigned int irq, s16 bus_num) { - struct fsl_spi_platform_data *pdata = dev->platform_data; + struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc52xx_psc_spi *mps; struct spi_master *master; int ret; diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 424d38e59421..de7b1141b90f 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -67,13 +67,8 @@ static int mxs_spi_setup_transfer(struct spi_device *dev, { struct mxs_spi *spi = spi_master_get_devdata(dev->master); struct mxs_ssp *ssp = &spi->ssp; - uint8_t bits_per_word; uint32_t hz = 0; - bits_per_word = dev->bits_per_word; - if (t && t->bits_per_word) - bits_per_word = t->bits_per_word; - hz = dev->max_speed_hz; if (t && t->speed_hz) hz = min(hz, t->speed_hz); @@ -513,7 +508,7 @@ static int mxs_spi_probe(struct platform_device *pdev) iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq_err = platform_get_irq(pdev, 0); - if (!iores || irq_err < 0) + if (irq_err < 0) return -EINVAL; base = devm_ioremap_resource(&pdev->dev, iores); @@ -563,25 +558,31 @@ static int mxs_spi_probe(struct platform_device *pdev) goto out_master_free; } - clk_prepare_enable(ssp->clk); + ret = clk_prepare_enable(ssp->clk); + if (ret) + goto out_dma_release; + clk_set_rate(ssp->clk, clk_freq); ssp->clk_rate = clk_get_rate(ssp->clk) / 1000; - stmp_reset_block(ssp->base); + ret = stmp_reset_block(ssp->base); + if (ret) + goto out_disable_clk; platform_set_drvdata(pdev, master); ret = spi_register_master(master); if (ret) { dev_err(&pdev->dev, "Cannot register SPI master, %d\n", ret); - goto out_free_dma; + goto out_disable_clk; } return 0; -out_free_dma: - dma_release_channel(ssp->dmach); +out_disable_clk: clk_disable_unprepare(ssp->clk); +out_dma_release: + dma_release_channel(ssp->dmach); out_master_free: spi_master_put(master); return ret; @@ -598,11 +599,8 @@ static int mxs_spi_remove(struct platform_device *pdev) ssp = &spi->ssp; spi_unregister_master(master); - - dma_release_channel(ssp->dmach); - clk_disable_unprepare(ssp->clk); - + dma_release_channel(ssp->dmach); spi_master_put(master); return 0; diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index 150d85453c27..47a68b43bcd5 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -174,17 +174,6 @@ static void nuc900_spi_gobusy(struct nuc900_spi *hw) spin_unlock_irqrestore(&hw->lock, flags); } -static int nuc900_spi_setupxfer(struct spi_device *spi, - struct spi_transfer *t) -{ - return 0; -} - -static int nuc900_spi_setup(struct spi_device *spi) -{ - return 0; -} - static inline unsigned int hw_txbyte(struct nuc900_spi *hw, int count) { return hw->tx ? hw->tx[count] : 0; @@ -361,7 +350,7 @@ static int nuc900_spi_probe(struct platform_device *pdev) hw = spi_master_get_devdata(master); hw->master = spi_master_get(master); - hw->pdata = pdev->dev.platform_data; + hw->pdata = dev_get_platdata(&pdev->dev); hw->dev = &pdev->dev; if (hw->pdata == NULL) { @@ -373,14 +362,12 @@ static int nuc900_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hw); init_completion(&hw->done); - master->mode_bits = SPI_MODE_0; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->num_chipselect = hw->pdata->num_cs; master->bus_num = hw->pdata->bus_num; hw->bitbang.master = hw->master; - hw->bitbang.setup_transfer = nuc900_spi_setupxfer; hw->bitbang.chipselect = nuc900_spi_chipsel; hw->bitbang.txrx_bufs = nuc900_spi_txrx; - hw->bitbang.master->setup = nuc900_spi_setup; hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (hw->res == NULL) { diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index 58deb79d046b..333cb1badcd7 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -285,7 +285,7 @@ static int tiny_spi_of_probe(struct platform_device *pdev) static int tiny_spi_probe(struct platform_device *pdev) { - struct tiny_spi_platform_data *platp = pdev->dev.platform_data; + struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev); struct tiny_spi *hw; struct spi_master *master; struct resource *res; @@ -315,15 +315,11 @@ static int tiny_spi_probe(struct platform_device *pdev) /* find and map our resources */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - goto exit_busy; - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - pdev->name)) - goto exit_busy; - hw->base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!hw->base) - goto exit_busy; + hw->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->base)) { + err = PTR_ERR(hw->base); + goto exit; + } /* irq is optional */ hw->irq = platform_get_irq(pdev, 0); if (hw->irq >= 0) { @@ -337,8 +333,10 @@ static int tiny_spi_probe(struct platform_device *pdev) if (platp) { hw->gpio_cs_count = platp->gpio_cs_count; hw->gpio_cs = platp->gpio_cs; - if (platp->gpio_cs_count && !platp->gpio_cs) - goto exit_busy; + if (platp->gpio_cs_count && !platp->gpio_cs) { + err = -EBUSY; + goto exit; + } hw->freq = platp->freq; hw->baudwidth = platp->baudwidth; } else { @@ -365,8 +363,6 @@ static int tiny_spi_probe(struct platform_device *pdev) exit_gpio: while (i-- > 0) gpio_free(hw->gpio_cs[i]); -exit_busy: - err = -EBUSY; exit: spi_master_put(master); return err; diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index 24daf964a409..5f28ddbe4f7e 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -28,7 +28,6 @@ #define OCTEON_SPI_MAX_CLOCK_HZ 16000000 struct octeon_spi { - struct spi_master *my_master; u64 register_base; u64 last_cfg; u64 cs_enax; @@ -64,7 +63,6 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, unsigned int speed_hz; int mode; bool cpha, cpol; - int bits_per_word; const u8 *tx_buf; u8 *rx_buf; int len; @@ -76,12 +74,9 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, mode = msg_setup->mode; cpha = mode & SPI_CPHA; cpol = mode & SPI_CPOL; - bits_per_word = msg_setup->bits_per_word; if (xfer->speed_hz) speed_hz = xfer->speed_hz; - if (xfer->bits_per_word) - bits_per_word = xfer->bits_per_word; if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ) speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; @@ -166,19 +161,6 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, return xfer->len; } -static int octeon_spi_validate_bpw(struct spi_device *spi, u32 speed) -{ - switch (speed) { - case 8: - break; - default: - dev_err(&spi->dev, "Error: %d bits per word not supported\n", - speed); - return -EINVAL; - } - return 0; -} - static int octeon_spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { @@ -197,15 +179,6 @@ static int octeon_spi_transfer_one_message(struct spi_master *master, } list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if (xfer->bits_per_word) { - status = octeon_spi_validate_bpw(msg->spi, - xfer->bits_per_word); - if (status) - goto err; - } - } - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { bool last_xfer = &xfer->transfer_list == msg->transfers.prev; int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer); if (r < 0) { @@ -236,14 +209,9 @@ static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi) static int octeon_spi_setup(struct spi_device *spi) { - int r; struct octeon_spi_setup *new_setup; struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); - r = octeon_spi_validate_bpw(spi, spi->bits_per_word); - if (r) - return r; - new_setup = octeon_spi_new_setup(spi); if (!new_setup) return -ENOMEM; @@ -261,14 +229,8 @@ static void octeon_spi_cleanup(struct spi_device *spi) kfree(old_setup); } -static int octeon_spi_nop_transfer_hardware(struct spi_master *master) -{ - return 0; -} - static int octeon_spi_probe(struct platform_device *pdev) { - struct resource *res_mem; struct spi_master *master; struct octeon_spi *p; @@ -278,8 +240,7 @@ static int octeon_spi_probe(struct platform_device *pdev) if (!master) return -ENOMEM; p = spi_master_get_devdata(master); - platform_set_drvdata(pdev, p); - p->my_master = master; + platform_set_drvdata(pdev, master); res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -307,9 +268,8 @@ static int octeon_spi_probe(struct platform_device *pdev) master->setup = octeon_spi_setup; master->cleanup = octeon_spi_cleanup; - master->prepare_transfer_hardware = octeon_spi_nop_transfer_hardware; master->transfer_one_message = octeon_spi_transfer_one_message; - master->unprepare_transfer_hardware = octeon_spi_nop_transfer_hardware; + master->bits_per_word_mask = SPI_BPW_MASK(8); master->dev.of_node = pdev->dev.of_node; err = spi_register_master(master); @@ -328,10 +288,11 @@ fail: static int octeon_spi_remove(struct platform_device *pdev) { - struct octeon_spi *p = platform_get_drvdata(pdev); + struct spi_master *master = platform_get_drvdata(pdev); + struct octeon_spi *p = spi_master_get_devdata(master); u64 register_base = p->register_base; - spi_unregister_master(p->my_master); + spi_unregister_master(master); /* Clear the CSENA* and put everything in a known state. */ cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0); diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index ee25670f8cfd..69ecf05757dd 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -83,11 +83,6 @@ #define SPI_SHUTDOWN 1 struct omap1_spi100k { - struct work_struct work; - - /* lock protects queue and registers */ - spinlock_t lock; - struct list_head msg_queue; struct spi_master *master; struct clk *ick; struct clk *fck; @@ -104,8 +99,6 @@ struct omap1_spi100k_cs { int word_len; }; -static struct workqueue_struct *omap1_spi100k_wq; - #define MOD_REG_BIT(val, mask, set) do { \ if (set) \ val |= mask; \ @@ -310,170 +303,102 @@ static int omap1_spi100k_setup(struct spi_device *spi) spi100k_open(spi->master); - clk_enable(spi100k->ick); - clk_enable(spi100k->fck); + clk_prepare_enable(spi100k->ick); + clk_prepare_enable(spi100k->fck); ret = omap1_spi100k_setup_transfer(spi, NULL); - clk_disable(spi100k->ick); - clk_disable(spi100k->fck); + clk_disable_unprepare(spi100k->ick); + clk_disable_unprepare(spi100k->fck); return ret; } -static void omap1_spi100k_work(struct work_struct *work) +static int omap1_spi100k_prepare_hardware(struct spi_master *master) { - struct omap1_spi100k *spi100k; - int status = 0; + struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - spi100k = container_of(work, struct omap1_spi100k, work); - spin_lock_irq(&spi100k->lock); + clk_prepare_enable(spi100k->ick); + clk_prepare_enable(spi100k->fck); - clk_enable(spi100k->ick); - clk_enable(spi100k->fck); + return 0; +} - /* We only enable one channel at a time -- the one whose message is - * at the head of the queue -- although this controller would gladly - * arbitrate among multiple channels. This corresponds to "single - * channel" master mode. As a side effect, we need to manage the - * chipselect with the FORCE bit ... CS != channel enable. - */ - while (!list_empty(&spi100k->msg_queue)) { - struct spi_message *m; - struct spi_device *spi; - struct spi_transfer *t = NULL; - int cs_active = 0; - struct omap1_spi100k_cs *cs; - int par_override = 0; - - m = container_of(spi100k->msg_queue.next, struct spi_message, - queue); - - list_del_init(&m->queue); - spin_unlock_irq(&spi100k->lock); - - spi = m->spi; - cs = spi->controller_state; - - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { - status = -EINVAL; +static int omap1_spi100k_transfer_one_message(struct spi_master *master, + struct spi_message *m) +{ + struct omap1_spi100k *spi100k = spi_master_get_devdata(master); + struct spi_device *spi = m->spi; + struct spi_transfer *t = NULL; + int cs_active = 0; + int par_override = 0; + int status = 0; + + list_for_each_entry(t, &m->transfers, transfer_list) { + if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { + status = -EINVAL; + break; + } + if (par_override || t->speed_hz || t->bits_per_word) { + par_override = 1; + status = omap1_spi100k_setup_transfer(spi, t); + if (status < 0) break; - } - if (par_override || t->speed_hz || t->bits_per_word) { - par_override = 1; - status = omap1_spi100k_setup_transfer(spi, t); - if (status < 0) - break; - if (!t->speed_hz && !t->bits_per_word) - par_override = 0; - } + if (!t->speed_hz && !t->bits_per_word) + par_override = 0; + } - if (!cs_active) { - omap1_spi100k_force_cs(spi100k, 1); - cs_active = 1; - } + if (!cs_active) { + omap1_spi100k_force_cs(spi100k, 1); + cs_active = 1; + } - if (t->len) { - unsigned count; + if (t->len) { + unsigned count; - count = omap1_spi100k_txrx_pio(spi, t); - m->actual_length += count; + count = omap1_spi100k_txrx_pio(spi, t); + m->actual_length += count; - if (count != t->len) { - status = -EIO; - break; - } + if (count != t->len) { + status = -EIO; + break; } + } - if (t->delay_usecs) - udelay(t->delay_usecs); + if (t->delay_usecs) + udelay(t->delay_usecs); - /* ignore the "leave it on after last xfer" hint */ + /* ignore the "leave it on after last xfer" hint */ - if (t->cs_change) { - omap1_spi100k_force_cs(spi100k, 0); - cs_active = 0; - } - } - - /* Restore defaults if they were overriden */ - if (par_override) { - par_override = 0; - status = omap1_spi100k_setup_transfer(spi, NULL); + if (t->cs_change) { + omap1_spi100k_force_cs(spi100k, 0); + cs_active = 0; } + } - if (cs_active) - omap1_spi100k_force_cs(spi100k, 0); + /* Restore defaults if they were overriden */ + if (par_override) { + par_override = 0; + status = omap1_spi100k_setup_transfer(spi, NULL); + } - m->status = status; - m->complete(m->context); + if (cs_active) + omap1_spi100k_force_cs(spi100k, 0); - spin_lock_irq(&spi100k->lock); - } + m->status = status; - clk_disable(spi100k->ick); - clk_disable(spi100k->fck); - spin_unlock_irq(&spi100k->lock); + spi_finalize_current_message(master); - if (status < 0) - printk(KERN_WARNING "spi transfer failed with %d\n", status); + return status; } -static int omap1_spi100k_transfer(struct spi_device *spi, struct spi_message *m) +static int omap1_spi100k_unprepare_hardware(struct spi_master *master) { - struct omap1_spi100k *spi100k; - unsigned long flags; - struct spi_transfer *t; - - m->actual_length = 0; - m->status = -EINPROGRESS; - - spi100k = spi_master_get_devdata(spi->master); - - /* Don't accept new work if we're shutting down */ - if (spi100k->state == SPI_SHUTDOWN) - return -ESHUTDOWN; - - /* reject invalid messages and transfers */ - if (list_empty(&m->transfers) || !m->complete) - return -EINVAL; - - list_for_each_entry(t, &m->transfers, transfer_list) { - const void *tx_buf = t->tx_buf; - void *rx_buf = t->rx_buf; - unsigned len = t->len; - - if (t->speed_hz > OMAP1_SPI100K_MAX_FREQ - || (len && !(rx_buf || tx_buf))) { - dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", - t->speed_hz, - len, - tx_buf ? "tx" : "", - rx_buf ? "rx" : "", - t->bits_per_word); - return -EINVAL; - } - - if (t->speed_hz && t->speed_hz < OMAP1_SPI100K_MAX_FREQ/(1<<16)) { - dev_dbg(&spi->dev, "%d Hz max exceeds %d\n", - t->speed_hz, - OMAP1_SPI100K_MAX_FREQ/(1<<16)); - return -EINVAL; - } - - } - - spin_lock_irqsave(&spi100k->lock, flags); - list_add_tail(&m->queue, &spi100k->msg_queue); - queue_work(omap1_spi100k_wq, &spi100k->work); - spin_unlock_irqrestore(&spi100k->lock, flags); + struct omap1_spi100k *spi100k = spi_master_get_devdata(master); - return 0; -} + clk_disable_unprepare(spi100k->ick); + clk_disable_unprepare(spi100k->fck); -static int omap1_spi100k_reset(struct omap1_spi100k *spi100k) -{ return 0; } @@ -496,11 +421,15 @@ static int omap1_spi100k_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->setup = omap1_spi100k_setup; - master->transfer = omap1_spi100k_transfer; + master->transfer_one_message = omap1_spi100k_transfer_one_message; + master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware; + master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware; master->cleanup = NULL; master->num_chipselect = 2; master->mode_bits = MODEBITS; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16); + master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ; platform_set_drvdata(pdev, master); @@ -512,42 +441,31 @@ static int omap1_spi100k_probe(struct platform_device *pdev) * You should allocate this with ioremap() before initializing * the SPI. */ - spi100k->base = (void __iomem *) pdev->dev.platform_data; - - INIT_WORK(&spi100k->work, omap1_spi100k_work); + spi100k->base = (void __iomem *)dev_get_platdata(&pdev->dev); - spin_lock_init(&spi100k->lock); - INIT_LIST_HEAD(&spi100k->msg_queue); - spi100k->ick = clk_get(&pdev->dev, "ick"); + spi100k->ick = devm_clk_get(&pdev->dev, "ick"); if (IS_ERR(spi100k->ick)) { dev_dbg(&pdev->dev, "can't get spi100k_ick\n"); status = PTR_ERR(spi100k->ick); - goto err1; + goto err; } - spi100k->fck = clk_get(&pdev->dev, "fck"); + spi100k->fck = devm_clk_get(&pdev->dev, "fck"); if (IS_ERR(spi100k->fck)) { dev_dbg(&pdev->dev, "can't get spi100k_fck\n"); status = PTR_ERR(spi100k->fck); - goto err2; + goto err; } - if (omap1_spi100k_reset(spi100k) < 0) - goto err3; - status = spi_register_master(master); if (status < 0) - goto err3; + goto err; spi100k->state = SPI_RUNNING; return status; -err3: - clk_put(spi100k->fck); -err2: - clk_put(spi100k->ick); -err1: +err: spi_master_put(master); return status; } @@ -557,33 +475,14 @@ static int omap1_spi100k_remove(struct platform_device *pdev) struct spi_master *master; struct omap1_spi100k *spi100k; struct resource *r; - unsigned limit = 500; - unsigned long flags; int status = 0; master = platform_get_drvdata(pdev); spi100k = spi_master_get_devdata(master); - spin_lock_irqsave(&spi100k->lock, flags); - - spi100k->state = SPI_SHUTDOWN; - while (!list_empty(&spi100k->msg_queue) && limit--) { - spin_unlock_irqrestore(&spi100k->lock, flags); - msleep(10); - spin_lock_irqsave(&spi100k->lock, flags); - } - - if (!list_empty(&spi100k->msg_queue)) - status = -EBUSY; - - spin_unlock_irqrestore(&spi100k->lock, flags); - if (status != 0) return status; - clk_put(spi100k->fck); - clk_put(spi100k->ick); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); spi_unregister_master(master); @@ -596,30 +495,11 @@ static struct platform_driver omap1_spi100k_driver = { .name = "omap1_spi100k", .owner = THIS_MODULE, }, + .probe = omap1_spi100k_probe, .remove = omap1_spi100k_remove, }; - -static int __init omap1_spi100k_init(void) -{ - omap1_spi100k_wq = create_singlethread_workqueue( - omap1_spi100k_driver.driver.name); - - if (omap1_spi100k_wq == NULL) - return -1; - - return platform_driver_probe(&omap1_spi100k_driver, omap1_spi100k_probe); -} - -static void __exit omap1_spi100k_exit(void) -{ - platform_driver_unregister(&omap1_spi100k_driver); - - destroy_workqueue(omap1_spi100k_wq); -} - -module_init(omap1_spi100k_init); -module_exit(omap1_spi100k_exit); +module_platform_driver(omap1_spi100k_driver); MODULE_DESCRIPTION("OMAP7xx SPI 100k controller driver"); MODULE_AUTHOR("Fabrice Crohas <fcrohas@gmail.com>"); diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 5994039758de..ed4af4708d9a 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -335,23 +335,6 @@ static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); } -static int omap2_prepare_transfer(struct spi_master *master) -{ - struct omap2_mcspi *mcspi = spi_master_get_devdata(master); - - pm_runtime_get_sync(mcspi->dev); - return 0; -} - -static int omap2_unprepare_transfer(struct spi_master *master) -{ - struct omap2_mcspi *mcspi = spi_master_get_devdata(master); - - pm_runtime_mark_last_busy(mcspi->dev); - pm_runtime_put_autosuspend(mcspi->dev); - return 0; -} - static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) { unsigned long timeout; @@ -1318,8 +1301,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->setup = omap2_mcspi_setup; - master->prepare_transfer_hardware = omap2_prepare_transfer; - master->unprepare_transfer_hardware = omap2_unprepare_transfer; + master->auto_runtime_pm = true; master->transfer_one_message = omap2_mcspi_transfer_one_message; master->cleanup = omap2_mcspi_cleanup; master->dev.of_node = node; @@ -1340,7 +1322,7 @@ static int omap2_mcspi_probe(struct platform_device *pdev) if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL)) mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; } else { - pdata = pdev->dev.platform_data; + pdata = dev_get_platdata(&pdev->dev); master->num_chipselect = pdata->num_cs; if (pdev->id != -1) master->bus_num = pdev->id; diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 5d90bebaa0fa..1d1d321d90c4 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/clk.h> +#include <linux/sizes.h> #include <asm/unaligned.h> #define DRIVER_NAME "orion_spi" @@ -446,30 +447,22 @@ static int orion_spi_probe(struct platform_device *pdev) spi->min_speed = DIV_ROUND_UP(tclk_hz, 30); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) { - status = -ENODEV; + spi->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(spi->base)) { + status = PTR_ERR(spi->base); goto out_rel_clk; } - if (!request_mem_region(r->start, resource_size(r), - dev_name(&pdev->dev))) { - status = -EBUSY; - goto out_rel_clk; - } - spi->base = ioremap(r->start, SZ_1K); - if (orion_spi_reset(spi) < 0) - goto out_rel_mem; + goto out_rel_clk; master->dev.of_node = pdev->dev.of_node; status = spi_register_master(master); if (status < 0) - goto out_rel_mem; + goto out_rel_clk; return status; -out_rel_mem: - release_mem_region(r->start, resource_size(r)); out_rel_clk: clk_disable_unprepare(spi->clk); clk_put(spi->clk); @@ -482,7 +475,6 @@ out: static int orion_spi_remove(struct platform_device *pdev) { struct spi_master *master; - struct resource *r; struct orion_spi *spi; master = platform_get_drvdata(pdev); @@ -491,9 +483,6 @@ static int orion_spi_remove(struct platform_device *pdev) clk_disable_unprepare(spi->clk); clk_put(spi->clk); - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); - spi_unregister_master(master); return 0; diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index abef061fb84a..9c511a954d21 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -1555,18 +1555,6 @@ static int pl022_transfer_one_message(struct spi_master *master, return 0; } -static int pl022_prepare_transfer_hardware(struct spi_master *master) -{ - struct pl022 *pl022 = spi_master_get_devdata(master); - - /* - * Just make sure we have all we need to run the transfer by syncing - * with the runtime PM framework. - */ - pm_runtime_get_sync(&pl022->adev->dev); - return 0; -} - static int pl022_unprepare_transfer_hardware(struct spi_master *master) { struct pl022 *pl022 = spi_master_get_devdata(master); @@ -1575,13 +1563,6 @@ static int pl022_unprepare_transfer_hardware(struct spi_master *master) writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); - if (pl022->master_info->autosuspend_delay > 0) { - pm_runtime_mark_last_busy(&pl022->adev->dev); - pm_runtime_put_autosuspend(&pl022->adev->dev); - } else { - pm_runtime_put(&pl022->adev->dev); - } - return 0; } @@ -2091,7 +2072,8 @@ pl022_platform_data_dt_get(struct device *dev) static int pl022_probe(struct amba_device *adev, const struct amba_id *id) { struct device *dev = &adev->dev; - struct pl022_ssp_controller *platform_info = adev->dev.platform_data; + struct pl022_ssp_controller *platform_info = + dev_get_platdata(&adev->dev); struct spi_master *master; struct pl022 *pl022 = NULL; /*Data for this driver */ struct device_node *np = adev->dev.of_node; @@ -2139,7 +2121,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) master->num_chipselect = num_cs; master->cleanup = pl022_cleanup; master->setup = pl022_setup; - master->prepare_transfer_hardware = pl022_prepare_transfer_hardware; + master->auto_runtime_pm = true; master->transfer_one_message = pl022_transfer_one_message; master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; master->rt = platform_info->rt; @@ -2193,8 +2175,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) status = -ENOMEM; goto err_no_ioremap; } - printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n", - adev->res.start, pl022->virtbase); + printk(KERN_INFO "pl022: mapped registers from %pa to %p\n", + &adev->res.start, pl022->virtbase); pl022->clk = devm_clk_get(&adev->dev, NULL); if (IS_ERR(pl022->clk)) { diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index f440dcee852b..2eb06ee0b326 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -69,6 +69,8 @@ MODULE_ALIAS("platform:pxa2xx-spi"); #define LPSS_TX_HITHRESH_DFLT 224 /* Offset from drv_data->lpss_base */ +#define GENERAL_REG 0x08 +#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24) #define SSP_REG 0x0c #define SPI_CS_CONTROL 0x18 #define SPI_CS_CONTROL_SW_MODE BIT(0) @@ -142,8 +144,13 @@ detection_done: __lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value); /* Enable multiblock DMA transfers */ - if (drv_data->master_info->enable_dma) + if (drv_data->master_info->enable_dma) { __lpss_ssp_write_priv(drv_data, SSP_REG, 1); + + value = __lpss_ssp_read_priv(drv_data, GENERAL_REG); + value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE; + __lpss_ssp_write_priv(drv_data, GENERAL_REG, value); + } } static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable) @@ -804,14 +811,6 @@ static int pxa2xx_spi_transfer_one_message(struct spi_master *master, return 0; } -static int pxa2xx_spi_prepare_transfer(struct spi_master *master) -{ - struct driver_data *drv_data = spi_master_get_devdata(master); - - pm_runtime_get_sync(&drv_data->pdev->dev); - return 0; -} - static int pxa2xx_spi_unprepare_transfer(struct spi_master *master) { struct driver_data *drv_data = spi_master_get_devdata(master); @@ -820,8 +819,6 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master) write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE, drv_data->ioaddr); - pm_runtime_mark_last_busy(&drv_data->pdev->dev); - pm_runtime_put_autosuspend(&drv_data->pdev->dev); return 0; } @@ -1134,8 +1131,8 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) master->cleanup = cleanup; master->setup = setup; master->transfer_one_message = pxa2xx_spi_transfer_one_message; - master->prepare_transfer_hardware = pxa2xx_spi_prepare_transfer; master->unprepare_transfer_hardware = pxa2xx_spi_unprepare_transfer; + master->auto_runtime_pm = true; drv_data->ssp_type = ssp->type; drv_data->null_dma_buf = (u32 *)PTR_ALIGN(&drv_data[1], DMA_ALIGNMENT); diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index b44a6ac3cec9..8719206a03a0 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -564,8 +564,12 @@ static void rspi_work(struct work_struct *work) unsigned long flags; int ret; - spin_lock_irqsave(&rspi->lock, flags); - while (!list_empty(&rspi->queue)) { + while (1) { + spin_lock_irqsave(&rspi->lock, flags); + if (list_empty(&rspi->queue)) { + spin_unlock_irqrestore(&rspi->lock, flags); + break; + } mesg = list_entry(rspi->queue.next, struct spi_message, queue); list_del_init(&mesg->queue); spin_unlock_irqrestore(&rspi->lock, flags); @@ -595,8 +599,6 @@ static void rspi_work(struct work_struct *work) mesg->status = 0; mesg->complete(mesg->context); - - spin_lock_irqsave(&rspi->lock, flags); } return; @@ -664,12 +666,13 @@ static irqreturn_t rspi_irq(int irq, void *_sr) static int rspi_request_dma(struct rspi_data *rspi, struct platform_device *pdev) { - struct rspi_plat_data *rspi_pd = pdev->dev.platform_data; + struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); dma_cap_mask_t mask; struct dma_slave_config cfg; int ret; - if (!rspi_pd) + if (!res || !rspi_pd) return 0; /* The driver assumes no error. */ rspi->dma_width_16bit = rspi_pd->dma_width_16bit; @@ -683,6 +686,8 @@ static int rspi_request_dma(struct rspi_data *rspi, if (rspi->chan_rx) { cfg.slave_id = rspi_pd->dma_rx_id; cfg.direction = DMA_DEV_TO_MEM; + cfg.dst_addr = 0; + cfg.src_addr = res->start + RSPI_SPDR; ret = dmaengine_slave_config(rspi->chan_rx, &cfg); if (!ret) dev_info(&pdev->dev, "Use DMA when rx.\n"); @@ -698,6 +703,8 @@ static int rspi_request_dma(struct rspi_data *rspi, if (rspi->chan_tx) { cfg.slave_id = rspi_pd->dma_tx_id; cfg.direction = DMA_MEM_TO_DEV; + cfg.dst_addr = res->start + RSPI_SPDR; + cfg.src_addr = 0; ret = dmaengine_slave_config(rspi->chan_tx, &cfg); if (!ret) dev_info(&pdev->dev, "Use DMA when tx\n"); @@ -719,7 +726,7 @@ static void rspi_release_dma(struct rspi_data *rspi) static int rspi_remove(struct platform_device *pdev) { - struct rspi_data *rspi = platform_get_drvdata(pdev); + struct rspi_data *rspi = spi_master_get(platform_get_drvdata(pdev)); spi_unregister_master(rspi->master); rspi_release_dma(rspi); diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 68910b310152..ce318d95a6ee 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -525,7 +525,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) memset(hw, 0, sizeof(struct s3c24xx_spi)); hw->master = spi_master_get(master); - hw->pdata = pdata = pdev->dev.platform_data; + hw->pdata = pdata = dev_get_platdata(&pdev->dev); hw->dev = &pdev->dev; if (pdata == NULL) { @@ -690,7 +690,7 @@ static int s3c24xx_spi_remove(struct platform_device *dev) static int s3c24xx_spi_suspend(struct device *dev) { - struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev)); + struct s3c24xx_spi *hw = dev_get_drvdata(dev); if (hw->pdata && hw->pdata->gpio_setup) hw->pdata->gpio_setup(hw->pdata, 0); @@ -701,7 +701,7 @@ static int s3c24xx_spi_suspend(struct device *dev) static int s3c24xx_spi_resume(struct device *dev) { - struct s3c24xx_spi *hw = platform_get_drvdata(to_platform_device(dev)); + struct s3c24xx_spi *hw = dev_get_drvdata(dev); s3c24xx_spi_initialsetup(hw); return 0; diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index eee1a7b4adc4..512b8893893b 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -356,8 +356,6 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) while (!is_polling(sdd) && !acquire_dma(sdd)) usleep_range(10000, 11000); - pm_runtime_get_sync(&sdd->pdev->dev); - return 0; } @@ -372,7 +370,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, &s3c64xx_spi_dma_client); } - pm_runtime_put(&sdd->pdev->dev); return 0; } @@ -1252,7 +1249,7 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) #else static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) { - return dev->platform_data; + return dev_get_platdata(dev); } #endif @@ -1277,7 +1274,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) struct resource *mem_res; struct resource *res; struct s3c64xx_spi_driver_data *sdd; - struct s3c64xx_spi_info *sci = pdev->dev.platform_data; + struct s3c64xx_spi_info *sci = dev_get_platdata(&pdev->dev); struct spi_master *master; int ret, irq; char clk_name[16]; @@ -1370,6 +1367,7 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) SPI_BPW_MASK(8); /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->auto_runtime_pm = true; sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res); if (IS_ERR(sdd->regs)) { diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 716edf999538..b95d6a9fb80e 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -99,21 +99,6 @@ static int hspi_status_check_timeout(struct hspi_priv *hspi, u32 mask, u32 val) /* * spi master function */ -static int hspi_prepare_transfer(struct spi_master *master) -{ - struct hspi_priv *hspi = spi_master_get_devdata(master); - - pm_runtime_get_sync(hspi->dev); - return 0; -} - -static int hspi_unprepare_transfer(struct spi_master *master) -{ - struct hspi_priv *hspi = spi_master_get_devdata(master); - - pm_runtime_put_sync(hspi->dev); - return 0; -} #define hspi_hw_cs_enable(hspi) hspi_hw_cs_ctrl(hspi, 0) #define hspi_hw_cs_disable(hspi) hspi_hw_cs_ctrl(hspi, 1) @@ -316,9 +301,8 @@ static int hspi_probe(struct platform_device *pdev) master->setup = hspi_setup; master->cleanup = hspi_cleanup; master->mode_bits = SPI_CPOL | SPI_CPHA; - master->prepare_transfer_hardware = hspi_prepare_transfer; + master->auto_runtime_pm = true; master->transfer_one_message = hspi_transfer_one_message; - master->unprepare_transfer_hardware = hspi_unprepare_transfer; ret = spi_register_master(master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 2bc5a6b86300..cbc7f2216c16 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -645,7 +645,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) if (pdev->dev.of_node) p->info = sh_msiof_spi_parse_dt(&pdev->dev); else - p->info = pdev->dev.platform_data; + p->info = dev_get_platdata(&pdev->dev); if (!p->info) { dev_err(&pdev->dev, "failed to obtain device info\n"); diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 097e506042be..8eefeb6007df 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -130,7 +130,7 @@ static int sh_sci_spi_probe(struct platform_device *dev) sp = spi_master_get_devdata(master); platform_set_drvdata(dev, sp); - sp->info = dev->dev.platform_data; + sp->info = dev_get_platdata(&dev->dev); /* setup spi bitbang adaptor */ sp->bitbang.master = spi_master_get(master); diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index fc20bcfd90c3..fc5081ab3677 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -599,8 +599,7 @@ static int spi_sirfsoc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int spi_sirfsoc_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); struct sirfsoc_spi *sspi = spi_master_get_devdata(master); clk_disable(sspi->clk); @@ -609,8 +608,7 @@ static int spi_sirfsoc_suspend(struct device *dev) static int spi_sirfsoc_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct spi_master *master = platform_get_drvdata(pdev); + struct spi_master *master = dev_get_drvdata(dev); struct sirfsoc_spi *sspi = spi_master_get_devdata(master); clk_enable(sspi->clk); diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index e8f542ab8935..c14e30c8af2e 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -816,14 +816,6 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, msg->status = 0; msg->actual_length = 0; - ret = pm_runtime_get_sync(tspi->dev); - if (ret < 0) { - dev_err(tspi->dev, "runtime PM get failed: %d\n", ret); - msg->status = ret; - spi_finalize_current_message(master); - return ret; - } - single_xfer = list_is_singular(&msg->transfers); list_for_each_entry(xfer, &msg->transfers, transfer_list) { INIT_COMPLETION(tspi->xfer_completion); @@ -859,7 +851,6 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, ret = 0; exit: tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); - pm_runtime_put(tspi->dev); msg->status = ret; spi_finalize_current_message(master); return ret; @@ -1053,6 +1044,7 @@ static int tegra_spi_probe(struct platform_device *pdev) master->transfer_one_message = tegra_spi_transfer_one_message; master->num_chipselect = MAX_CHIP_SELECT; master->bus_num = -1; + master->auto_runtime_pm = true; tspi->master = master; tspi->dev = &pdev->dev; diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index c1d5d95e70ea..1d814dc6e000 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -335,12 +335,6 @@ static int tegra_sflash_transfer_one_message(struct spi_master *master, struct spi_device *spi = msg->spi; int ret; - ret = pm_runtime_get_sync(tsd->dev); - if (ret < 0) { - dev_err(tsd->dev, "pm_runtime_get() failed, err = %d\n", ret); - return ret; - } - msg->status = 0; msg->actual_length = 0; single_xfer = list_is_singular(&msg->transfers); @@ -380,7 +374,6 @@ exit: tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND); msg->status = ret; spi_finalize_current_message(master); - pm_runtime_put(tsd->dev); return ret; } @@ -477,6 +470,7 @@ static int tegra_sflash_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA; master->setup = tegra_sflash_setup; master->transfer_one_message = tegra_sflash_transfer_one_message; + master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; master->bus_num = -1; diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 80490cc11ce5..c70353672a23 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -836,11 +836,6 @@ static int tegra_slink_transfer_one_message(struct spi_master *master, msg->status = 0; msg->actual_length = 0; - ret = pm_runtime_get_sync(tspi->dev); - if (ret < 0) { - dev_err(tspi->dev, "runtime get failed: %d\n", ret); - goto done; - } single_xfer = list_is_singular(&msg->transfers); list_for_each_entry(xfer, &msg->transfers, transfer_list) { @@ -878,8 +873,6 @@ static int tegra_slink_transfer_one_message(struct spi_master *master, exit: tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND); tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2); - pm_runtime_put(tspi->dev); -done: msg->status = ret; spi_finalize_current_message(master); return ret; @@ -1086,6 +1079,7 @@ static int tegra_slink_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->setup = tegra_slink_setup; master->transfer_one_message = tegra_slink_transfer_one_message; + master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; master->bus_num = -1; diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c new file mode 100644 index 000000000000..e12d962a289f --- /dev/null +++ b/drivers/spi/spi-ti-qspi.c @@ -0,0 +1,574 @@ +/* + * TI QSPI driver + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * Author: Sourav Poddar <sourav.poddar@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GPLv2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/omap-dma.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> + +#include <linux/spi/spi.h> + +struct ti_qspi_regs { + u32 clkctrl; +}; + +struct ti_qspi { + struct completion transfer_complete; + + /* IRQ synchronization */ + spinlock_t lock; + + /* list synchronization */ + struct mutex list_lock; + + struct spi_master *master; + void __iomem *base; + struct clk *fclk; + struct device *dev; + + struct ti_qspi_regs ctx_reg; + + u32 spi_max_frequency; + u32 cmd; + u32 dc; + u32 stat; +}; + +#define QSPI_PID (0x0) +#define QSPI_SYSCONFIG (0x10) +#define QSPI_INTR_STATUS_RAW_SET (0x20) +#define QSPI_INTR_STATUS_ENABLED_CLEAR (0x24) +#define QSPI_INTR_ENABLE_SET_REG (0x28) +#define QSPI_INTR_ENABLE_CLEAR_REG (0x2c) +#define QSPI_SPI_CLOCK_CNTRL_REG (0x40) +#define QSPI_SPI_DC_REG (0x44) +#define QSPI_SPI_CMD_REG (0x48) +#define QSPI_SPI_STATUS_REG (0x4c) +#define QSPI_SPI_DATA_REG (0x50) +#define QSPI_SPI_SETUP0_REG (0x54) +#define QSPI_SPI_SWITCH_REG (0x64) +#define QSPI_SPI_SETUP1_REG (0x58) +#define QSPI_SPI_SETUP2_REG (0x5c) +#define QSPI_SPI_SETUP3_REG (0x60) +#define QSPI_SPI_DATA_REG_1 (0x68) +#define QSPI_SPI_DATA_REG_2 (0x6c) +#define QSPI_SPI_DATA_REG_3 (0x70) + +#define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000) + +#define QSPI_FCLK 192000000 + +/* Clock Control */ +#define QSPI_CLK_EN (1 << 31) +#define QSPI_CLK_DIV_MAX 0xffff + +/* Command */ +#define QSPI_EN_CS(n) (n << 28) +#define QSPI_WLEN(n) ((n - 1) << 19) +#define QSPI_3_PIN (1 << 18) +#define QSPI_RD_SNGL (1 << 16) +#define QSPI_WR_SNGL (2 << 16) +#define QSPI_RD_DUAL (3 << 16) +#define QSPI_RD_QUAD (7 << 16) +#define QSPI_INVAL (4 << 16) +#define QSPI_WC_CMD_INT_EN (1 << 14) +#define QSPI_FLEN(n) ((n - 1) << 0) + +/* STATUS REGISTER */ +#define WC 0x02 + +/* INTERRUPT REGISTER */ +#define QSPI_WC_INT_EN (1 << 1) +#define QSPI_WC_INT_DISABLE (1 << 1) + +/* Device Control */ +#define QSPI_DD(m, n) (m << (3 + n * 8)) +#define QSPI_CKPHA(n) (1 << (2 + n * 8)) +#define QSPI_CSPOL(n) (1 << (1 + n * 8)) +#define QSPI_CKPOL(n) (1 << (n * 8)) + +#define QSPI_FRAME 4096 + +#define QSPI_AUTOSUSPEND_TIMEOUT 2000 + +static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, + unsigned long reg) +{ + return readl(qspi->base + reg); +} + +static inline void ti_qspi_write(struct ti_qspi *qspi, + unsigned long val, unsigned long reg) +{ + writel(val, qspi->base + reg); +} + +static int ti_qspi_setup(struct spi_device *spi) +{ + struct ti_qspi *qspi = spi_master_get_devdata(spi->master); + struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; + int clk_div = 0, ret; + u32 clk_ctrl_reg, clk_rate, clk_mask; + + if (spi->master->busy) { + dev_dbg(qspi->dev, "master busy doing other trasnfers\n"); + return -EBUSY; + } + + if (!qspi->spi_max_frequency) { + dev_err(qspi->dev, "spi max frequency not defined\n"); + return -EINVAL; + } + + clk_rate = clk_get_rate(qspi->fclk); + + clk_div = DIV_ROUND_UP(clk_rate, qspi->spi_max_frequency) - 1; + + if (clk_div < 0) { + dev_dbg(qspi->dev, "clock divider < 0, using /1 divider\n"); + return -EINVAL; + } + + if (clk_div > QSPI_CLK_DIV_MAX) { + dev_dbg(qspi->dev, "clock divider >%d , using /%d divider\n", + QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1); + return -EINVAL; + } + + dev_dbg(qspi->dev, "hz: %d, clock divider %d\n", + qspi->spi_max_frequency, clk_div); + + ret = pm_runtime_get_sync(qspi->dev); + if (ret) { + dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); + return ret; + } + + clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG); + + clk_ctrl_reg &= ~QSPI_CLK_EN; + + /* disable SCLK */ + ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG); + + /* enable SCLK */ + clk_mask = QSPI_CLK_EN | clk_div; + ti_qspi_write(qspi, clk_mask, QSPI_SPI_CLOCK_CNTRL_REG); + ctx_reg->clkctrl = clk_mask; + + pm_runtime_mark_last_busy(qspi->dev); + ret = pm_runtime_put_autosuspend(qspi->dev); + if (ret < 0) { + dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n"); + return ret; + } + + return 0; +} + +static void ti_qspi_restore_ctx(struct ti_qspi *qspi) +{ + struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; + + ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG); +} + +static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) +{ + int wlen, count, ret; + unsigned int cmd; + const u8 *txbuf; + + txbuf = t->tx_buf; + cmd = qspi->cmd | QSPI_WR_SNGL; + count = t->len; + wlen = t->bits_per_word; + + while (count) { + switch (wlen) { + case 8: + dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", + cmd, qspi->dc, *txbuf); + writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); + ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); + ret = wait_for_completion_timeout(&qspi->transfer_complete, + QSPI_COMPLETION_TIMEOUT); + if (ret == 0) { + dev_err(qspi->dev, "write timed out\n"); + return -ETIMEDOUT; + } + txbuf += 1; + count -= 1; + break; + case 16: + dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", + cmd, qspi->dc, *txbuf); + writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); + ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); + ret = wait_for_completion_timeout(&qspi->transfer_complete, + QSPI_COMPLETION_TIMEOUT); + if (ret == 0) { + dev_err(qspi->dev, "write timed out\n"); + return -ETIMEDOUT; + } + txbuf += 2; + count -= 2; + break; + case 32: + dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n", + cmd, qspi->dc, *txbuf); + writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); + ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); + ret = wait_for_completion_timeout(&qspi->transfer_complete, + QSPI_COMPLETION_TIMEOUT); + if (ret == 0) { + dev_err(qspi->dev, "write timed out\n"); + return -ETIMEDOUT; + } + txbuf += 4; + count -= 4; + break; + } + } + + return 0; +} + +static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) +{ + int wlen, count, ret; + unsigned int cmd; + u8 *rxbuf; + + rxbuf = t->rx_buf; + cmd = qspi->cmd; + switch (t->rx_nbits) { + case SPI_NBITS_DUAL: + cmd |= QSPI_RD_DUAL; + break; + case SPI_NBITS_QUAD: + cmd |= QSPI_RD_QUAD; + break; + default: + cmd |= QSPI_RD_SNGL; + break; + } + count = t->len; + wlen = t->bits_per_word; + + while (count) { + dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); + ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); + ret = wait_for_completion_timeout(&qspi->transfer_complete, + QSPI_COMPLETION_TIMEOUT); + if (ret == 0) { + dev_err(qspi->dev, "read timed out\n"); + return -ETIMEDOUT; + } + switch (wlen) { + case 8: + *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG); + rxbuf += 1; + count -= 1; + break; + case 16: + *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); + rxbuf += 2; + count -= 2; + break; + case 32: + *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); + rxbuf += 4; + count -= 4; + break; + } + } + + return 0; +} + +static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) +{ + int ret; + + if (t->tx_buf) { + ret = qspi_write_msg(qspi, t); + if (ret) { + dev_dbg(qspi->dev, "Error while writing\n"); + return ret; + } + } + + if (t->rx_buf) { + ret = qspi_read_msg(qspi, t); + if (ret) { + dev_dbg(qspi->dev, "Error while reading\n"); + return ret; + } + } + + return 0; +} + +static int ti_qspi_start_transfer_one(struct spi_master *master, + struct spi_message *m) +{ + struct ti_qspi *qspi = spi_master_get_devdata(master); + struct spi_device *spi = m->spi; + struct spi_transfer *t; + int status = 0, ret; + int frame_length; + + /* setup device control reg */ + qspi->dc = 0; + + if (spi->mode & SPI_CPHA) + qspi->dc |= QSPI_CKPHA(spi->chip_select); + if (spi->mode & SPI_CPOL) + qspi->dc |= QSPI_CKPOL(spi->chip_select); + if (spi->mode & SPI_CS_HIGH) + qspi->dc |= QSPI_CSPOL(spi->chip_select); + + frame_length = (m->frame_length << 3) / spi->bits_per_word; + + frame_length = clamp(frame_length, 0, QSPI_FRAME); + + /* setup command reg */ + qspi->cmd = 0; + qspi->cmd |= QSPI_EN_CS(spi->chip_select); + qspi->cmd |= QSPI_FLEN(frame_length); + qspi->cmd |= QSPI_WC_CMD_INT_EN; + + ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG); + ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG); + + mutex_lock(&qspi->list_lock); + + list_for_each_entry(t, &m->transfers, transfer_list) { + qspi->cmd |= QSPI_WLEN(t->bits_per_word); + + ret = qspi_transfer_msg(qspi, t); + if (ret) { + dev_dbg(qspi->dev, "transfer message failed\n"); + mutex_unlock(&qspi->list_lock); + return -EINVAL; + } + + m->actual_length += t->len; + } + + mutex_unlock(&qspi->list_lock); + + m->status = status; + spi_finalize_current_message(master); + + ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); + + return status; +} + +static irqreturn_t ti_qspi_isr(int irq, void *dev_id) +{ + struct ti_qspi *qspi = dev_id; + u16 int_stat; + + irqreturn_t ret = IRQ_HANDLED; + + spin_lock(&qspi->lock); + + int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR); + qspi->stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); + + if (!int_stat) { + dev_dbg(qspi->dev, "No IRQ triggered\n"); + ret = IRQ_NONE; + goto out; + } + + ret = IRQ_WAKE_THREAD; + + ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); + ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, + QSPI_INTR_STATUS_ENABLED_CLEAR); + +out: + spin_unlock(&qspi->lock); + + return ret; +} + +static irqreturn_t ti_qspi_threaded_isr(int this_irq, void *dev_id) +{ + struct ti_qspi *qspi = dev_id; + unsigned long flags; + + spin_lock_irqsave(&qspi->lock, flags); + + if (qspi->stat & WC) + complete(&qspi->transfer_complete); + + spin_unlock_irqrestore(&qspi->lock, flags); + + ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG); + + return IRQ_HANDLED; +} + +static int ti_qspi_runtime_resume(struct device *dev) +{ + struct ti_qspi *qspi; + struct spi_master *master; + + master = dev_get_drvdata(dev); + qspi = spi_master_get_devdata(master); + ti_qspi_restore_ctx(qspi); + + return 0; +} + +static const struct of_device_id ti_qspi_match[] = { + {.compatible = "ti,dra7xxx-qspi" }, + {.compatible = "ti,am4372-qspi" }, + {}, +}; +MODULE_DEVICE_TABLE(of, ti_qspi_match); + +static int ti_qspi_probe(struct platform_device *pdev) +{ + struct ti_qspi *qspi; + struct spi_master *master; + struct resource *r; + struct device_node *np = pdev->dev.of_node; + u32 max_freq; + int ret = 0, num_cs, irq; + + master = spi_alloc_master(&pdev->dev, sizeof(*qspi)); + if (!master) + return -ENOMEM; + + master->mode_bits = SPI_CPOL | SPI_CPHA; + + master->bus_num = -1; + master->flags = SPI_MASTER_HALF_DUPLEX; + master->setup = ti_qspi_setup; + master->auto_runtime_pm = true; + master->transfer_one_message = ti_qspi_start_transfer_one; + master->dev.of_node = pdev->dev.of_node; + master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + + if (!of_property_read_u32(np, "num-cs", &num_cs)) + master->num_chipselect = num_cs; + + platform_set_drvdata(pdev, master); + + qspi = spi_master_get_devdata(master); + qspi->master = master; + qspi->dev = &pdev->dev; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "no irq resource?\n"); + return irq; + } + + spin_lock_init(&qspi->lock); + mutex_init(&qspi->list_lock); + + qspi->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(qspi->base)) { + ret = PTR_ERR(qspi->base); + goto free_master; + } + + ret = devm_request_threaded_irq(&pdev->dev, irq, ti_qspi_isr, + ti_qspi_threaded_isr, 0, + dev_name(&pdev->dev), qspi); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", + irq); + goto free_master; + } + + qspi->fclk = devm_clk_get(&pdev->dev, "fck"); + if (IS_ERR(qspi->fclk)) { + ret = PTR_ERR(qspi->fclk); + dev_err(&pdev->dev, "could not get clk: %d\n", ret); + } + + init_completion(&qspi->transfer_complete); + + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT); + pm_runtime_enable(&pdev->dev); + + if (!of_property_read_u32(np, "spi-max-frequency", &max_freq)) + qspi->spi_max_frequency = max_freq; + + ret = spi_register_master(master); + if (ret) + goto free_master; + + return 0; + +free_master: + spi_master_put(master); + return ret; +} + +static int ti_qspi_remove(struct platform_device *pdev) +{ + struct ti_qspi *qspi = platform_get_drvdata(pdev); + + spi_unregister_master(qspi->master); + + return 0; +} + +static const struct dev_pm_ops ti_qspi_pm_ops = { + .runtime_resume = ti_qspi_runtime_resume, +}; + +static struct platform_driver ti_qspi_driver = { + .probe = ti_qspi_probe, + .remove = ti_qspi_remove, + .driver = { + .name = "ti,dra7xxx-qspi", + .owner = THIS_MODULE, + .pm = &ti_qspi_pm_ops, + .of_match_table = ti_qspi_match, + } +}; + +module_platform_driver(ti_qspi_driver); + +MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI QSPI controller driver"); diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c index 10606fcc6efc..7d20e121e4c1 100644 --- a/drivers/spi/spi-ti-ssp.c +++ b/drivers/spi/spi-ti-ssp.c @@ -283,7 +283,7 @@ static int ti_ssp_spi_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int error = 0; - pdata = dev->platform_data; + pdata = dev_get_platdata(dev); if (!pdata) { dev_err(dev, "platform data not found\n"); return -EINVAL; diff --git a/drivers/spi/spi-tle62x0.c b/drivers/spi/spi-tle62x0.c index 6b0874d782ed..b5a70e3fecb7 100644 --- a/drivers/spi/spi-tle62x0.c +++ b/drivers/spi/spi-tle62x0.c @@ -247,7 +247,7 @@ static int tle62x0_probe(struct spi_device *spi) int ptr; int ret; - pdata = spi->dev.platform_data; + pdata = dev_get_platdata(&spi->dev); if (pdata == NULL) { dev_err(&spi->dev, "no device data specified\n"); return -EINVAL; diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 09a942852593..0bf1b2c457a1 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -80,10 +80,9 @@ struct xilinx_spi { /* bitbang has to be first */ struct spi_bitbang bitbang; struct completion done; - struct resource mem; /* phys mem */ void __iomem *regs; /* virt. address of the control registers */ - u32 irq; + int irq; u8 *rx_ptr; /* pointer in the Tx buffer */ const u8 *tx_ptr; /* pointer in the Rx buffer */ @@ -233,21 +232,6 @@ static int xilinx_spi_setup_transfer(struct spi_device *spi, return 0; } -static int xilinx_spi_setup(struct spi_device *spi) -{ - /* always return 0, we can not check the number of bits. - * There are cases when SPI setup is called before any driver is - * there, in that case the SPI core defaults to 8 bits, which we - * do not support in some cases. But if we return an error, the - * SPI device would not be registered and no driver can get hold of it - * When the driver is there, it will call SPI setup again with the - * correct number of bits per transfer. - * If a driver setups with the wrong bit number, it will fail when - * it tries to do a transfer - */ - return 0; -} - static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi) { u8 sr; @@ -355,17 +339,34 @@ static const struct of_device_id xilinx_spi_of_match[] = { }; MODULE_DEVICE_TABLE(of, xilinx_spi_of_match); -struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, - u32 irq, s16 bus_num, int num_cs, int bits_per_word) +static int xilinx_spi_probe(struct platform_device *pdev) { - struct spi_master *master; struct xilinx_spi *xspi; - int ret; + struct xspi_platform_data *pdata; + struct resource *res; + int ret, num_cs = 0, bits_per_word = 8; + struct spi_master *master; u32 tmp; + u8 i; + + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + num_cs = pdata->num_chipselect; + bits_per_word = pdata->bits_per_word; + } else { + of_property_read_u32(pdev->dev.of_node, "xlnx,num-ss-bits", + &num_cs); + } + + if (!num_cs) { + dev_err(&pdev->dev, + "Missing slave select configuration data\n"); + return -EINVAL; + } - master = spi_alloc_master(dev, sizeof(struct xilinx_spi)); + master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi)); if (!master) - return NULL; + return -ENODEV; /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA; @@ -375,25 +376,18 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, xspi->bitbang.chipselect = xilinx_spi_chipselect; xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer; xspi->bitbang.txrx_bufs = xilinx_spi_txrx_bufs; - xspi->bitbang.master->setup = xilinx_spi_setup; init_completion(&xspi->done); - if (!request_mem_region(mem->start, resource_size(mem), - XILINX_SPI_NAME)) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + xspi->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xspi->regs)) { + ret = PTR_ERR(xspi->regs); goto put_master; - - xspi->regs = ioremap(mem->start, resource_size(mem)); - if (xspi->regs == NULL) { - dev_warn(dev, "ioremap failure\n"); - goto map_failed; } - master->bus_num = bus_num; + master->bus_num = pdev->dev.id; master->num_chipselect = num_cs; - master->dev.of_node = dev->of_node; - - xspi->mem = *mem; - xspi->irq = irq; + master->dev.of_node = pdev->dev.of_node; /* * Detect endianess on the IP via loop bit in CR. Detection @@ -423,113 +417,63 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, } else if (xspi->bits_per_word == 32) { xspi->tx_fn = xspi_tx32; xspi->rx_fn = xspi_rx32; - } else - goto unmap_io; - + } else { + ret = -EINVAL; + goto put_master; + } /* SPI controller initializations */ xspi_init_hw(xspi); + xspi->irq = platform_get_irq(pdev, 0); + if (xspi->irq < 0) { + ret = xspi->irq; + goto put_master; + } + /* Register for SPI Interrupt */ - ret = request_irq(xspi->irq, xilinx_spi_irq, 0, XILINX_SPI_NAME, xspi); + ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0, + dev_name(&pdev->dev), xspi); if (ret) - goto unmap_io; + goto put_master; ret = spi_bitbang_start(&xspi->bitbang); if (ret) { - dev_err(dev, "spi_bitbang_start FAILED\n"); - goto free_irq; - } - - dev_info(dev, "at 0x%08llX mapped to 0x%p, irq=%d\n", - (unsigned long long)mem->start, xspi->regs, xspi->irq); - return master; - -free_irq: - free_irq(xspi->irq, xspi); -unmap_io: - iounmap(xspi->regs); -map_failed: - release_mem_region(mem->start, resource_size(mem)); -put_master: - spi_master_put(master); - return NULL; -} -EXPORT_SYMBOL(xilinx_spi_init); - -void xilinx_spi_deinit(struct spi_master *master) -{ - struct xilinx_spi *xspi; - - xspi = spi_master_get_devdata(master); - - spi_bitbang_stop(&xspi->bitbang); - free_irq(xspi->irq, xspi); - iounmap(xspi->regs); - - release_mem_region(xspi->mem.start, resource_size(&xspi->mem)); - spi_master_put(xspi->bitbang.master); -} -EXPORT_SYMBOL(xilinx_spi_deinit); - -static int xilinx_spi_probe(struct platform_device *dev) -{ - struct xspi_platform_data *pdata; - struct resource *r; - int irq, num_cs = 0, bits_per_word = 8; - struct spi_master *master; - u8 i; - - pdata = dev->dev.platform_data; - if (pdata) { - num_cs = pdata->num_chipselect; - bits_per_word = pdata->bits_per_word; - } - -#ifdef CONFIG_OF - if (dev->dev.of_node) { - const __be32 *prop; - int len; - - /* number of slave select bits is required */ - prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits", - &len); - if (prop && len >= sizeof(*prop)) - num_cs = __be32_to_cpup(prop); - } -#endif - - if (!num_cs) { - dev_err(&dev->dev, "Missing slave select configuration data\n"); - return -EINVAL; + dev_err(&pdev->dev, "spi_bitbang_start FAILED\n"); + goto put_master; } - - r = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!r) - return -ENODEV; - - irq = platform_get_irq(dev, 0); - if (irq < 0) - return -ENXIO; - - master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs, - bits_per_word); - if (!master) - return -ENODEV; + dev_info(&pdev->dev, "at 0x%08llX mapped to 0x%p, irq=%d\n", + (unsigned long long)res->start, xspi->regs, xspi->irq); if (pdata) { for (i = 0; i < pdata->num_devices; i++) spi_new_device(master, pdata->devices + i); } - platform_set_drvdata(dev, master); + platform_set_drvdata(pdev, master); return 0; + +put_master: + spi_master_put(master); + + return ret; } -static int xilinx_spi_remove(struct platform_device *dev) +static int xilinx_spi_remove(struct platform_device *pdev) { - xilinx_spi_deinit(platform_get_drvdata(dev)); + struct spi_master *master = platform_get_drvdata(pdev); + struct xilinx_spi *xspi = spi_master_get_devdata(master); + void __iomem *regs_base = xspi->regs; + + spi_bitbang_stop(&xspi->bitbang); + + /* Disable all the interrupts just in case */ + xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET); + /* Disable the global IPIF interrupt */ + xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET); + + spi_master_put(xspi->bitbang.master); return 0; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 978dda2c5239..9e039c60c068 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -553,6 +553,10 @@ static void spi_pump_messages(struct kthread_work *work) master->unprepare_transfer_hardware(master)) dev_err(&master->dev, "failed to unprepare transfer hardware\n"); + if (master->auto_runtime_pm) { + pm_runtime_mark_last_busy(master->dev.parent); + pm_runtime_put_autosuspend(master->dev.parent); + } return; } @@ -572,11 +576,23 @@ static void spi_pump_messages(struct kthread_work *work) master->busy = true; spin_unlock_irqrestore(&master->queue_lock, flags); + if (!was_busy && master->auto_runtime_pm) { + ret = pm_runtime_get_sync(master->dev.parent); + if (ret < 0) { + dev_err(&master->dev, "Failed to power device: %d\n", + ret); + return; + } + } + if (!was_busy && master->prepare_transfer_hardware) { ret = master->prepare_transfer_hardware(master); if (ret) { dev_err(&master->dev, "failed to prepare transfer hardware\n"); + + if (master->auto_runtime_pm) + pm_runtime_put(master->dev.parent); return; } } @@ -774,7 +790,7 @@ static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg) msg->status = -EINPROGRESS; list_add_tail(&msg->queue, &master->queue); - if (master->running && !master->busy) + if (!master->busy) queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); @@ -869,6 +885,47 @@ static void of_register_spi_devices(struct spi_master *master) if (of_find_property(nc, "spi-3wire", NULL)) spi->mode |= SPI_3WIRE; + /* Device DUAL/QUAD mode */ + prop = of_get_property(nc, "spi-tx-bus-width", &len); + if (prop && len == sizeof(*prop)) { + switch (be32_to_cpup(prop)) { + case SPI_NBITS_SINGLE: + break; + case SPI_NBITS_DUAL: + spi->mode |= SPI_TX_DUAL; + break; + case SPI_NBITS_QUAD: + spi->mode |= SPI_TX_QUAD; + break; + default: + dev_err(&master->dev, + "spi-tx-bus-width %d not supported\n", + be32_to_cpup(prop)); + spi_dev_put(spi); + continue; + } + } + + prop = of_get_property(nc, "spi-rx-bus-width", &len); + if (prop && len == sizeof(*prop)) { + switch (be32_to_cpup(prop)) { + case SPI_NBITS_SINGLE: + break; + case SPI_NBITS_DUAL: + spi->mode |= SPI_RX_DUAL; + break; + case SPI_NBITS_QUAD: + spi->mode |= SPI_RX_QUAD; + break; + default: + dev_err(&master->dev, + "spi-rx-bus-width %d not supported\n", + be32_to_cpup(prop)); + spi_dev_put(spi); + continue; + } + } + /* Device speed */ prop = of_get_property(nc, "spi-max-frequency", &len); if (!prop || len < sizeof(*prop)) { @@ -1169,7 +1226,7 @@ int spi_register_master(struct spi_master *master) else { status = spi_master_initialize_queue(master); if (status) { - device_unregister(&master->dev); + device_del(&master->dev); goto done; } } @@ -1316,6 +1373,19 @@ int spi_setup(struct spi_device *spi) unsigned bad_bits; int status = 0; + /* check mode to prevent that DUAL and QUAD set at the same time + */ + if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) || + ((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) { + dev_err(&spi->dev, + "setup: can not select dual and quad at the same time\n"); + return -EINVAL; + } + /* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden + */ + if ((spi->mode & SPI_3WIRE) && (spi->mode & + (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD))) + return -EINVAL; /* help drivers fail *cleanly* when they need options * that aren't supported with their current master */ @@ -1351,6 +1421,11 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) struct spi_master *master = spi->master; struct spi_transfer *xfer; + if (list_empty(&message->transfers)) + return -EINVAL; + if (!message->complete) + return -EINVAL; + /* Half-duplex links include original MicroWire, and ones with * only one data pin like SPI_3WIRE (switches direction) or where * either MOSI or MISO is missing. They can also be caused by @@ -1373,12 +1448,20 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) /** * Set transfer bits_per_word and max speed as spi device default if * it is not set for this transfer. + * Set transfer tx_nbits and rx_nbits as single transfer default + * (SPI_NBITS_SINGLE) if it is not set for this transfer. */ list_for_each_entry(xfer, &message->transfers, transfer_list) { + message->frame_length += xfer->len; if (!xfer->bits_per_word) xfer->bits_per_word = spi->bits_per_word; - if (!xfer->speed_hz) + if (!xfer->speed_hz) { xfer->speed_hz = spi->max_speed_hz; + if (master->max_speed_hz && + xfer->speed_hz > master->max_speed_hz) + xfer->speed_hz = master->max_speed_hz; + } + if (master->bits_per_word_mask) { /* Only 32 bits fit in the mask */ if (xfer->bits_per_word > 32) @@ -1387,6 +1470,54 @@ static int __spi_async(struct spi_device *spi, struct spi_message *message) BIT(xfer->bits_per_word - 1))) return -EINVAL; } + + if (xfer->speed_hz && master->min_speed_hz && + xfer->speed_hz < master->min_speed_hz) + return -EINVAL; + if (xfer->speed_hz && master->max_speed_hz && + xfer->speed_hz > master->max_speed_hz) + return -EINVAL; + + if (xfer->tx_buf && !xfer->tx_nbits) + xfer->tx_nbits = SPI_NBITS_SINGLE; + if (xfer->rx_buf && !xfer->rx_nbits) + xfer->rx_nbits = SPI_NBITS_SINGLE; + /* check transfer tx/rx_nbits: + * 1. keep the value is not out of single, dual and quad + * 2. keep tx/rx_nbits is contained by mode in spi_device + * 3. if SPI_3WIRE, tx/rx_nbits should be in single + */ + if (xfer->tx_buf) { + if (xfer->tx_nbits != SPI_NBITS_SINGLE && + xfer->tx_nbits != SPI_NBITS_DUAL && + xfer->tx_nbits != SPI_NBITS_QUAD) + return -EINVAL; + if ((xfer->tx_nbits == SPI_NBITS_DUAL) && + !(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD))) + return -EINVAL; + if ((xfer->tx_nbits == SPI_NBITS_QUAD) && + !(spi->mode & SPI_TX_QUAD)) + return -EINVAL; + if ((spi->mode & SPI_3WIRE) && + (xfer->tx_nbits != SPI_NBITS_SINGLE)) + return -EINVAL; + } + /* check transfer rx_nbits */ + if (xfer->rx_buf) { + if (xfer->rx_nbits != SPI_NBITS_SINGLE && + xfer->rx_nbits != SPI_NBITS_DUAL && + xfer->rx_nbits != SPI_NBITS_QUAD) + return -EINVAL; + if ((xfer->rx_nbits == SPI_NBITS_DUAL) && + !(spi->mode & (SPI_RX_DUAL | SPI_RX_QUAD))) + return -EINVAL; + if ((xfer->rx_nbits == SPI_NBITS_QUAD) && + !(spi->mode & SPI_RX_QUAD)) + return -EINVAL; + if ((spi->mode & SPI_3WIRE) && + (xfer->rx_nbits != SPI_NBITS_SINGLE)) + return -EINVAL; + } } message->spi = spi; diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index e25eba5713c1..b3b5125faa72 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -482,7 +482,7 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) ret = comedi_device_postconfig(dev); if (ret < 0) { comedi_device_detach(dev); - module_put(dev->driver->module); + module_put(driv->module); } /* On success, the driver module count has been incremented. */ return ret; diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 609dbc2f7151..83b4ef4dfcf8 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1119,11 +1119,11 @@ static int usbtmc_probe(struct usb_interface *intf, /* Determine if it is a Rigol or not */ data->rigol_quirk = 0; dev_dbg(&intf->dev, "Trying to find if device Vendor 0x%04X Product 0x%04X has the RIGOL quirk\n", - data->usb_dev->descriptor.idVendor, - data->usb_dev->descriptor.idProduct); + le16_to_cpu(data->usb_dev->descriptor.idVendor), + le16_to_cpu(data->usb_dev->descriptor.idProduct)); for(n = 0; usbtmc_id_quirk[n].idVendor > 0; n++) { - if ((usbtmc_id_quirk[n].idVendor == data->usb_dev->descriptor.idVendor) && - (usbtmc_id_quirk[n].idProduct == data->usb_dev->descriptor.idProduct)) { + if ((usbtmc_id_quirk[n].idVendor == le16_to_cpu(data->usb_dev->descriptor.idVendor)) && + (usbtmc_id_quirk[n].idProduct == le16_to_cpu(data->usb_dev->descriptor.idProduct))) { dev_dbg(&intf->dev, "Setting this device as having the RIGOL quirk\n"); data->rigol_quirk = 1; break; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index a63598895077..5b44cd47da5b 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -78,6 +78,12 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x04d8, 0x000c), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* CarrolTouch 4000U */ + { USB_DEVICE(0x04e7, 0x0009), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* CarrolTouch 4500U */ + { USB_DEVICE(0x04e7, 0x0030), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Samsung Android phone modem - ID conflict with SPH-I500 */ { USB_DEVICE(0x04e8, 0x6601), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index f80d0330d548..8e3c878f38cf 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1391,21 +1391,20 @@ iso_stream_schedule ( /* Behind the scheduling threshold? */ if (unlikely(start < next)) { + unsigned now2 = (now - base) & (mod - 1); /* USB_ISO_ASAP: Round up to the first available slot */ if (urb->transfer_flags & URB_ISO_ASAP) start += (next - start + period - 1) & -period; /* - * Not ASAP: Use the next slot in the stream. If - * the entire URB falls before the threshold, fail. + * Not ASAP: Use the next slot in the stream, + * no matter what. */ - else if (start + span - period < next) { - ehci_dbg(ehci, "iso urb late %p (%u+%u < %u)\n", + else if (start + span - period < now2) { + ehci_dbg(ehci, "iso underrun %p (%u+%u < %u)\n", urb, start + base, - span - period, next + base); - status = -EXDEV; - goto fail; + span - period, now2 + base); } } diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 08613e241894..0f1d193fef02 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -304,6 +304,11 @@ static int __init ohci_pci_init(void) pr_info("%s: " DRIVER_DESC "\n", hcd_name); ohci_init_driver(&ohci_pci_hc_driver, &pci_overrides); + + /* Entries for the PCI suspend/resume callbacks are special */ + ohci_pci_hc_driver.pci_suspend = ohci_suspend; + ohci_pci_hc_driver.pci_resume = ohci_resume; + return pci_register_driver(&ohci_pci_driver); } module_init(ohci_pci_init); diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index eb3c8c142fa9..eeb27208c0d1 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -830,7 +830,7 @@ static int adu_probe(struct usb_interface *interface, /* let the user know what node this device is now attached to */ dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d\n", - udev->descriptor.idProduct, dev->serial_number, + le16_to_cpu(udev->descriptor.idProduct), dev->serial_number, (dev->minor - ADU_MINOR_BASE)); exit: dbg(2, " %s : leave, return value %p (dev)", __func__, dev); diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h index ca266280895d..e1859b8ef567 100644 --- a/drivers/usb/phy/phy-fsl-usb.h +++ b/drivers/usb/phy/phy-fsl-usb.h @@ -15,7 +15,7 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "otg_fsm.h" +#include "phy-fsm-usb.h" #include <linux/usb/otg.h> #include <linux/ioctl.h> diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c index c520b3548e7c..7f4596606e18 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -29,7 +29,7 @@ #include <linux/usb/gadget.h> #include <linux/usb/otg.h> -#include "phy-otg-fsm.h" +#include "phy-fsm-usb.h" /* Change USB protocol when there is a protocol change */ static int otg_set_protocol(struct otg_fsm *fsm, int protocol) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 5a979729f8ec..58c17fdc85eb 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -2303,7 +2303,7 @@ static int keyspan_startup(struct usb_serial *serial) if (d_details == NULL) { dev_err(&serial->dev->dev, "%s - unknown product id %x\n", __func__, le16_to_cpu(serial->dev->descriptor.idProduct)); - return 1; + return -ENODEV; } /* Setup private data for serial driver */ diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 51da424327b0..b01300164fc0 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -90,6 +90,7 @@ struct urbtracker { struct list_head urblist_entry; struct kref ref_count; struct urb *urb; + struct usb_ctrlrequest *setup; }; enum mos7715_pp_modes { @@ -271,6 +272,7 @@ static void destroy_urbtracker(struct kref *kref) struct mos7715_parport *mos_parport = urbtrack->mos_parport; usb_free_urb(urbtrack->urb); + kfree(urbtrack->setup); kfree(urbtrack); kref_put(&mos_parport->ref_count, destroy_mos_parport); } @@ -355,7 +357,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, struct urbtracker *urbtrack; int ret_val; unsigned long flags; - struct usb_ctrlrequest setup; struct usb_serial *serial = mos_parport->serial; struct usb_device *usbdev = serial->dev; @@ -373,14 +374,20 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, kfree(urbtrack); return -ENOMEM; } - setup.bRequestType = (__u8)0x40; - setup.bRequest = (__u8)0x0e; - setup.wValue = get_reg_value(reg, dummy); - setup.wIndex = get_reg_index(reg); - setup.wLength = 0; + urbtrack->setup = kmalloc(sizeof(*urbtrack->setup), GFP_KERNEL); + if (!urbtrack->setup) { + usb_free_urb(urbtrack->urb); + kfree(urbtrack); + return -ENOMEM; + } + urbtrack->setup->bRequestType = (__u8)0x40; + urbtrack->setup->bRequest = (__u8)0x0e; + urbtrack->setup->wValue = get_reg_value(reg, dummy); + urbtrack->setup->wIndex = get_reg_index(reg); + urbtrack->setup->wLength = 0; usb_fill_control_urb(urbtrack->urb, usbdev, usb_sndctrlpipe(usbdev, 0), - (unsigned char *)&setup, + (unsigned char *)urbtrack->setup, NULL, 0, async_complete, urbtrack); kref_init(&urbtrack->ref_count); INIT_LIST_HEAD(&urbtrack->urblist_entry); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index d953d674f222..3bac4693c038 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -2193,7 +2193,7 @@ static int mos7810_check(struct usb_serial *serial) static int mos7840_probe(struct usb_serial *serial, const struct usb_device_id *id) { - u16 product = serial->dev->descriptor.idProduct; + u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); u8 *buf; int device_type; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 375b5a400b6f..5c9f9b1d7736 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1536,14 +1536,15 @@ static int ti_download_firmware(struct ti_device *tdev) char buf[32]; /* try ID specific firmware first, then try generic firmware */ - sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor, - dev->descriptor.idProduct); + sprintf(buf, "ti_usb-v%04x-p%04x.fw", + le16_to_cpu(dev->descriptor.idVendor), + le16_to_cpu(dev->descriptor.idProduct)); status = request_firmware(&fw_p, buf, &dev->dev); if (status != 0) { buf[0] = '\0'; - if (dev->descriptor.idVendor == MTS_VENDOR_ID) { - switch (dev->descriptor.idProduct) { + if (le16_to_cpu(dev->descriptor.idVendor) == MTS_VENDOR_ID) { + switch (le16_to_cpu(dev->descriptor.idProduct)) { case MTS_CDMA_PRODUCT_ID: strcpy(buf, "mts_cdma.fw"); break; diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 8257d30c4072..85365784040b 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -291,18 +291,18 @@ static void usb_wwan_indat_callback(struct urb *urb) tty_flip_buffer_push(&port->port); } else dev_dbg(dev, "%s: empty read urb received\n", __func__); - - /* Resubmit urb so we continue receiving */ - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - if (err != -EPERM) { - dev_err(dev, "%s: resubmit read urb failed. (%d)\n", __func__, err); - /* busy also in error unless we are killed */ - usb_mark_last_busy(port->serial->dev); - } - } else { + } + /* Resubmit urb so we continue receiving */ + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + if (err != -EPERM) { + dev_err(dev, "%s: resubmit read urb failed. (%d)\n", + __func__, err); + /* busy also in error unless we are killed */ usb_mark_last_busy(port->serial->dev); } + } else { + usb_mark_last_busy(port->serial->dev); } } diff --git a/drivers/usb/wusbcore/wa-xfer.c b/drivers/usb/wusbcore/wa-xfer.c index 16968c899493..d3493ca0525d 100644 --- a/drivers/usb/wusbcore/wa-xfer.c +++ b/drivers/usb/wusbcore/wa-xfer.c @@ -1226,6 +1226,12 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb) } spin_lock_irqsave(&xfer->lock, flags); rpipe = xfer->ep->hcpriv; + if (rpipe == NULL) { + pr_debug("%s: xfer id 0x%08X has no RPIPE. %s", + __func__, wa_xfer_id(xfer), + "Probably already aborted.\n" ); + goto out_unlock; + } /* Check the delayed list -> if there, release and complete */ spin_lock_irqsave(&wa->xfer_list_lock, flags2); if (!list_empty(&xfer->list_node) && xfer->seg == NULL) @@ -1644,8 +1650,7 @@ static void wa_xfer_result_cb(struct urb *urb) break; } usb_status = xfer_result->bTransferStatus & 0x3f; - if (usb_status == WA_XFER_STATUS_ABORTED - || usb_status == WA_XFER_STATUS_NOT_FOUND) + if (usb_status == WA_XFER_STATUS_NOT_FOUND) /* taken care of already */ break; xfer_id = xfer_result->dwTransferID; diff --git a/drivers/xen/events.c b/drivers/xen/events.c index a58ac435a9a4..5e8be462aed5 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c @@ -348,7 +348,7 @@ static void init_evtchn_cpu_bindings(void) for_each_possible_cpu(i) memset(per_cpu(cpu_evtchn_mask, i), - (i == 0) ? ~0 : 0, sizeof(*per_cpu(cpu_evtchn_mask, i))); + (i == 0) ? ~0 : 0, NR_EVENT_CHANNELS/8); } static inline void clear_evtchn(int port) @@ -1493,8 +1493,10 @@ void rebind_evtchn_irq(int evtchn, int irq) /* Rebind an evtchn so that it gets delivered to a specific cpu */ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) { + struct shared_info *s = HYPERVISOR_shared_info; struct evtchn_bind_vcpu bind_vcpu; int evtchn = evtchn_from_irq(irq); + int masked; if (!VALID_EVTCHN(evtchn)) return -1; @@ -1511,6 +1513,12 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) bind_vcpu.vcpu = tcpu; /* + * Mask the event while changing the VCPU binding to prevent + * it being delivered on an unexpected VCPU. + */ + masked = sync_test_and_set_bit(evtchn, BM(s->evtchn_mask)); + + /* * If this fails, it usually just indicates that we're dealing with a * virq or IPI channel, which don't actually need to be rebound. Ignore * it, but don't do the xenlinux-level rebind in that case. @@ -1518,6 +1526,9 @@ static int rebind_irq_to_cpu(unsigned irq, unsigned tcpu) if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &bind_vcpu) >= 0) bind_evtchn_to_cpu(evtchn, tcpu); + if (!masked) + unmask_evtchn(evtchn); + return 0; } |