diff options
author | James Hogan <james.hogan@imgtec.com> | 2014-07-28 15:57:10 +0100 |
---|---|---|
committer | James Hogan <james.hogan@imgtec.com> | 2015-11-12 00:18:32 +0000 |
commit | 541484f278bb584a7970f91b6c43ea6fa76fd209 (patch) | |
tree | 3b8da5f40598419d852da2d198d923c37ed4c813 | |
parent | f41e0d92a683a20eaa0ff80dbd45b0b362fa1fb6 (diff) | |
download | metag-legacy-master.tar.gz |
Numerous fixes and updates to the official metag tree up to July 28th
2014.
Signed-off-by: James Hogan <james.hogan@imgtec.com>
43 files changed, 584 insertions, 351 deletions
diff --git a/arch/metag/boards/TZ1090-01XX/setup.c b/arch/metag/boards/TZ1090-01XX/setup.c index 4f0a6357af6d4d..ceaaf244020a24 100644 --- a/arch/metag/boards/TZ1090-01XX/setup.c +++ b/arch/metag/boards/TZ1090-01XX/setup.c @@ -93,35 +93,13 @@ static int __init comet_01xx_init_usb(void) return 0; } -/* Allocate all SDIO GPIOs and drive them low. */ -static struct gpio sd_temp_gpios[] = { - { GPIO_SDIO_CMD, GPIOF_OUT_INIT_LOW, "SDIO_CMD"}, - { GPIO_SDIO_CLK, GPIOF_OUT_INIT_LOW, "SDIO_CLK"}, - { GPIO_SDIO_D0, GPIOF_OUT_INIT_LOW, "SDIO_D<0>"}, - { GPIO_SDIO_D1, GPIOF_OUT_INIT_LOW, "SDIO_D<1>"}, - { GPIO_SDIO_D2, GPIOF_OUT_INIT_LOW, "SDIO_D<2>"}, - { GPIO_SDIO_D3, GPIOF_OUT_INIT_LOW, "SDIO_D<3>"}, -}; - /* - * Toggle the power by switching off the power line, and driving the SD pins - * low to ensure it switches off. NB switch only on rev2 onwards. + * Toggle the power by switching off the power line. NB switch only on rev2 + * onwards. */ static void mci_setpower(u32 slot_id, u32 volt) { - int err; - if (volt) { - gpio_free_array(sd_temp_gpios, ARRAY_SIZE(sd_temp_gpios)); - - gpio_set_value(GPIO_PDC_GPIO0, 1); - } else { - gpio_set_value(GPIO_PDC_GPIO0, 0); - - err = gpio_request_array(sd_temp_gpios, - ARRAY_SIZE(sd_temp_gpios)); - if (err) - pr_warn("SDIO pins already allocated. Can not pull low.\n"); - } + gpio_set_value(GPIO_PDC_GPIO0, volt); } /* diff --git a/arch/metag/include/asm/barrier.h b/arch/metag/include/asm/barrier.h index c90bfc6bf64892..e355a4c10968ee 100644 --- a/arch/metag/include/asm/barrier.h +++ b/arch/metag/include/asm/barrier.h @@ -15,6 +15,7 @@ static inline void wr_fence(void) volatile int *flushptr = (volatile int *) LINSYSEVENT_WR_FENCE; barrier(); *flushptr = 0; + barrier(); } #else /* CONFIG_METAG_META21 */ @@ -35,6 +36,7 @@ static inline void wr_fence(void) *flushptr = 0; *flushptr = 0; *flushptr = 0; + barrier(); } #endif /* !CONFIG_METAG_META21 */ @@ -68,6 +70,7 @@ static inline void fence(void) volatile int *flushptr = (volatile int *) LINSYSEVENT_WR_ATOMIC_UNLOCK; barrier(); *flushptr = 0; + barrier(); } #define smp_mb() fence() #define smp_rmb() fence() diff --git a/arch/metag/include/asm/processor.h b/arch/metag/include/asm/processor.h index f16477d1f571cb..3be8581af4956a 100644 --- a/arch/metag/include/asm/processor.h +++ b/arch/metag/include/asm/processor.h @@ -22,6 +22,8 @@ /* Add an extra page of padding at the top of the stack for the guard page. */ #define STACK_TOP (TASK_SIZE - PAGE_SIZE) #define STACK_TOP_MAX STACK_TOP +/* Maximum virtual space for stack */ +#define STACK_SIZE_MAX (1 << 28) /* 256 MB */ /* This decides where the kernel will search for a free chunk of vm * space during mmap's. diff --git a/arch/metag/include/asm/soc-tz1090/defs.h b/arch/metag/include/asm/soc-tz1090/defs.h index 4241405cdf0a82..2c538997a9533b 100644 --- a/arch/metag/include/asm/soc-tz1090/defs.h +++ b/arch/metag/include/asm/soc-tz1090/defs.h @@ -387,6 +387,8 @@ #define CR_TOP_CLKOUT1_3_EN_BIT 9 #define CR_TOP_CLKOUT0_3_EN_BIT 5 /* CR_TOP_SYSPLL_CTL1 */ +#define CR_TOP_SYSPLL_RESET_BIT 28 +#define CR_TOP_SYSPLL_FASTEN_BIT 27 #define CR_TOP_SYSPLL_PWRDN_BIT 24 /* CR_TOP_ADCPLL_CTL0 */ #define CR_TOP_ADCPLL_BWADJ_SHIFT 20 diff --git a/arch/metag/include/asm/tbx.h b/arch/metag/include/asm/tbx.h index 287b36ff8ad1cf..703b9cb0ac5c13 100644 --- a/arch/metag/include/asm/tbx.h +++ b/arch/metag/include/asm/tbx.h @@ -150,11 +150,9 @@ #else /* Reserved 0x04-0x09 */ #endif -#define TBID_SIGNUM_SWS 0x0A /* KICK received with SigMask != 0 */ -#define TBID_SIGNUM_SWK 0x0B /* KICK received with SigMask == 0 */ -/* Reserved 0x0C-0x0F */ +/* Reserved 0x0A-0x0F */ #define TBID_SIGNUM_TRT 0x10 /* Timer trigger */ -#define TBID_SIGNUM_LWK 0x11 /* Low level kick (handler provided by TBI) */ +#define TBID_SIGNUM_LWK 0x11 /* Low level kick */ #define TBID_SIGNUM_XXF 0x12 /* Fault handler - receives ALL _xxF sigs */ #ifdef TBI_1_4 #define TBID_SIGNUM_DFR 0x13 /* Deferred Exception handler */ @@ -183,8 +181,7 @@ each hardware signal, sometimes this is a many-to-one relationship. */ #define TBI_TRIG_BIT(SigNum) (\ ((SigNum) >= TBID_SIGNUM_TRT) ? 1<<((SigNum)-TBID_SIGNUM_TRT) :\ - ( ((SigNum) == TBID_SIGNUM_SWS) || \ - ((SigNum) == TBID_SIGNUM_SWK) ) ? \ + ((SigNum) == TBID_SIGNUM_LWK) ? \ TXSTAT_KICK_BIT : TXSTATI_BGNDHALT_BIT ) /* Return the hardware trigger vector number for entries in the @@ -687,10 +684,8 @@ typedef union _tbires_tag_ { Triggers will indicate the status of TXSTAT or TXSTATI sampled by the code that called the handler. - InstOrSWSId is defined firstly as 'Inst' if the SigNum is TBID_SIGNUM_SWx - and hold the actual SWITCH instruction detected, secondly if SigNum - is TBID_SIGNUM_SWS the 'SWSId' is defined to hold the Id of the - software signal detected, in other cases the value of this + Inst is defined as 'Inst' if the SigNum is TBID_SIGNUM_SWx and holds the + actual SWITCH instruction detected, in other cases the value of this parameter is undefined. pTBI points at the PTBI structure related to the thread and processing @@ -709,7 +704,7 @@ typedef union _tbires_tag_ { */ typedef TBIRES (*PTBIAPIFN)( TBIRES State, int SigNum, - int Triggers, int InstOrSWSId, + int Triggers, int Inst, volatile struct _tbi_tag_ *pTBI ); #endif /* ifndef __ASSEMBLY__ */ @@ -757,7 +752,7 @@ typedef volatile struct _tbi_tag_ { #ifndef __ASSEMBLY__ /* This handler should be used for TBID_SIGNUM_DFR */ extern TBIRES __TBIHandleDFR ( TBIRES State, int SigNum, - int Triggers, int InstOrSWSId, + int Triggers, int Inst, volatile struct _tbi_tag_ *pTBI ); #endif #endif diff --git a/arch/metag/include/uapi/asm/Kbuild b/arch/metag/include/uapi/asm/Kbuild index 84e09feb4d546f..ab78be2b6eb050 100644 --- a/arch/metag/include/uapi/asm/Kbuild +++ b/arch/metag/include/uapi/asm/Kbuild @@ -4,11 +4,11 @@ include include/uapi/asm-generic/Kbuild.asm header-y += byteorder.h header-y += ech.h header-y += ptrace.h -header-y += resource.h header-y += sigcontext.h header-y += siginfo.h header-y += swab.h header-y += unistd.h generic-y += mman.h +generic-y += resource.h generic-y += setup.h diff --git a/arch/metag/include/uapi/asm/resource.h b/arch/metag/include/uapi/asm/resource.h deleted file mode 100644 index 526d23cc30544a..00000000000000 --- a/arch/metag/include/uapi/asm/resource.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _UAPI_METAG_RESOURCE_H -#define _UAPI_METAG_RESOURCE_H - -#define _STK_LIM_MAX (1 << 28) -#include <asm-generic/resource.h> - -#endif /* _UAPI_METAG_RESOURCE_H */ diff --git a/arch/metag/kernel/coremem.c b/arch/metag/kernel/coremem.c index 22b4d8ed0b06bd..236c6bdb7deaeb 100644 --- a/arch/metag/kernel/coremem.c +++ b/arch/metag/kernel/coremem.c @@ -128,26 +128,41 @@ unsigned long metag_cache_lock(unsigned int flags, unsigned long phys, return 0; } - /* First take account of offset of memory in page */ - offset = offset_in_page(phys); - rounded_size = size + offset; + /* Round down the physical address to a cache line boundary */ + offset = phys & (DCACHE_LINE_BYTES - 1); phys -= offset; ccr += offset; + size += offset; + /* Round up the size to a cache line boundary */ + size = (size + (DCACHE_LINE_BYTES - 1)) & -DCACHE_LINE_BYTES; + + /* The size of the current global cache partition may be limited too */ + if (size > ((flags & METAG_COREMEM_IMEM) + ? get_global_icache_size() + : get_global_dcache_size())) + return 0; + + /* + * The physical address must be size aligned, so the size we choose + * depends on what boundaries the region crosses. + * A simple XOR will show which power of 2 boundaries the region + * crosses. + */ + rounded_size_sh = ilog2(phys ^ (phys + size - 1)) + 1; + if (rounded_size_sh < MMCU_TnCCM_REGSZ0_POWER) + rounded_size_sh = MMCU_TnCCM_REGSZ0_POWER; + rounded_size = 1 << rounded_size_sh; + rounded_size_sh -= MMCU_TnCCM_REGSZ0_POWER; - /* Get rounded up log2 of size */ - rounded_size_sh = ilog2((rounded_size<<1)-1) - MMCU_TnCCM_REGSZ0_POWER; - if (rounded_size_sh < 0) - rounded_size_sh = 0; - rounded_size = (1 << MMCU_TnCCM_REGSZ0_POWER) << rounded_size_sh; /* There's a maximum amount of lockable cache */ if (rounded_size > MMCU_TnCCM_REGSZ_MAXBYTES) return 0; - /* The size of the current global cache partition may be limited too */ - if (rounded_size > ((flags & METAG_COREMEM_IMEM) - ? get_global_icache_size() - : get_global_dcache_size())) - return 0; + + /* First take account of offset of memory in page */ + offset = phys & (rounded_size - 1); + phys -= offset; + ccr += offset; ccmctrl = metag_in32(ccmctrl_addr); if (ccmctrl & MMCU_TnCCM_ENABLE_BIT) diff --git a/arch/metag/kernel/dma.c b/arch/metag/kernel/dma.c index 300feb523a3dab..26a33d7651cbd8 100644 --- a/arch/metag/kernel/dma.c +++ b/arch/metag/kernel/dma.c @@ -402,11 +402,6 @@ static int __init dma_alloc_init(void) pgd = pgd_offset(&init_mm, CONSISTENT_START); pud = pud_alloc(&init_mm, pgd, CONSISTENT_START); pmd = pmd_alloc(&init_mm, pud, CONSISTENT_START); - if (!pmd) { - pr_err("%s: no pmd tables\n", __func__); - ret = -ENOMEM; - break; - } WARN_ON(!pmd_none(*pmd)); pte = pte_alloc_kernel(pmd, CONSISTENT_START); diff --git a/arch/metag/kernel/setup.c b/arch/metag/kernel/setup.c index 895c8d07441764..14085002337731 100644 --- a/arch/metag/kernel/setup.c +++ b/arch/metag/kernel/setup.c @@ -319,13 +319,9 @@ void __init setup_arch(char **cmdline_p) * rather than the version from the bootloader. This makes call * stacks easier to understand and may allow us to unmap the * bootloader at some point. - * - * We need to keep the LWK handler that TBI installed in order to - * be able to do inter-thread comms. */ for (i = 0; i <= TBID_SIGNUM_MAX; i++) - if (i != TBID_SIGNUM_LWK) - _pTBI->fnSigs[i] = __TBIUnExpXXX; + _pTBI->fnSigs[i] = __TBIUnExpXXX; /* A Meta requirement is that the kernel is loaded (virtually) * at the PAGE_OFFSET. diff --git a/arch/metag/kernel/traps.c b/arch/metag/kernel/traps.c index fab50e3a5c578e..cb338bcdc0f91a 100644 --- a/arch/metag/kernel/traps.c +++ b/arch/metag/kernel/traps.c @@ -1210,8 +1210,7 @@ void __cpuinit per_cpu_trap_init(unsigned long cpu) set_trigger_mask(TBI_INTS_INIT(thread) | /* interrupts */ TBI_TRIG_BIT(TBID_SIGNUM_LWK) | /* low level kick */ - TBI_TRIG_BIT(TBID_SIGNUM_SW1) | - TBI_TRIG_BIT(TBID_SIGNUM_SWS)); + TBI_TRIG_BIT(TBID_SIGNUM_SW1)); /* non-priv - use current stack */ int_context.Sig.pCtx = NULL; @@ -1254,14 +1253,14 @@ void __init trap_init(void) _pTBI->fnSigs[TBID_SIGNUM_SW1] = switch1_wrapper; _pTBI->fnSigs[TBID_SIGNUM_SW2] = switchx_wrapper; _pTBI->fnSigs[TBID_SIGNUM_SW3] = switchx_wrapper; - _pTBI->fnSigs[TBID_SIGNUM_SWK] = kick_wrapper; + _pTBI->fnSigs[TBID_SIGNUM_LWK] = kick_wrapper; #else _pTBI->fnSigs[TBID_SIGNUM_XXF] = fault_handler; _pTBI->fnSigs[TBID_SIGNUM_SW0] = switchx_handler; _pTBI->fnSigs[TBID_SIGNUM_SW1] = switch1_handler; _pTBI->fnSigs[TBID_SIGNUM_SW2] = switchx_handler; _pTBI->fnSigs[TBID_SIGNUM_SW3] = switchx_handler; - _pTBI->fnSigs[TBID_SIGNUM_SWK] = kick_handler; + _pTBI->fnSigs[TBID_SIGNUM_LWK] = kick_handler; #endif #ifdef CONFIG_METAG_META21 diff --git a/arch/metag/mm/numa.c b/arch/metag/mm/numa.c index 9ae578c9b620b5..b172aa45fcf820 100644 --- a/arch/metag/mm/numa.c +++ b/arch/metag/mm/numa.c @@ -34,7 +34,7 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end) unsigned long pgdat_paddr; /* Don't allow bogus node assignment */ - BUG_ON(nid > MAX_NUMNODES || nid <= 0); + BUG_ON(nid >= MAX_NUMNODES || nid <= 0); start_pfn = start >> PAGE_SHIFT; end_pfn = end >> PAGE_SHIFT; diff --git a/arch/metag/soc/tz1090/suspend.S b/arch/metag/soc/tz1090/suspend.S index 6599f53e40f4ab..764d203ba9e552 100644 --- a/arch/metag/soc/tz1090/suspend.S +++ b/arch/metag/soc/tz1090/suspend.S @@ -1,4 +1,4 @@ -! Copyright 2010 Imagination Technologies Ltd. +! Copyright 2010-2014 Imagination Technologies Ltd. ! ! Functions for suspending the comet SoC. @@ -130,8 +130,7 @@ ENTRY(_metag_comet_standby) MOVT D0FrT, #HI(CR_TOP_SYSPLL_CTL1) ADD D0FrT, D0FrT, #LO(CR_TOP_SYSPLL_CTL1) GETD D0Ar6, [D0FrT] - MOVT D0Ar4, #HI(1 << CR_TOP_SYSPLL_PWRDN_BIT) - OR D0Ar6, D0Ar6, D0Ar4 + ORT D0Ar6, D0Ar6, #HI(1 << CR_TOP_SYSPLL_PWRDN_BIT) SETD [D0FrT], D0Ar6 #endif #endif @@ -162,17 +161,30 @@ ENTRY(_metag_comet_standby) #endif #ifdef META_PLL_BYPASS - ! power up the PLL + ! power up the PLL, assert reset, and allow time to lock on #ifdef META_PLL_PWRDN - ! CR_TOP_SYSPLL_CTL1 ^= (1 << CR_TOP_SYSPLL_PWRDN_BIT) MOVT D0FrT, #HI(CR_TOP_SYSPLL_CTL1) ADD D0FrT, D0FrT, #LO(CR_TOP_SYSPLL_CTL1) GETD D0Ar6, [D0FrT] - MOVT D0Ar4, #HI(1 << CR_TOP_SYSPLL_PWRDN_BIT) - XOR D0Ar6, D0Ar6, D0Ar4 + ! CR_TOP_SYSPLL_CTL1 ^= PWRDN_BIT (clear) | RESET (set) + XORT D0Ar6, D0Ar6, #HI((1 << CR_TOP_SYSPLL_PWRDN_BIT) | \ + (1 << CR_TOP_SYSPLL_RESET_BIT)) + SETD [D0FrT], D0Ar6 + ! wait for min 5uS reset pulse (max XTAL1 = 40MHz, 5uS = 200 cycles) + MPAUSE 2 + ! CR_TOP_SYSPLL_CTL1 &= ~RESET + ANDMT D0Ar6, D0Ar6, #HI(~(1 << CR_TOP_SYSPLL_RESET_BIT)) + ! CR_TOP_SYSPLL_CTL1 |= FASTEN + ORT D0Ar6, D0Ar6, #HI(1 << CR_TOP_SYSPLL_FASTEN_BIT) SETD [D0FrT], D0Ar6 ! wait for PLL to power back up and sort itself out - MPAUSE 2000 + ! May require up to 500 divided rclk cycles (assume divided XTAL1) + ! Max divider = 64, Meta clocked off XTAL1 too + ! Delay = 500*64 = 32000 cycles + MPAUSE 320 + ! CR_TOP_SYSPLL_CTL1 &= ~FASTEN + ANDMT D0Ar6, D0Ar6, #HI(~(1 << CR_TOP_SYSPLL_FASTEN_BIT)) + SETD [D0FrT], D0Ar6 #endif ! Switch system clock back to PLL diff --git a/arch/metag/tbx/tbidefr.S b/arch/metag/tbx/tbidefr.S index 3eb165ebf5408a..8f0902b22f7034 100644 --- a/arch/metag/tbx/tbidefr.S +++ b/arch/metag/tbx/tbidefr.S @@ -20,7 +20,7 @@ /* D1Ar1:D0Ar2 -- State * D0Ar3 -- SigNum * D0Ar4 -- Triggers - * D1Ar5 -- InstOrSWSId + * D1Ar5 -- Inst * D0Ar6 -- pTBI (volatile) */ ___TBIHandleDFR: diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h index cc2290a3cace1e..c6ee86542fecb7 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h @@ -53,6 +53,8 @@ #define STACK_TOP TASK_SIZE #define STACK_TOP_MAX DEFAULT_TASK_SIZE +#define STACK_SIZE_MAX (1 << 30) /* 1 GB */ + #endif #ifndef __ASSEMBLY__ diff --git a/drivers/clk/clk-specified-rate.c b/drivers/clk/clk-specified-rate.c index 8f7803331bb613..c276a9daf485ea 100644 --- a/drivers/clk/clk-specified-rate.c +++ b/drivers/clk/clk-specified-rate.c @@ -163,7 +163,7 @@ void __init of_specified_clk_setup(struct device_node *node) __func__, clk_name, len); goto err_iounmap; } - num_rates = len / (sizeof(*rates)*2); + num_rates = len / sizeof(*rates); rates = kzalloc(sizeof(*rates)*num_rates, GFP_KERNEL); if (!rates) { diff --git a/drivers/clk/metag/clk-mux.c b/drivers/clk/metag/clk-mux.c index 0d3096d1e4ec21..868a1f45c42316 100644 --- a/drivers/clk/metag/clk-mux.c +++ b/drivers/clk/metag/clk-mux.c @@ -172,7 +172,7 @@ static void __init of_metag_mux_clk_setup(struct device_node *node) if (!parent_names) { pr_err("%s(%s): could not allocate %u parent names\n", __func__, clk_name, num_parents); - goto err_kfree; + goto out_kfree; } /* fill in the parent names */ @@ -190,7 +190,7 @@ static void __init of_metag_mux_clk_setup(struct device_node *node) if (default_clock >= num_parents) { pr_err("%s(%s): default-clock %u out of range (%u bits)\n", __func__, clk_name, default_clock, width); - goto err_kfree; + goto out_kfree; } } else { default_clock = -1; @@ -200,7 +200,7 @@ static void __init of_metag_mux_clk_setup(struct device_node *node) if (!reg) { pr_err("%s(%s): of_iomap failed\n", __func__, clk_name); - goto err_kfree; + goto out_kfree; } if (of_find_property(node, "linux,clk-set-rate-parent", NULL)) @@ -217,11 +217,12 @@ static void __init of_metag_mux_clk_setup(struct device_node *node) of_clk_add_provider(node, of_clk_src_simple_get, clk); - return; + /* parent_names is copied by clk_register(), so it can now be freed */ + goto out_kfree; err_iounmap: iounmap(reg); -err_kfree: +out_kfree: kfree(parent_names); } CLK_OF_DECLARE(metag_mux_clk, "img,meta-mux-clock", of_metag_mux_clk_setup); diff --git a/drivers/clk/tz1090/clk-tz1090-pll.c b/drivers/clk/tz1090/clk-tz1090-pll.c index 1447f3161ae160..c48b948a44b79a 100644 --- a/drivers/clk/tz1090/clk-tz1090-pll.c +++ b/drivers/clk/tz1090/clk-tz1090-pll.c @@ -199,14 +199,16 @@ static int clk_tz1090_pll_set_rate(struct clk_hw *hw, unsigned long rate, /* allow 5us after clkf before deasserting reset */ udelay(5); - /* take PLL out of reset */ + /* take PLL out of reset and enable fasten */ ctl1 &= ~PLL_CTL1_RESET_B; + ctl1 |= PLL_CTL1_FASTEN_B; writel(ctl1, pll->reg + PLL_CTL1); /* count at least 500 divided ref clks to allow time to lock */ msleep(1 + 500*1000*(clkr+1)/parent_rate); - /* take PLL out of bypass */ + /* take PLL out of fasten / bypass */ + ctl1 &= ~PLL_CTL1_FASTEN_B; ctl1 &= ~PLL_CTL1_BYPASS_B; writel(ctl1, pll->reg + PLL_CTL1); diff --git a/drivers/dma/img_mdc_dma.c b/drivers/dma/img_mdc_dma.c index f49fbae4d70679..fc2ee217f29820 100644 --- a/drivers/dma/img_mdc_dma.c +++ b/drivers/dma/img_mdc_dma.c @@ -53,6 +53,7 @@ struct mdc_chan { /* List of current DMA descriptors */ struct list_head active_desc; /* Active descriptors */ struct list_head free_desc; /* Used descriptors */ + struct list_head ready_desc; bool sg; /* true for sg xfer */ bool cyclic; /* true for cyclic xfer */ bool is_list; /* list-based xfer */ @@ -90,6 +91,7 @@ struct mdc_dma_desc { int buffer_size; int sample_size; int sample_count; + bool irq_acked; }; /* Forward declaration for dma driver */ @@ -317,7 +319,7 @@ static void img_dma_reset(struct mdc_chan *mchan) /*thread id used in tag for reads*/ MDC_SET_FIELD(rpconf, MDC_RTHREAD, mchan->thread); /*thread id used in tag for writes*/ - MDC_SET_FIELD(rpconf, MDC_STHREAD, mchan->thread); + MDC_SET_FIELD(rpconf, MDC_WTHREAD, mchan->thread); /*priority of transfers*/ MDC_SET_FIELD(rpconf, MDC_PRIORITY, mchan->priority); @@ -348,6 +350,7 @@ static irqreturn_t mdc_handler_isr(int irq, void *chan_id) u32 irq_status; struct mdc_chan *mchan = chan_id; + struct mdc_dma_desc *desc; spin_lock(&mchan->lock); @@ -361,11 +364,19 @@ static irqreturn_t mdc_handler_isr(int irq, void *chan_id) mchan->mdma->base_addr, mchan->a_chan_nr, 0); /* Skip tasklet? */ - if (mchan->skip_callback) + if (mchan->skip_callback) { mchan->skip_callback = false; - else + } else { + list_for_each_entry(desc, &mchan->active_desc, node) { + if (!desc->irq_acked || mchan->cyclic) { + desc->sample_count++; + desc->irq_acked = true; + break; + } + } /* Schedule the tasklet */ tasklet_schedule(&mchan->tasklet); + } } spin_unlock(&mchan->lock); @@ -383,10 +394,8 @@ static irqreturn_t mdc_handler_isr(int irq, void *chan_id) static void mdc_dma_tasklet(unsigned long data) { struct mdc_chan *mchan = (struct mdc_chan *)data; - struct mdc_dma_desc *desc; + struct mdc_dma_desc *desc, *safe; unsigned long flags; - dma_async_tx_callback callback = NULL; - void *param = NULL; spin_lock_irqsave(&mchan->lock, flags); if (list_empty(&mchan->active_desc)) { @@ -394,24 +403,48 @@ static void mdc_dma_tasklet(unsigned long data) return; } - desc = list_first_entry(&mchan->active_desc, typeof(*desc), node); - if (++desc->sample_count == desc->total_samples) { - desc->sample_count = 0; - mchan->finished = true; - /* For cyclic, this descriptor will remain active */ - if (!mchan->cyclic) - /* Move it back to the free list */ - list_move_tail(&desc->node, &mchan->free_desc); - } - if (desc->txd.callback) { - callback = desc->txd.callback; - param = desc->txd.callback_param; + list_for_each_entry_safe(desc, safe, &mchan->active_desc, node) { + dev_vdbg(mchan2dev(mchan), + "Tasklet descriptor\n" + "Address : 0x%p\n" + "Sample count : %d\n" + "Total count : %d\n" + "Acked : %d\n", + desc, desc->sample_count, desc->total_samples, + desc->irq_acked); + if (desc->sample_count >= desc->total_samples) { + if (desc->irq_acked) { + desc->sample_count = 0; + mchan->finished = true; + desc->irq_acked = false; + } + /* + * Move it to the ready list. + * For cyclic we keep it active. + */ + if (!mchan->cyclic) + list_move_tail(&desc->node, &mchan->ready_desc); + } } spin_unlock_irqrestore(&mchan->lock, flags); - /* We are safe to call the callback now */ - if (callback) - callback(param); + /* + * If cyclic, that means we only have one descriptor so get it and + * see if there is a callback to call now + */ + if (mchan->cyclic) { + desc = list_first_entry(&mchan->active_desc, typeof(*desc), node); + if (desc->txd.callback) + desc->txd.callback(desc->txd.callback_param); + } else { + list_for_each_entry_safe(desc, safe, &mchan->ready_desc, node) { + if (desc->txd.callback) + desc->txd.callback(desc->txd.callback_param); + async_tx_ack(&desc->txd); + /* Move it back to the free list */ + list_move_tail(&desc->node, &mchan->free_desc); + } + } } /* @@ -430,7 +463,7 @@ static dma_cookie_t mdc_dma_tx_submit(struct dma_async_tx_descriptor *txd) cookie = dma_cookie_assign(&dma_desc->txd); dma_desc->status = DMA_IN_PROGRESS; /* Add descriptor to active list */ - list_add(&dma_desc->node, &mchan->active_desc); + list_add_tail(&dma_desc->node, &mchan->active_desc); spin_unlock_irqrestore(&mchan->lock, flags); @@ -537,7 +570,7 @@ static struct mdc_dma_desc *mdc_dma_get_desc(struct mdc_chan *chan, } /* We couldn't find a suitable descriptor */ spin_unlock_irqrestore(&chan->lock, irq_flags); - desc = kzalloc(sizeof(*desc), GFP_KERNEL); + desc = kzalloc(sizeof(*desc), GFP_ATOMIC); if (!desc) { dev_err(mchan2dev(chan), "Failed to allocate DMA descriptor\n"); @@ -638,6 +671,7 @@ static struct dma_async_tx_descriptor *mdc_prep_memcpy(struct dma_chan *chan, mchan->is_list = false; mchan->cyclic = false; /* tx defaults for tx_status. single transfer */ + mdesc->irq_acked = false; mdesc->sample_count = 0; mdesc->sample_size = 1; mdesc->total_samples = mdesc->buffer_size = 1; @@ -720,6 +754,7 @@ static struct dma_async_tx_descriptor *mdc_prep_dma_cyclic( if (!mdesc) return NULL; + mdesc->irq_acked = false; mdesc->sample_count = 0; mdesc->total_samples = 0; mdesc->sample_size = period_len; @@ -825,6 +860,8 @@ static struct dma_async_tx_descriptor *mdc_prep_slave_sg( struct img_dma_mdc_list *desc_list; dma_addr_t list_base, next_list, addr; int i, width, temp, burst_size_min, burst_size, req_width; + u32 genconf, rpconf; + dma_addr_t dst, src; u32 len; if (unlikely(!sg_len || !sgl || !mchan)) @@ -838,8 +875,10 @@ static struct dma_async_tx_descriptor *mdc_prep_slave_sg( if (!mdesc) return NULL; - mchan->is_list = true; + mchan->is_list = (sg_len > 1); + mchan->cyclic = false; mchan->sg = true; + mdesc->irq_acked = false; mdesc->sample_count = 0; mdesc->sample_size = 1; /* single list item */ mdesc->total_samples = mdesc->buffer_size = sg_len; @@ -866,81 +905,136 @@ static struct dma_async_tx_descriptor *mdc_prep_slave_sg( img_dma_reset(mchan); - /* This is for the MDC linked-list */ - desc_list = (struct img_dma_mdc_list *)mchan->virt_addr; - mdesc->start_list = list_base = next_list = mchan->dma_addr; - - /* Hand back the DMA buffer to the CPU */ - dma_sync_single_for_cpu(mchan->mdma->dma_slave.dev, - mchan->dma_addr, - PAGE_SIZE, DMA_BIDIRECTIONAL); - burst_size_min = burst_size_lookup[mdma->config.bus_width & 0x7]; - for_each_sg(sgl, sg, sg_len, i) { - /* - * Each list item is a 32-byte packet represented by the - * img_dma_mdc_list struct. Every member of that struct - * corresponds to the channel register - */ - next_list += sizeof(struct img_dma_mdc_list); - len = sg_dma_len(sg); - addr = sg_dma_address(sg); + if (!mchan->is_list) { + len = sg_dma_len(sgl); + addr = sg_dma_address(sgl); width = check_widths(mchan->mdma, addr); - desc_list->gen_conf = 0x30000088 + genconf = 0x30000088 | ((mchan->a_chan_nr & 0x3f) << 20) | ((mchan->access_delay & 0x7) << 16); temp = (mchan->thread & 0xf); - desc_list->readport_conf = 0x00000002 | temp << 2 + rpconf = 0x00000002 | temp << 2 | temp << 24 | temp << 16; - MDC_SET_FIELD(desc_list->readport_conf, MDC_PRIORITY, + MDC_SET_FIELD(rpconf, MDC_PRIORITY, mchan->priority); if (direction == DMA_MEM_TO_DEV) { - MDC_SET_FIELD(desc_list->gen_conf, MDC_INC_R, 1); - MDC_SET_FIELD(desc_list->gen_conf, MDC_WIDTH_R, width); + MDC_SET_FIELD(genconf, MDC_INC_R, 1); + MDC_SET_FIELD(genconf, MDC_WIDTH_R, width); req_width = mchan->dma_config.dst_addr_width; - MDC_SET_FIELD(desc_list->gen_conf, MDC_WIDTH_W, + MDC_SET_FIELD(genconf, MDC_WIDTH_W, map_to_mdc_width(req_width)); - desc_list->read_addr = addr; - desc_list->write_addr = mchan->dma_config.dst_addr; + src = addr; + dst = mchan->dma_config.dst_addr; burst_size = mchan->dma_config.dst_maxburst; - desc_list->readport_conf |= - (burst_size < burst_size_min) - ? (burst_size_min - 1) << 4 - : (burst_size - 1) << 4; } else { - MDC_SET_FIELD(desc_list->gen_conf, MDC_INC_W, 1); - MDC_SET_FIELD(desc_list->gen_conf, MDC_WIDTH_W, width); + MDC_SET_FIELD(genconf, MDC_INC_W, 1); + MDC_SET_FIELD(genconf, MDC_WIDTH_W, width); req_width = mchan->dma_config.src_addr_width; - MDC_SET_FIELD(desc_list->gen_conf, MDC_WIDTH_R, + MDC_SET_FIELD(genconf, MDC_WIDTH_R, map_to_mdc_width(req_width)); - desc_list->read_addr = mchan->dma_config.src_addr; - desc_list->write_addr = addr; + src = mchan->dma_config.src_addr; + dst = addr; burst_size = mchan->dma_config.src_maxburst; + } + rpconf |= (burst_size < burst_size_min) + ? (burst_size_min - 1) << 4 + : (burst_size - 1) << 4; + + /* Write the single sg entry to hardware */ + MDC_RSET_READ_ADDRESS((unsigned long)mchan->mdma->base_addr, + mchan->a_chan_nr, src); + MDC_RSET_WRITE_ADDRESS((unsigned long)mchan->mdma->base_addr, + mchan->a_chan_nr, dst); + MDC_RSET_GENERAL_CONFIG((unsigned long)mchan->mdma->base_addr, + mchan->a_chan_nr, genconf); + MDC_RSET_READ_PORT_CONFIG((unsigned long)mchan->mdma->base_addr, + mchan->a_chan_nr, rpconf); + MDC_RSET_TRANSFER_SIZE((unsigned long)mchan->mdma->base_addr, + mchan->a_chan_nr, len - 1); + wmb(); + + } else { + /* This is for the MDC linked-list */ + desc_list = (struct img_dma_mdc_list *)mchan->virt_addr; + mdesc->start_list = list_base = next_list = mchan->dma_addr; + + /* Hand back the DMA buffer to the CPU */ + dma_sync_single_for_cpu(mchan->mdma->dma_slave.dev, + mchan->dma_addr, + PAGE_SIZE, DMA_BIDIRECTIONAL); + + for_each_sg(sgl, sg, sg_len, i) { + /* + * Each list item is a 32-byte packet represented by the + * img_dma_mdc_list struct. Every member of that struct + * corresponds to the channel register + */ + next_list += sizeof(struct img_dma_mdc_list); + len = sg_dma_len(sg); + addr = sg_dma_address(sg); + width = check_widths(mchan->mdma, addr); + desc_list->gen_conf = 0x30000088 + | ((mchan->a_chan_nr & 0x3f) << 20) + | ((mchan->access_delay & 0x7) << 16); + + temp = (mchan->thread & 0xf); + desc_list->readport_conf = 0x00000002 | temp << 2 + | temp << 24 | temp << 16; + + MDC_SET_FIELD(desc_list->readport_conf, MDC_PRIORITY, + mchan->priority); + + if (direction == DMA_MEM_TO_DEV) { + MDC_SET_FIELD(desc_list->gen_conf, MDC_INC_R, + 1); + MDC_SET_FIELD(desc_list->gen_conf, MDC_WIDTH_R, + width); + req_width = mchan->dma_config.dst_addr_width; + MDC_SET_FIELD(desc_list->gen_conf, MDC_WIDTH_W, + map_to_mdc_width(req_width)); + desc_list->read_addr = addr; + desc_list->write_addr = + mchan->dma_config.dst_addr; + burst_size = mchan->dma_config.dst_maxburst; + } else { + MDC_SET_FIELD(desc_list->gen_conf, MDC_INC_W, + 1); + MDC_SET_FIELD(desc_list->gen_conf, MDC_WIDTH_W, + width); + req_width = mchan->dma_config.src_addr_width; + MDC_SET_FIELD(desc_list->gen_conf, MDC_WIDTH_R, + map_to_mdc_width(req_width)); + desc_list->read_addr = + mchan->dma_config.src_addr; + desc_list->write_addr = addr; + burst_size = mchan->dma_config.src_maxburst; + } desc_list->readport_conf |= (burst_size < burst_size_min) ? (burst_size_min - 1) << 4 : (burst_size - 1) << 4; - } - desc_list->xfer_size = len - 1; - desc_list->node_addr = next_list; - desc_list->cmds_done = 0; - desc_list->ctrl_status = 0x11; + desc_list->xfer_size = len - 1; + desc_list->node_addr = next_list; + desc_list->cmds_done = 0; + desc_list->ctrl_status = 0x11; - desc_list++; - } + desc_list++; + } - desc_list[-1].node_addr = 0; + desc_list[-1].node_addr = 0; - /* we are done with the DMA buffer, give it back to the device */ - dma_sync_single_for_device(mchan->mdma->dma_slave.dev, - mchan->dma_addr, - PAGE_SIZE, - DMA_BIDIRECTIONAL); + /* we are done with the DMA buffer, give it back to the device */ + dma_sync_single_for_device(mchan->mdma->dma_slave.dev, + mchan->dma_addr, + PAGE_SIZE, + DMA_BIDIRECTIONAL); + } return &mdesc->txd; } @@ -1251,6 +1345,12 @@ static int mdc_terminate_all(struct dma_chan *chan) kfree(desc); } + /* Safe removal of list items */ + list_for_each_entry_safe(desc, safe, &mchan->ready_desc, node) { + list_del(&desc->node); + kfree(desc); + } + /* Reset cookie for this channel */ dma_cookie_init(chan); @@ -1392,7 +1492,9 @@ static void __init mdc_chan_init(struct mdc_dmadev *mdma, mdc_chan->dchan.device = &mdma->dma_slave; mdc_chan->a_chan_nr = i; mdc_chan->periph = 0; - if (i < mdma->config.dma_channels) + spin_lock_init(&mdc_chan->lock); + if ((i < mdma->config.dma_channels) && + (mdma->callbacks->available(i))) mdma->slave_channel[i].alloc_status = IMG_DMA_CHANNEL_AVAILABLE; else @@ -1407,6 +1509,7 @@ static void __init mdc_chan_init(struct mdc_dmadev *mdma, /* init the list of descriptors for this channel */ INIT_LIST_HEAD(&mdc_chan->active_desc); INIT_LIST_HEAD(&mdc_chan->free_desc); + INIT_LIST_HEAD(&mdc_chan->ready_desc); /* Add channel to the DMA channel linked-list */ list_add_tail(&mdc_chan->dchan.device_node, @@ -1437,6 +1540,8 @@ int mdc_dma_probe(struct platform_device *pdev, return -ENOMEM; } + spin_lock_init(&mdma->lock); + mem_resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); mdma->base_addr = devm_request_and_ioremap(dev, mem_resource); if (!mdma->base_addr) { diff --git a/drivers/dma/tz1090-mdc-dma.c b/drivers/dma/tz1090-mdc-dma.c index f0a465703087fd..84c26fe4e7cfd0 100644 --- a/drivers/dma/tz1090-mdc-dma.c +++ b/drivers/dma/tz1090-mdc-dma.c @@ -99,6 +99,10 @@ static void setup_dma_channel(int dmanr, unsigned int periph) __global_unlock2(lstat); } +static int img_is_chan_available(int dmanr) +{ + return dma_channels[dmanr] == IMG_DMA_CHANNEL_AVAILABLE; +} static int img_request_dma(int dmanr, unsigned int periph) { @@ -267,6 +271,7 @@ device_initcall(proc_dma_init); static struct img_mdc_soc_callbacks comet_dma_callbacks = { .allocate = img_request_dma, + .available = img_is_chan_available, .free = img_free_dma, .suspend = img_dma_suspend, .resume = img_dma_resume, diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index 5c42d610a47c8b..0cbf81996716b3 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -492,7 +492,7 @@ int comet_gpio_pullup_type(unsigned int gpio, unsigned int pullup) { struct tz1090_gpio_bank *bank = NULL; struct comet_gpio_pullup *gpio_pullup; - unsigned int offset = 0, value; + unsigned int offset = 0, index, value; int idx; int lstat; @@ -501,15 +501,16 @@ int comet_gpio_pullup_type(unsigned int gpio, unsigned int pullup) if (idx < 0) return -EINVAL; - bank = comet_gpio_chip[idx]; + bank = comet_gpio_chip[0]; gpio_pullup = &gpio_pullup_table[gpio]; + index = gpio_pullup->index << 2; offset = gpio_pullup->offset; __global_lock2(lstat); - value = tz1090_gpio_read(bank, REG_GPIO_PU_PD); + value = tz1090_gpio_read(bank, REG_GPIO_PU_PD + index); value &= ~(0x3 << offset); value |= (pullup & 0x3) << offset; - tz1090_gpio_write(bank, REG_GPIO_PU_PD, value); + tz1090_gpio_write(bank, REG_GPIO_PU_PD + index, value); __global_unlock2(lstat); return 0; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c2534d62911cfd..ff0fd655729f9e 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1214,15 +1214,14 @@ int gpiochip_add(struct gpio_chip *chip) } } + spin_unlock_irqrestore(&gpio_lock, flags); + #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&chip->pin_ranges); #endif of_gpiochip_add(chip); -unlock: - spin_unlock_irqrestore(&gpio_lock, flags); - if (status) goto fail; @@ -1235,6 +1234,9 @@ unlock: chip->label ? : "generic"); return 0; + +unlock: + spin_unlock_irqrestore(&gpio_lock, flags); fail: /* failures here can mean systems won't boot... */ pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n", diff --git a/drivers/i2c/busses/i2c-img.c b/drivers/i2c/busses/i2c-img.c index 4749b113d38ac3..1a0144c127fa8a 100644 --- a/drivers/i2c/busses/i2c-img.c +++ b/drivers/i2c/busses/i2c-img.c @@ -80,7 +80,7 @@ #define INT_TIMING 0x40000 /* level interrupts need clearing after handling instead of before */ -#define INT_LEVEL 0x01e00 +#define INT_LEVEL 0x00600 /* don't allow any interrupts while the clock may be off */ #define INT_ENABLE_MASK_INACTIVE 0x00000 diff --git a/drivers/irqchip/irq-metag-ext.c b/drivers/irqchip/irq-metag-ext.c index 13d9aa8de87c5e..cf3ef3c4a57e36 100644 --- a/drivers/irqchip/irq-metag-ext.c +++ b/drivers/irqchip/irq-metag-ext.c @@ -516,7 +516,7 @@ static int meta_intc_set_affinity(struct irq_data *data, * one cpu (the interrupt code doesn't support it), so we just * pick the first cpu we find in 'cpumask'. */ - cpu = cpumask_any(cpumask); + cpu = cpumask_any_and(cpumask, cpu_online_mask); thread = cpu_2_hwthread_id[cpu]; metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR2(thread)), vec_addr); diff --git a/drivers/irqchip/irq-metag.c b/drivers/irqchip/irq-metag.c index 8e94d7a3b20d27..c16c186d97d35f 100644 --- a/drivers/irqchip/irq-metag.c +++ b/drivers/irqchip/irq-metag.c @@ -201,7 +201,7 @@ static int metag_internal_irq_set_affinity(struct irq_data *data, * one cpu (the interrupt code doesn't support it), so we just * pick the first cpu we find in 'cpumask'. */ - cpu = cpumask_any(cpumask); + cpu = cpumask_any_and(cpumask, cpu_online_mask); thread = cpu_2_hwthread_id[cpu]; metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR1(thread)), diff --git a/drivers/media/rc/ir-img.c b/drivers/media/rc/ir-img.c index b4509aff99012b..de8694f2ae687c 100644 --- a/drivers/media/rc/ir-img.c +++ b/drivers/media/rc/ir-img.c @@ -638,10 +638,12 @@ static void img_ir_set_decoder(struct img_ir_priv *priv, if (ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2)) { ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2); img_ir_write(priv, IMG_IR_STATUS, ir_status); - img_ir_read(priv, IMG_IR_DATA_LW); - img_ir_read(priv, IMG_IR_DATA_UP); } + /* always read data to clear buffer if IR wakes the device */ + img_ir_read(priv, IMG_IR_DATA_LW); + img_ir_read(priv, IMG_IR_DATA_UP); + /* clear the scancode filters */ priv->sc_filter.data = 0; priv->sc_filter.mask = 0; diff --git a/drivers/net/wireless/uccp310wlan/80211_if.c b/drivers/net/wireless/uccp310wlan/80211_if.c index e68ef8df89479f..a5eee74424024f 100644 --- a/drivers/net/wireless/uccp310wlan/80211_if.c +++ b/drivers/net/wireless/uccp310wlan/80211_if.c @@ -45,6 +45,8 @@ #define _80211IF_DEBUG(...) do { } while (0) #endif +extern int reset_hal_params(void); + static char *mac_addr = DEFAULT_MAC_ADDRESS; /* Its value will be the default mac address and it can only be updated with the @@ -149,6 +151,27 @@ static struct ieee80211_supported_band band_5ghz = { .n_bitrates = ARRAY_SIZE(ofdm_rates), }; +static const struct ieee80211_iface_limit if_limit1[] = {{ .max = 4, .types = BIT(NL80211_IFTYPE_STATION)} }; +static const struct ieee80211_iface_limit if_limit2[] = {{ .max = 2, .types = BIT(NL80211_IFTYPE_STATION)} }; +static const struct ieee80211_iface_limit if_limit3[] = {{ .max = 1, .types = BIT(NL80211_IFTYPE_STATION),}, + { .max = 1, .types = BIT(NL80211_IFTYPE_AP)| + BIT(NL80211_IFTYPE_P2P_CLIENT)| + BIT(NL80211_IFTYPE_ADHOC)| + BIT(NL80211_IFTYPE_P2P_GO)} }; +static const struct ieee80211_iface_limit if_limit4[] = {{ .max = 1, .types = BIT(NL80211_IFTYPE_AP)}, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_GO)} }; + +static const struct ieee80211_iface_limit if_limit5[] = {{ .max = 1, .types = BIT(NL80211_IFTYPE_ADHOC)}, + { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT)} }; + +static const struct ieee80211_iface_combination if_comb[] = { + { .limits = if_limit1, .n_limits = ARRAY_SIZE(if_limit1), .max_interfaces = 4, .num_different_channels = 1}, + { .limits = if_limit2, .n_limits = ARRAY_SIZE(if_limit2), .max_interfaces = 2, .num_different_channels = 1}, + { .limits = if_limit3, .n_limits = ARRAY_SIZE(if_limit3), .max_interfaces = 2, .num_different_channels = 1}, + { .limits = if_limit4, .n_limits = ARRAY_SIZE(if_limit4), .max_interfaces = 2, .num_different_channels = 1}, + { .limits = if_limit5, .n_limits = ARRAY_SIZE(if_limit5), .max_interfaces = 2, .num_different_channels = 1} +}; + static int conv_str_to_byte(unsigned char *byte, unsigned char *str, int len) @@ -204,7 +227,7 @@ static unsigned char get_ps_info(unsigned char *ie_data, } static void tx(struct ieee80211_hw *hw, - struct ieee80211_tx_control *control, + struct ieee80211_tx_control *tx_control, struct sk_buff *skb) { struct mac80211_dev *dev = hw->priv; @@ -295,7 +318,7 @@ static int add_interface(struct ieee80211_hw *hw, iftype = vif->type; v = vif; - vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + if (!(iftype == NL80211_IFTYPE_STATION || iftype == NL80211_IFTYPE_ADHOC || iftype == NL80211_IFTYPE_AP)) { @@ -677,18 +700,24 @@ static void sw_scan_start(struct ieee80211_hw *hw) { _80211IF_DEBUG("%s-80211IF: scan started\n", ((struct mac80211_dev *)(hw->priv))->name); - /* - * TODO:: - */ + uccp310wlan_prog_scan_ind(1); } static void sw_scan_complete(struct ieee80211_hw *hw) { + struct mac80211_dev *dev = hw->priv; + struct ieee80211_vif *vif; + int vif_index; + _80211IF_DEBUG("%s-80211IF: scan stopped\n", ((struct mac80211_dev *)(hw->priv))->name); - /* - * TODO:: - */ + if (dev->active_vifs == 1) { + for (vif_index = 0; vif_index < wifi->params.num_vifs; vif_index++) { + vif = (struct ieee80211_vif *)rcu_dereference(dev->vifs[vif_index]); + if (vif && (vif->type == NL80211_IFTYPE_STATION) && (vif->bss_conf.assoc)) + uccp310wlan_prog_scan_ind(0); + } + } } static void init_hw(struct ieee80211_hw *hw) @@ -696,12 +725,19 @@ static void init_hw(struct ieee80211_hw *hw) struct mac80211_dev *dev = (struct mac80211_dev *)hw->priv; /* Supported Interface Types and other Default values*/ hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO); + if (wifi->params.num_vifs > 1) { + hw->wiphy->iface_combinations = if_comb; + hw->wiphy->n_iface_combinations = sizeof(if_comb)/sizeof(struct ieee80211_iface_combination); + } hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS ; /* umac */ hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD; hw->flags |= IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING; hw->flags |= IEEE80211_HW_SUPPORTS_PER_STA_GTK; + hw->flags |= IEEE80211_HW_CONNECTION_MONITOR; + + hw->flags |= IEEE80211_HW_MFP_CAPABLE; hw->max_listen_interval = 10; /* umac */ hw->max_rates = 4; /* umac */ @@ -728,6 +764,8 @@ static void init_hw(struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; + } static struct ieee80211_ops ops = { .tx = tx, @@ -827,6 +865,7 @@ out: static ssize_t proc_read(struct seq_file *m, void *v) { + seq_printf(m, "************* PARAMS ***********\n"); seq_printf(m, "dot11a_support = %d\n", wifi->params.dot11a_support); seq_printf(m, "sensitivity = %d\n", wifi->params.ed_sensitivity); @@ -835,6 +874,7 @@ static ssize_t proc_read(struct seq_file *m, void *v) seq_printf(m, "production_test = %d\n", wifi->params.production_test); seq_printf(m, "show_phy_stats = %d\n", wifi->params.show_phy_stats); seq_printf(m, "num_vifs = %d\n", wifi->params.num_vifs); + seq_printf(m, "max_bcn_loss = %d\n", wifi->params.max_bcn_loss); seq_printf(m, "************* STATS ***********\n"); seq_printf(m, "rx_packet_count = %d\n", wifi->stats.rx_packet_count); if (wifi->params.show_phy_stats) { @@ -896,11 +936,17 @@ static ssize_t proc_read(struct seq_file *m, void *v) seq_printf(m, "\n"); } #endif + seq_printf(m, "TS1 = %llu\n", (unsigned long long)get_unaligned_le64(wifi->params.ts1)); + seq_printf(m, "TS2 = %lu\n", (unsigned long)get_unaligned_le32(wifi->params.ts2)); + seq_printf(m, "BSSID = %pM\n", (wifi->params.bssid)); + return 0; } -static ssize_t proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) +static ssize_t proc_write(struct file *file, + const char __user *buffer, + size_t count, + loff_t *ppos) { char buf[100]; int ret; @@ -931,6 +977,12 @@ static ssize_t proc_write(struct file *file, const char __user *buffer, printk(KERN_ERR "Invalid parameter value.\n"); else wifi->params.ed_sensitivity = sval; + } else if (!strncmp(buf, "dyn_ed_ceiling=", 15)) { + ret = kstrtol(buf+15, 0, &sval); + if (sval > -51 || sval < -96 || (sval % 3 != 0)) + printk(KERN_ERR "Invalid parameter value.\n"); + else + wifi->params.dyn_ed_ceiling = sval; } else if (!strncmp(buf, "auto_sensitivity=", 17)) { ret = kstrtoul(buf+17, 0, &val); if ((val == 0) || (val == 1)) @@ -990,6 +1042,23 @@ static ssize_t proc_write(struct file *file, const char __user *buffer, printk(KERN_ERR "Invalid parameter value.\n"); } else if (!strncmp(buf, "get_rx_stats=", 13)) { uccp310wlan_prog_mib_stats(); + } else if (!strncmp(buf, "reset_hal_params=", 17)) { + ret = kstrtoul(buf+17, 0, &val); + if (((struct mac80211_dev *)(wifi->hw->priv))->state != STARTED) { + if (val != 1) + printk(KERN_ERR "Invalid parameter value.\n"); + else + reset_hal_params(); + } else { + printk(KERN_ERR "HAL parameters reset can be done only when all interface are down\n"); + } + } else if (!strncmp(buf, "max_bcn_loss=", 13)) { + ret = kstrtoul(buf+13, 0, &val); + if (val >= 5) + wifi->params.max_bcn_loss = val; + else + printk(KERN_ERR "Invalid parameter value (should be >=5)"); + } else { printk(KERN_ERR "Invalid parameter name.\n"); } @@ -1001,11 +1070,12 @@ static int proc_open(struct inode *inode, struct file *file) return single_open(file, proc_read, NULL); } -static const struct file_operations params_fops = { +static const struct file_operations proc_fops = { .open = proc_open, .read = seq_read, .llseek = seq_lseek, - .write = proc_write, + .release = single_release, + .write = proc_write }; static int proc_init(void) @@ -1027,7 +1097,7 @@ static int proc_init(void) } entry = proc_create("params", 0644, wifi->umac_proc_dir_entry, - ¶ms_fops); + &proc_fops); if (!entry) { printk(KERN_ERR "Failed to create proc entry\n"); err = -ENOMEM; @@ -1038,9 +1108,11 @@ static int proc_init(void) memset(&wifi->params, 0, sizeof(struct wifi_params)); memset(wifi->params.rf_params, 0xff, sizeof(wifi->params.rf_params)); wifi->params.ed_sensitivity = -84; + wifi->params.dyn_ed_ceiling = -51; wifi->params.rf_params[0] = 0x3B; wifi->params.auto_sensitivity = 1; wifi->params.num_vifs = 1; + wifi->params.max_bcn_loss = MAX_BEACON_LOSS_COUNT; return err; diff --git a/drivers/net/wireless/uccp310wlan/core.c b/drivers/net/wireless/uccp310wlan/core.c index b7496c5f3052a5..3ede750b1327d6 100644 --- a/drivers/net/wireless/uccp310wlan/core.c +++ b/drivers/net/wireless/uccp310wlan/core.c @@ -70,15 +70,29 @@ static void vif_bcn_timer_expiry(unsigned long data) if (!ieee80211_sdata_running(sdata)) return; - if (uvif->vif->bss_conf.enable_beacon == false) + + if (uvif->vif->bss_conf.enable_beacon == false) { + if (uvif->vif->type == NL80211_IFTYPE_STATION && + uvif->vif->bss_conf.assoc) { + ieee80211_connection_loss(uvif->vif); + printk(KERN_DEBUG "Maximum Beacon Loss count exceeded..............Disconnecting\n"); + del_timer(&uvif->bcn_timer); + } return; + } + if (uvif->vif->type == NL80211_IFTYPE_AP) { skb_queue_head_init(&bcast_frames); temp = skb = ieee80211_beacon_get(uvif->dev->hw, uvif->vif); - skb->priority = 1; - skb_queue_tail(&bcast_frames, skb); + + if (skb) { + skb->priority = 1; + skb_queue_tail(&bcast_frames, skb); + } else { + goto reschedule_timer; + } skb = ieee80211_get_buffered_bc(uvif->dev->hw, uvif->vif); while (skb) { @@ -87,8 +101,8 @@ static void vif_bcn_timer_expiry(unsigned long data) temp = skb; skb = ieee80211_get_buffered_bc(uvif->dev->hw, uvif->vif); } - - temp->priority = 0; + if (temp) + temp->priority = 0; spin_lock_irqsave(&uvif->dev->bcast_lock, flags); while ((skb = skb_dequeue(&bcast_frames))) @@ -96,11 +110,15 @@ static void vif_bcn_timer_expiry(unsigned long data) spin_unlock_irqrestore(&uvif->dev->bcast_lock, flags); } else { skb = ieee80211_beacon_get(uvif->dev->hw, uvif->vif); - uccp310wlan_tx_frame(skb, uvif->dev, true); + if (skb) + uccp310wlan_tx_frame(skb, uvif->dev, true); + else + goto reschedule_timer; /* TODO: IBSS PS handling */ } +reschedule_timer: mod_timer(&uvif->bcn_timer, jiffies + msecs_to_jiffies(uvif->vif->bss_conf.beacon_int)); } @@ -124,6 +142,7 @@ int uccp310wlan_core_init(struct mac80211_dev *dev) 512, /* Tx MSDU life time in msecs */ dev->params->ed_sensitivity, dev->params->auto_sensitivity, + dev->params->dyn_ed_ceiling, dev->params->rf_params); uccp310wlan_prog_txpower(dev->txpower); @@ -165,6 +184,9 @@ void uccp310wlan_vif_add(struct umac_vif *uvif) type = IF_MODE_STA_BSS; uvif->noa_active = 0; skb_queue_head_init(&uvif->noa_que); + init_timer(&uvif->bcn_timer); + uvif->bcn_timer.data = (unsigned long)uvif; + uvif->bcn_timer.function = vif_bcn_timer_expiry; break; case NL80211_IFTYPE_ADHOC: type = IF_MODE_STA_IBSS; @@ -202,8 +224,6 @@ void uccp310wlan_vif_add(struct umac_vif *uvif) uvif->config.edca_params[queue].txop, uvif->config.edca_params[queue].cwmin, uvif->config.edca_params[queue].cwmax); - - } } @@ -217,6 +237,7 @@ void uccp310wlan_vif_remove(struct umac_vif *uvif) switch (uvif->vif->type) { case NL80211_IFTYPE_STATION: type = IF_MODE_STA_BSS; + del_timer(&uvif->bcn_timer); break; case NL80211_IFTYPE_ADHOC: type = IF_MODE_STA_IBSS; @@ -335,6 +356,12 @@ void uccp310wlan_vif_bss_info_changed(struct umac_vif *uvif, struct ieee80211_bs switch (uvif->vif->type) { case NL80211_IFTYPE_STATION: if (changed & BSS_CHANGED_ASSOC) { + if (uvif->dev->active_vifs == 1) { + if (uvif->vif->bss_conf.assoc) + uccp310wlan_prog_scan_ind(0); + else + uccp310wlan_prog_scan_ind(1); + } if (bss_conf->assoc) { UMAC_DEBUG("%s-UMAC: AID %d, CAPS 0x%04x\n", uvif->dev->name, bss_conf->aid, bss_conf->assoc_capability | (bss->wmm_used << 9)); @@ -345,6 +372,9 @@ void uccp310wlan_vif_bss_info_changed(struct umac_vif *uvif, struct ieee80211_bs uvif->vif->addr, bss_conf->assoc_capability | (bss->wmm_used << 9)); uvif->noa_active = 0; + mod_timer(&uvif->bcn_timer, (jiffies + msecs_to_jiffies(uvif->dev->params->max_bcn_loss * uvif->vif->bss_conf.beacon_int))); + } else { + del_timer(&uvif->bcn_timer); } } break; @@ -479,10 +509,14 @@ void uccp310wlan_rx_frame(struct sk_buff *skb, void *context) struct ieee80211_hdr *hdr; struct ieee80211_rx_status rx_status; int i; + struct ieee80211_vif *vif = NULL; + struct umac_vif *uvif; + int vif_index; + dev->stats->rx_packet_count++; - skb_pull(skb, 32); /* Remove RX control information */ + skb_pull(skb, 44); /* Remove RX control information */ #ifdef CONFIG_RX_DEBUG printk(KERN_DEBUG "%s-RX: RX frame, length = %d, RSSI = %d, rate = %d\n", dev->name, rx->buff_len, rx->rssi, rx->rate); @@ -519,7 +553,22 @@ void uccp310wlan_rx_frame(struct sk_buff *skb, void *context) if (((hdr->frame_control & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_MGMT) && ((hdr->frame_control & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_BEACON)) { rx_status.mactime = get_unaligned_le64(rx->timestamp); - rx_status.flag |= RX_FLAG_MACTIME_START; + rx_status.flag |= RX_FLAG_MACTIME_END; + for (vif_index = 0; vif_index < dev->params->num_vifs; vif_index++) { + vif = (struct ieee80211_vif *)rcu_dereference(dev->vifs[vif_index]); + if (vif && (vif->type == NL80211_IFTYPE_STATION) && (vif->bss_conf.assoc) && + (!memcmp((vif_to_sdata(vif))->u.mgd.bssid, hdr->addr3, ETH_ALEN))) { + uvif = (struct umac_vif *)vif->drv_priv; + mod_timer(&uvif->bcn_timer, (jiffies + + msecs_to_jiffies(uvif->dev->params->max_bcn_loss * vif->bss_conf.beacon_int))); + } + if (vif && !compare_ether_addr(hdr->addr2, (vif_to_sdata(vif))->u.mgd.bssid)) { + memcpy(dev->params->ts1, rx->ts1, sizeof(rx->ts1)); + memcpy(dev->params->ts2, rx->ts2, sizeof(rx->ts2)); + memcpy(dev->params->bssid, (vif_to_sdata(vif))->u.mgd.bssid, ETH_ALEN); + } + + } } memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); diff --git a/drivers/net/wireless/uccp310wlan/hal_hostport.c b/drivers/net/wireless/uccp310wlan/hal_hostport.c index b8f4afd0a4f9b4..7ea761258863a4 100644 --- a/drivers/net/wireless/uccp310wlan/hal_hostport.c +++ b/drivers/net/wireless/uccp310wlan/hal_hostport.c @@ -53,6 +53,13 @@ unsigned int irq_ts_index; spinlock_t timing_lock; #endif +int reset_hal_params(void) +{ + hpriv->cmd_cnt = COMMAND_START_MAGIC; + hpriv->event_cnt = 0; + return 0; +} + static int hal_ready(void) { unsigned int value = 0; diff --git a/drivers/net/wireless/uccp310wlan/hal_hostport.h b/drivers/net/wireless/uccp310wlan/hal_hostport.h index fb1a08240a1e2a..00ecd71a64a7e2 100644 --- a/drivers/net/wireless/uccp310wlan/hal_hostport.h +++ b/drivers/net/wireless/uccp310wlan/hal_hostport.h @@ -98,7 +98,7 @@ void _uccp310wlan_80211if_exit(void); /******************************************************************************************************/ #define HAL_SHARED_MEM_OFFSET 0x30000 #define HAL_WLAN_BULK_RAM_START (HAL_META_BULK_RAM + (hpriv->shm_offset)) -#define HAL_WLAN_BULK_RAM_LEN 0x00012000 +#define HAL_WLAN_BULK_RAM_LEN 0x00016000 /* Command, Event and Buff mappping offsets */ #define HAL_COMMAND_OFFSET (0) @@ -107,6 +107,7 @@ void _uccp310wlan_80211if_exit(void); #define HAL_BULK_RAM_CMD_START ((hpriv->bulk_ram_mem_addr) + HAL_COMMAND_OFFSET) #define HAL_BULK_RAM_EVENT_START ((hpriv->bulk_ram_mem_addr) + HAL_EVENT_OFFSET) + #define HAL_IRQ_LINE external_irq_map(UCC0_IRQ_NUM) #if defined(__cplusplus) diff --git a/drivers/net/wireless/uccp310wlan/lmac_if.c b/drivers/net/wireless/uccp310wlan/lmac_if.c index 058d8c08682428..9f45032bd36c8b 100644 --- a/drivers/net/wireless/uccp310wlan/lmac_if.c +++ b/drivers/net/wireless/uccp310wlan/lmac_if.c @@ -89,6 +89,16 @@ int uccp310wlan_prog_reset(unsigned int reset_type) sizeof(struct umac_cmd_reset)); } +int uccp310wlan_prog_scan_ind(unsigned int scan_start) +{ + struct umac_cmd_scan_ind scan; + + scan.hdr.id = scan_start ? CMD_SCAN_START : CMD_SCAN_STOP; + scan.hdr.flags = 0; + return uccp310wlan_send_cmd((unsigned char *) &scan, + sizeof(struct umac_cmd_scan_ind)); +} + int uccp310wlan_prog_vif_ctrl(int index, unsigned char *mac_addr, unsigned int vif_type, @@ -299,6 +309,7 @@ int uccp310wlan_prog_global_cfg(unsigned int rx_msdu_lifetime, unsigned int tx_msdu_lifetime, unsigned int sensitivity, unsigned int dyn_ed_enable, + unsigned int dyn_ed_ceiling, unsigned char *rf_params) { struct umac_cmd_global_cfg gbl_config; @@ -310,6 +321,7 @@ int uccp310wlan_prog_global_cfg(unsigned int rx_msdu_lifetime, gbl_config.tx_msdu_lifetime = tx_msdu_lifetime; gbl_config.ed_sensitivity = sensitivity; gbl_config.dynamic_ed_enable = dyn_ed_enable; + gbl_config.dynamic_ed_ceiling = dyn_ed_ceiling; memcpy(gbl_config.rf_params, rf_params, 8); return uccp310wlan_send_cmd((unsigned char *) &gbl_config, diff --git a/drivers/net/wireless/uccp310wlan/lmac_if.h b/drivers/net/wireless/uccp310wlan/lmac_if.h index f07a2de77f88f7..4641be38a37e18 100644 --- a/drivers/net/wireless/uccp310wlan/lmac_if.h +++ b/drivers/net/wireless/uccp310wlan/lmac_if.h @@ -43,6 +43,7 @@ struct umac_key { /* Commands */ extern int uccp310wlan_prog_reset(unsigned int reset_type); +extern int uccp310wlan_prog_scan_ind(unsigned int scan_ind); extern int uccp310wlan_prog_vif_ctrl(int index, unsigned char *vif_addr, unsigned int vif_type, @@ -85,6 +86,7 @@ extern int uccp310wlan_prog_global_cfg(unsigned int rx_msdu_lifetime, unsigned int tx_msdu_lifetime, unsigned int sensitivity, unsigned int dyn_ed_enabled, + unsigned int dyn_ed_ceiling, unsigned char *rf_params); extern int uccp310wlan_prog_txpower(unsigned int txpower); extern int uccp310wlan_prog_mcast_addr_cfg(unsigned char *mcast_addr, diff --git a/drivers/net/wireless/uccp310wlan/umac.h b/drivers/net/wireless/uccp310wlan/umac.h index 9d8ab259725144..fb27481d468bf8 100644 --- a/drivers/net/wireless/uccp310wlan/umac.h +++ b/drivers/net/wireless/uccp310wlan/umac.h @@ -63,15 +63,22 @@ extern spinlock_t timing_lock; #define SUPPORTED_FILTERS (FIF_ALLMULTI | FIF_BCN_PRBRESP_PROMISC) #define MAX_BUFF_POOL_ELEMENTS 9 /* Must be alteast 6, one for each AC + two for BCN queue + spares*/ #define MAX_TX_QUEUE_LEN 20 +#define MAX_BEACON_LOSS_COUNT 20 /*Beacon loss timeout is calculated as N frames times the advertised beacon interval*/ struct wifi_params { int ed_sensitivity; + int dyn_ed_ceiling; int num_vifs; unsigned char auto_sensitivity; unsigned char rf_params[8]; unsigned char show_phy_stats; unsigned char production_test; unsigned int dot11a_support; + unsigned int max_bcn_loss; + unsigned char ts1[8]; + unsigned char ts2[4]; + unsigned char bssid[ETH_ALEN]; + }; struct wifi_stats { diff --git a/drivers/net/wireless/uccp310wlan/umac_lmac_if.h b/drivers/net/wireless/uccp310wlan/umac_lmac_if.h index 7470fd7309740b..0b82e0a36dd8f2 100644 --- a/drivers/net/wireless/uccp310wlan/umac_lmac_if.h +++ b/drivers/net/wireless/uccp310wlan/umac_lmac_if.h @@ -30,6 +30,8 @@ #ifndef _UCCP310WLAN_UMAC_LMAC_IF_H_ #define _UCCP310WLAN_UMAC_LMAC_IF_H_ +#include <linux/compiler.h> + #define MICHAEL_LEN 8 #define MAX_KEY_LEN 16 @@ -37,8 +39,6 @@ #define WEP104_KEYLEN 13 #define MAX_WEP_KEY_LEN 13 -#define _PACKED_ __attribute__((__packed__)) - enum UMAC_QUEUE_NUM { WLAN_AC_BK = 0, WLAN_AC_BE, @@ -51,7 +51,7 @@ enum UMAC_QUEUE_NUM { struct umac_lmac_msg_hdr { unsigned int id; unsigned int flags; -} _PACKED_; +} __packed; /* Commands */ enum UMAC_CMD { @@ -73,6 +73,8 @@ enum UMAC_CMD { CMD_MIB_STATS, CMD_PHY_STATS, CMD_TEST, /* Can be used by hardware abstraction layer(s) */ + CMD_SCAN_START, + CMD_SCAN_STOP, CMD_LAST }; /* UMAC commands */ @@ -86,7 +88,11 @@ struct umac_cmd_reset { #define LMAC_ENABLE 0 #define LMAC_DISABLE 1 unsigned int reset_type; -} _PACKED_; +} __packed; + +struct umac_cmd_scan_ind { + struct umac_lmac_msg_hdr hdr; +} __packed; struct umac_cmd_vif_ctrl { struct umac_lmac_msg_hdr hdr; @@ -120,7 +126,7 @@ struct umac_cmd_vif_ctrl { * interface address to add or delete */ unsigned char mac_addr[ETH_ALEN]; -} _PACKED_; +} __packed; struct umac_cmd_vif_cfg { struct umac_lmac_msg_hdr hdr; @@ -200,7 +206,7 @@ struct umac_cmd_vif_cfg { /* bssid of interface */ unsigned char bssid[ETH_ALEN]; -} _PACKED_; +} __packed; struct umac_cmd_global_cfg { struct umac_lmac_msg_hdr hdr; @@ -211,6 +217,7 @@ struct umac_cmd_global_cfg { unsigned int tx_msdu_lifetime; int ed_sensitivity; + int dynamic_ed_ceiling; /* * dynamic_ed_enable - @@ -222,12 +229,12 @@ struct umac_cmd_global_cfg { unsigned int dynamic_ed_enable; unsigned char rf_params[8]; -} _PACKED_ ; +} __packed; struct umac_cmd_txpower { struct umac_lmac_msg_hdr hdr; unsigned int txpower; /* In dbm */ -} _PACKED_; +} __packed; struct umac_cmd_mcst_filter_cfg { struct umac_lmac_msg_hdr hdr; @@ -245,7 +252,7 @@ struct umac_cmd_mcst_filter_cfg { */ unsigned char addr[ETH_ALEN]; -} _PACKED_; +} __packed; struct umac_cmd_mcst_filter_ctrl { struct umac_lmac_msg_hdr hdr; @@ -258,7 +265,7 @@ struct umac_cmd_mcst_filter_ctrl { #define MCAST_FILTER_DISABLE 0 #define MCAST_FILTER_ENABLE 1 unsigned int ctrl; -} _PACKED_ ; +} __packed; struct umac_cmd_rcv_bcn_mode { struct umac_lmac_msg_hdr hdr; @@ -271,7 +278,7 @@ struct umac_cmd_rcv_bcn_mode { #define RCV_NETWORK_BCNS 1 #define RCV_NO_BCNS 2 unsigned int mode; -} _PACKED_ ; +} __packed; struct umac_cmd_txq_params { struct umac_lmac_msg_hdr hdr; @@ -309,7 +316,7 @@ struct umac_cmd_txq_params { */ unsigned char vif_addr[ETH_ALEN]; -} _PACKED_; +} __packed; struct umac_cmd_ps_cfg { struct umac_lmac_msg_hdr hdr; @@ -332,12 +339,12 @@ struct umac_cmd_ps_cfg { */ unsigned char vif_addr[ETH_ALEN]; -} _PACKED_ ; +} __packed; struct umac_cmd_channel { struct umac_lmac_msg_hdr hdr; unsigned int channel; -} _PACKED_ ; +} __packed; struct umac_cmd_peer_key_cfg { struct umac_lmac_msg_hdr hdr; @@ -388,7 +395,7 @@ struct umac_cmd_peer_key_cfg { unsigned char rx_mic[MICHAEL_LEN]; -} _PACKED_ ; +} __packed; struct umac_cmd_if_key_cfg { struct umac_lmac_msg_hdr hdr; @@ -427,7 +434,7 @@ struct umac_cmd_if_key_cfg { } rsn_grp_key; } key; -} _PACKED_ ; +} __packed; struct umac_cmd_tx { struct umac_lmac_msg_hdr hdr; @@ -502,15 +509,15 @@ struct umac_cmd_tx { */ unsigned int force_encrypt; -} _PACKED_; +} __packed; struct umac_cmd_mib_stats { struct umac_lmac_msg_hdr hdr; -} _PACKED_ ; +} __packed; struct umac_cmd_phy_stats { struct umac_lmac_msg_hdr hdr; -} _PACKED_ ; +} __packed; /* Events */ @@ -537,7 +544,7 @@ struct umac_event_lmac_error { * LMAC will send the unexpected errors in this event.. */ unsigned int error; -} _PACKED_ ; +} __packed; struct umac_event_noa { struct umac_lmac_msg_hdr hdr; @@ -552,12 +559,12 @@ struct umac_event_noa { #define ABSENCE_START 0 /* Indicates AP is absent */ #define ABSENCE_STOP 1 /* Indicates AP is present */ unsigned int ap_present; -} _PACKED_ ; +} __packed; struct umac_event_reset_complete { struct umac_lmac_msg_hdr hdr; char version[6]; -} _PACKED_ ; +} __packed; struct umac_event_rx { struct umac_lmac_msg_hdr hdr; @@ -567,8 +574,12 @@ struct umac_event_rx { unsigned char timestamp[8]; #define RX_MIC_SUCCESS 0 /* No MIC error in frame */ #define RX_MIC_FAILURE 1 /* MIC error in frame */ - unsigned int status; -} _PACKED_ ; + unsigned int status; + unsigned char ts1[8]; + unsigned char ts2[4]; + + +} __packed; struct umac_event_tx_done { @@ -596,7 +607,7 @@ struct umac_event_tx_done { unsigned int retries_num; unsigned int rate; unsigned int queue; -} _PACKED_ ; +} __packed; struct umac_event_mib_stats { struct umac_lmac_msg_hdr hdr; @@ -618,7 +629,7 @@ struct umac_event_mib_stats { unsigned int tx_ack_pkt_cnt; unsigned int frag_success_cnt; int sensitivity; -} _PACKED_; +} __packed; struct umac_event_phy_stats { struct umac_lmac_msg_hdr hdr; diff --git a/drivers/net/wireless/uccp310wlan/version.h b/drivers/net/wireless/uccp310wlan/version.h index 0f9cc148acbf93..338a16356f1bc0 100644 --- a/drivers/net/wireless/uccp310wlan/version.h +++ b/drivers/net/wireless/uccp310wlan/version.h @@ -27,7 +27,7 @@ *END**************************************************************************/ #ifndef _UCCP310WLAN_VERSION_H #define _UCCP310WLAN_VERSION_H -#define UMAC_VERSION "2_3_1" +#define UMAC_VERSION "2_3_4" #endif /* _UCCP310WLAN_VERSION_H */ /* EOF */ diff --git a/drivers/rtc/rtc-imgpdc.c b/drivers/rtc/rtc-imgpdc.c index b95c0acd5f00c8..730d6284d54921 100644 --- a/drivers/rtc/rtc-imgpdc.c +++ b/drivers/rtc/rtc-imgpdc.c @@ -220,7 +220,11 @@ start_again: *updating = upd; } -/* caller must hold lock. does handle read during time update. */ +/* + * caller must hold lock. + * does handle read during time update. + * does not initialise tm->wday, tm->yday, or tm->tm_isdst + */ static void _pdc_rtc_read_time(struct pdc_rtc_priv *priv, struct rtc_time *tm) { int upd; @@ -417,7 +421,7 @@ static void pdc_rtc_stop_alarm(struct pdc_rtc_priv *priv) spin_lock_irqsave(&priv->lock, flags); if (priv->alarm_irq_delay) { - pdc_rtc_read_time(priv->dev, &tm); + _pdc_rtc_read_time(priv, &tm); rtc_tm_to_time(&tm, &now); } _pdc_rtc_stop_alarm(priv, now); @@ -462,7 +466,7 @@ static int _pdc_rtc_set_alarm(struct pdc_rtc_priv *priv, bool temporary, if (priv->alarm_irq_delay) { alrm_adj = *alrm; - pdc_rtc_read_time(priv->dev, &tm); + _pdc_rtc_read_time(priv, &tm); rtc_tm_to_time(&tm, &now); try_again_locked: @@ -576,7 +580,7 @@ try_again_locked: */ spin_lock_irqsave(&priv->lock, flags); if (!priv->alarm_pending) { - pdc_rtc_read_time(priv->dev, &tm); + _pdc_rtc_read_time(priv, &tm); rtc_tm_to_time(&tm, &now); /* If it's too late, immediately trigger the alarm */ if (scheduled <= now) { @@ -717,7 +721,7 @@ static irqreturn_t pdc_rtc_isr(int irq, void *dev_id) priv->hardstop_time = 0; if (events & RTC_AF) { if (!now && priv->alarm_irq_delay) { - pdc_rtc_read_time(priv->dev, &tm); + _pdc_rtc_read_time(priv, &tm); rtc_tm_to_time(&tm, &now); } priv->alarm_pending = 1; @@ -726,7 +730,7 @@ static irqreturn_t pdc_rtc_isr(int irq, void *dev_id) } else { /* make absolutely sure that the alarm is properly stopped */ if (priv->alarm_irq_delay) { - pdc_rtc_read_time(priv->dev, &tm); + _pdc_rtc_read_time(priv, &tm); rtc_tm_to_time(&tm, &now); } _pdc_rtc_stop_alarm(priv, now); diff --git a/drivers/spi/spi-img.c b/drivers/spi/spi-img.c index 79012f52afd8f3..3f18e988ac783e 100644 --- a/drivers/spi/spi-img.c +++ b/drivers/spi/spi-img.c @@ -46,42 +46,11 @@ * The FIFO is 16 bytes deep. If we can fit the transfer in the FIFO * it's more efficient to do that and avoid the overhead of setting * up DMA. - * - * - * NOTE: This is set to zero to disable PIO for now. It works with mmc but not - * the Marvell 88W8686 wifi chip for reasons that are unknown at present. */ -#define DMA_MIN_SIZE 0 /*16 if if worked for all devices*/ - -#if defined(CONFIG_META_DMA_CONTROLLER) +#define DMA_MIN_SIZE 32 -/* BURST SIZE is in bytes for MDC */ +/* BURST SIZE is in bytes */ #define BURST_SIZE 8 /*Fifo is 16 bytes deep so burst this many*/ -#define BURST_BYTES (BURST_SIZE*8) - -#define BURST_MASK (~(BURST_BYTES - 1)) - -#else /* DMAC */ - -/* We have to work around a hardware bug. When DMAing from external memory to - * the SPI controller the DMAC creates a byte mask for the first and last - * transfers. Unfortunately it uses the end byte mask for every burst, not just - * the final burst. The workaround is to make sure we only DMA whole bursts - * (so the end byte mask is all 1s) or single bursts if we're transferring - * less than a whole burst. - * - * The burst size is defined in bus-width terms so 1 is a 64-bit burst. - */ -#define BURST_SIZE 1 -#define BURST_BYTES (BURST_SIZE*8) -#define BURST_MASK (~(BURST_BYTES - 1)) - -/* The DMAC also cannot do DMA from unaligned buffers thus we copy the data to - * a dma-able bounce buffer first. - */ -#define NEED_BOUNCE_BUFFERS 1 - -#endif /* SPI - Device Registers */ #define SPI_DEV0_REG 0x000 /* Device 0*/ @@ -106,12 +75,20 @@ #define SPI_SDTRIG_EN 0x1 -#define SPI_GDTRIG 0x1 +#define SPI_GDTRIG 0x01 +#define SPI_GDFUL 0x08 #define SPI_ALLDONE_TRIG 0x10 #define SPI_WRITE_INT_MASK 0x1f #define SPI_READ_INT_MASK 0x1f +#define SPI_DI_GDFUL BIT(19) /* RX FIFO full */ +#define SPI_DI_GDHF BIT(18) /* RX FIFO half full */ +#define SPI_DI_GDEX BIT(17) /* RX FIFO not empty */ +#define SPI_DI_SDFUL BIT(3) /* TX FIFO full */ +#define SPI_DI_SDHF BIT(2) /* TX FIFO half full */ +#define SPI_DI_SDEX BIT(1) /* TX FIFO not empty */ + #define START_STATE ((void *)0) #define RUNNING_STATE ((void *)1) #define DONE_STATE ((void *)2) @@ -138,6 +115,7 @@ struct driver_data { /* Clocks */ struct clk *clk; + unsigned long clk_rate; struct img_spi_master *master_info; @@ -160,11 +138,6 @@ struct driver_data { /* Length of the current DMA */ size_t len; - /* Length of any subsequent DMA needed to clean up after the bug - * mentioned above. - */ - size_t tail_len; - /* Total length of the transfer */ size_t map_len; @@ -234,7 +207,7 @@ static u8 hz_to_clk_div(struct driver_data *drv_data, u32 speed_hz) { /* Register value is: * Fout = (Fin * reg / 512) MHz */ - u8 val = min_t(unsigned int, speed_hz/(clk_get_rate(drv_data->clk)/512), + u8 val = min_t(unsigned int, speed_hz/((drv_data->clk_rate)/512), 0xffU); /* Clamp value at 1 as 0 is invalid (we get no clock) */ @@ -316,8 +289,7 @@ static void start_dma(struct driver_data *drv_data, struct chip_data *chip) transaction |= (chip_select << 16); - if ((drv_data->tail_len) || - (!drv_data->cs_change && !drv_data->last_transfer)) + if (!drv_data->cs_change && !drv_data->last_transfer) transaction |= SPI_TRANS_REG_CONT_BIT; /* Ensure all writes to the tx buffer have completed. */ @@ -419,8 +391,11 @@ static void start_pio(struct driver_data *drv_data, struct chip_data *chip) { unsigned int transaction = 0; unsigned int chip_select = drv_data->cur_chip->chip_select_num; - unsigned int i; - uint32_t irq_status; + unsigned int tx, rx = 0; + const u8 *write_buf = drv_data->tx; + u8 *read_buf = drv_data->rx; + uint32_t di; + int can_tx, can_rx; if (chip->cs_high) chip_select |= 0x1; @@ -433,12 +408,14 @@ static void start_pio(struct driver_data *drv_data, struct chip_data *chip) if (!drv_data->cs_change && !drv_data->last_transfer) transaction |= SPI_TRANS_REG_CONT_BIT; - /* Fill up the FIFO */ - for (i = 0; i < drv_data->map_len; i++) { - const u8 *write_buf = drv_data->tx; + /* Prime the FIFO */ + for (tx = 0; tx < drv_data->map_len; tx++) { u8 write_byte; + /* until FIFO is half full */ + if (spi_readl(drv_data, SPI_DI_STATUS) & SPI_DI_SDHF) + break; if (write_buf) - write_byte = write_buf[i]; + write_byte = write_buf[tx]; else write_byte = 0x00; spi_writeb(write_byte, drv_data, DMA_SPIO_SENDDAT); @@ -447,17 +424,42 @@ static void start_pio(struct driver_data *drv_data, struct chip_data *chip) /* Start the transaction */ spi_writel(transaction, drv_data, SPI_TRANS_REG); - /* Wait for the data we're going to read to fill the FIFO */ - irq_status = 0; - while (!((irq_status & SPI_GDTRIG) || (irq_status & SPI_ALLDONE_TRIG))) - irq_status = spi_readl(drv_data, DMA_SPII_INT_STAT); - - /* Read from FIFO */ - for (i = 0; i < drv_data->map_len; i++) { - u8 *read_buf = drv_data->rx; - u8 read_byte = spi_readb(drv_data, DMA_SPII_GETDAT); - if (read_buf) - read_buf[i] = read_byte; + /* Maintain FIFOs until transfer is complete */ + can_tx = (tx < drv_data->map_len); + can_rx = (rx < drv_data->map_len); + while (can_tx || can_rx || !(spi_readl(drv_data, DMA_SPII_INT_STAT) & + (SPI_GDTRIG | SPI_ALLDONE_TRIG))) { + di = spi_readl(drv_data, SPI_DI_STATUS); + /* + * Top up TX unless both RX and TX are half full, + * in which case RX needs draining more urgently. + */ + if (can_tx && !(di & SPI_DI_SDFUL) && + (!can_rx || ((di & (SPI_DI_SDHF | SPI_DI_GDHF)) != + (SPI_DI_SDHF | SPI_DI_GDHF)))) { + /* Write to TX FIFO */ + u8 write_byte; + if (write_buf) + write_byte = write_buf[tx]; + else + write_byte = 0x00; + spi_writeb(write_byte, drv_data, DMA_SPIO_SENDDAT); + ++tx; + can_tx = (tx < drv_data->map_len); + } + /* + * Drain RX unless neither RX or TX are half full, + * in which case TX needs filling more urgently. + */ + if (can_rx && (di & SPI_DI_GDEX) && + (!can_tx || (di & (SPI_DI_SDHF | SPI_DI_GDHF)))) { + /* Read from RX FIFO */ + u8 read_byte = spi_readb(drv_data, DMA_SPII_GETDAT); + if (read_buf) + read_buf[rx] = read_byte; + ++rx; + can_rx = (rx < drv_data->map_len); + } } /* Clear any interrupts we generated */ @@ -503,27 +505,6 @@ static irqreturn_t spi_irq(int irq, void *dev_id) return IRQ_HANDLED; } - if (drv_data->tail_len) { - if (drv_data->rx_dma) - drv_data->rx_dma += drv_data->len; - - if (drv_data->tx_dma) - drv_data->tx_dma += drv_data->len; - - drv_data->len = drv_data->tail_len; - - drv_data->tail_len = 0; - - start_dma(drv_data, drv_data->cur_chip); - - return IRQ_HANDLED; - } - -#ifdef NEED_BOUNCE_BUFFERS - if (drv_data->rx) - memcpy(drv_data->rx, drv_data->rx_buf, drv_data->map_len); -#else - if (drv_data->tx_mapped_by_us) { dma_unmap_single(&drv_data->pdev->dev, drv_data->tx_dma, @@ -548,7 +529,6 @@ static irqreturn_t spi_irq(int irq, void *dev_id) (u32)drv_data->rx_dma, drv_data->len);*/ } -#endif dev_dbg(&drv_data->pdev->dev, "interrupt di status: %#x\n", spi_readl(drv_data, SPI_DI_STATUS)); @@ -576,7 +556,6 @@ static irqreturn_t spi_irq(int irq, void *dev_id) return IRQ_HANDLED; } -#ifndef NEED_BOUNCE_BUFFERS /* Helper:*/ static int map_buffers(struct driver_data *drv_data, struct spi_message *message, @@ -661,7 +640,6 @@ static int map_buffers(struct driver_data *drv_data, } return 0; } -#endif static void pump_transfers(unsigned long data) { @@ -728,28 +706,6 @@ static void pump_transfers(unsigned long data) wmb(); } -#ifdef NEED_BOUNCE_BUFFERS - /* Copy data to bounce buffer due to DMAC bug */ - if (transfer->len > DMA_MIN_SIZE) { - if (drv_data->tx) - memcpy(drv_data->tx_buf, drv_data->tx, transfer->len); - else - /*send out zeros*/ - memset(drv_data->tx_buf, 0x00, transfer->len); - - drv_data->rx_dma = drv_data->rx_dma_start; - drv_data->tx_dma = drv_data->tx_dma_start; - - } - - if (transfer->len > BURST_BYTES) - drv_data->len = transfer->len & BURST_MASK; - else - drv_data->len = transfer->len; - - drv_data->tail_len = transfer->len - drv_data->len; - -#else /* MDC */ /* setup dma mappings for buffers, no need for * the bounce buffer! */ @@ -761,9 +717,7 @@ static void pump_transfers(unsigned long data) return; } drv_data->len = transfer->len; - drv_data->tail_len = 0; } -#endif drv_data->map_len = transfer->len; @@ -1179,7 +1133,6 @@ static int __init img_spi_probe(struct platform_device *pdev) struct driver_data *drv_data = NULL; struct resource *irq_resource, *mem_resource; int status = 0; - unsigned long clk_rate; /* Allocate master with space for drv_data */ master = spi_alloc_master(dev, sizeof(struct driver_data)); @@ -1230,13 +1183,15 @@ static int __init img_spi_probe(struct platform_device *pdev) /* try setting the clock to the requested rate */ if (platform_info->clk_rate) { status = clk_set_rate(drv_data->clk, platform_info->clk_rate); - clk_rate = clk_get_rate(drv_data->clk); - if (clk_rate != platform_info->clk_rate) { + drv_data->clk_rate = clk_get_rate(drv_data->clk); + if (drv_data->clk_rate != platform_info->clk_rate) { dev_warn(dev, "SPI clock requested: %lu HZ. Actual SPI clock: %lu (status=%d)\n", - platform_info->clk_rate, clk_rate, status); + platform_info->clk_rate, drv_data->clk_rate, status); } status = 0; + } else { + drv_data->clk_rate = clk_get_rate(drv_data->clk); } /* try enabling the clock */ diff --git a/fs/exec.c b/fs/exec.c index ffd7a813ad3d06..3ddb02cbad6f1a 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -654,10 +654,10 @@ int setup_arg_pages(struct linux_binprm *bprm, unsigned long rlim_stack; #ifdef CONFIG_STACK_GROWSUP - /* Limit stack size to 1GB */ + /* Limit stack size */ stack_base = rlimit_max(RLIMIT_STACK); - if (stack_base > (1 << 30)) - stack_base = 1 << 30; + if (stack_base > STACK_SIZE_MAX) + stack_base = STACK_SIZE_MAX; /* Make sure we didn't let the argument array grow too large. */ if (vma->vm_end - vma->vm_start > stack_base) diff --git a/include/linux/img_mdc_dma.h b/include/linux/img_mdc_dma.h index 800429b672df46..da14c11c0068df 100644 --- a/include/linux/img_mdc_dma.h +++ b/include/linux/img_mdc_dma.h @@ -45,6 +45,7 @@ struct mdc_dma_cookie { /* Platform data for SOC DMA callbacks */ struct img_mdc_soc_callbacks { int (*allocate) (int, unsigned int); /* allocate a DMA channel */ + int (*available) (int); /* Check if DMA channel is available */ int (*free) (int); /* free a DMA channel */ /* * SOC DMA specific callbacks for suspend_noirq and resume_noirq. diff --git a/init/Kconfig b/init/Kconfig index 2d9b83104dcf71..38fca0ee68c1a3 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -441,6 +441,7 @@ config TREE_RCU config TREE_PREEMPT_RCU bool "Preemptible tree-based hierarchical RCU" depends on PREEMPT + select IRQ_WORK help This option selects the RCU implementation that is designed for very large SMP systems with hundreds or diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index ac7ef5414bdede..e6512e2ffd2002 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -290,7 +290,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, struct minstrel_rate *msr, *mr; unsigned int ndx; bool mrr_capable; - bool prev_sample = mi->prev_sample; + bool prev_sample; int delta; int sampling_ratio; @@ -314,6 +314,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, (mi->sample_count + mi->sample_deferred / 2); /* delta < 0: no sampling required */ + prev_sample = mi->prev_sample; mi->prev_sample = false; if (delta < 0 || (!mrr_capable && prev_sample)) return; diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 721587c9cd847e..73e205c892a0d0 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -38,9 +38,9 @@ enum si476x_digital_io_output_format { SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT = 8, }; -#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK ((0b111 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \ - (0b111 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)) -#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK (0b1111110) +#define SI476X_DIGITAL_IO_OUTPUT_WIDTH_MASK ((0x7 << SI476X_DIGITAL_IO_SLOT_SIZE_SHIFT) | \ + (0x7 << SI476X_DIGITAL_IO_SAMPLE_SIZE_SHIFT)) +#define SI476X_DIGITAL_IO_OUTPUT_FORMAT_MASK (0x7e) enum si476x_daudio_formats { SI476X_DAUDIO_MODE_I2S = (0x0 << 1), diff --git a/sound/soc/tz1090/tz1090-pcm.c b/sound/soc/tz1090/tz1090-pcm.c index 6d860a28214fcf..ac790b4ae4cbe2 100644 --- a/sound/soc/tz1090/tz1090-pcm.c +++ b/sound/soc/tz1090/tz1090-pcm.c @@ -118,7 +118,7 @@ out: /*Called on stream close */ static int comet_pcm_close(struct snd_pcm_substream *substream) { - snd_dmaengine_pcm_close(substream); + snd_dmaengine_pcm_close_release_chan(substream); return 0; } |