From b635f1912da764c960c044ffd58ba27157aa2c85 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 23 Sep 2009 08:06:25 +0000 Subject: Blackfin: allow boards to register early devices Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/setup.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 95448ae9c43a..69cbc1a81201 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -792,10 +792,17 @@ static inline int __init get_mem_size(void) BUG(); } +__attribute__((weak)) +void __init native_machine_early_platform_add_devices(void) +{ +} + void __init setup_arch(char **cmdline_p) { unsigned long sclk, cclk; + native_machine_early_platform_add_devices(); + enable_shadow_console(); /* Check to make sure we are running on the right processor */ -- cgit v1.2.3 From e18e7dd33454f277b9438af66d25984362278021 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Mon, 7 Dec 2009 10:05:58 +0000 Subject: Blackfin: fix MPU page permission masks overflow when dealing with async memory Attempting to use the MPU while doing XIP out of parallel flash hooked up to the async memory bus would often result in random crashes as the MPU slowly corrupted memory. The fallout here is that the async banks gain MPU protection from user space too. So any accesses have to go through the mmap() interface rather than just using hardcoded pointers. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/mmu_context.h | 14 +++++++++++--- arch/blackfin/kernel/cplb-mpu/cplbmgr.c | 30 ++++++++++++++++++++++-------- arch/blackfin/kernel/setup.c | 5 +++++ 3 files changed, 38 insertions(+), 11 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/mmu_context.h b/arch/blackfin/include/asm/mmu_context.h index ae8ef4ffd806..7f363d7e43a5 100644 --- a/arch/blackfin/include/asm/mmu_context.h +++ b/arch/blackfin/include/asm/mmu_context.h @@ -13,6 +13,7 @@ #include #include #include +#include /* Note: L1 stacks are CPU-private things, so we bluntly disable this feature in SMP mode, and use the per-CPU scratch SRAM bank only to @@ -117,9 +118,16 @@ static inline void protect_page(struct mm_struct *mm, unsigned long addr, unsigned long flags) { unsigned long *mask = mm->context.page_rwx_mask; - unsigned long page = addr >> 12; - unsigned long idx = page >> 5; - unsigned long bit = 1 << (page & 31); + unsigned long page; + unsigned long idx; + unsigned long bit; + + if (unlikely(addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE)) + page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> 12; + else + page = addr >> 12; + idx = page >> 5; + bit = 1 << (page & 31); if (flags & VM_READ) mask[idx] |= bit; diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c index 930c01c06813..d4cc53a0ef89 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c @@ -114,10 +114,15 @@ static noinline int dcplb_miss(unsigned int cpu) d_data = L2_DMEMORY; } else if (addr >= physical_mem_end) { if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) { - addr &= ~(4 * 1024 * 1024 - 1); - d_data &= ~PAGE_SIZE_4KB; - d_data |= PAGE_SIZE_4MB; - d_data |= CPLB_USER_RD | CPLB_USER_WR; + mask = current_rwx_mask[cpu]; + if (mask) { + int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT; + int idx = page >> 5; + int bit = 1 << (page & 31); + + if (mask[idx] & bit) + d_data |= CPLB_USER_RD; + } } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH && (status & (FAULT_RW | FAULT_USERSUPV)) == FAULT_USERSUPV) { addr &= ~(1 * 1024 * 1024 - 1); @@ -204,10 +209,19 @@ static noinline int icplb_miss(unsigned int cpu) i_data = L2_IMEMORY; } else if (addr >= physical_mem_end) { if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) { - addr &= ~(4 * 1024 * 1024 - 1); - i_data &= ~PAGE_SIZE_4KB; - i_data |= PAGE_SIZE_4MB; - i_data |= CPLB_USER_RD; + if (!(status & FAULT_USERSUPV)) { + unsigned long *mask = current_rwx_mask[cpu]; + + if (mask) { + int page = (addr - (ASYNC_BANK0_BASE - _ramend)) >> PAGE_SHIFT; + int idx = page >> 5; + int bit = 1 << (page & 31); + + mask += 2 * page_mask_nelts; + if (mask[idx] & bit) + i_data |= CPLB_USER_RD; + } + } } else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH && (status & FAULT_USERSUPV)) { addr &= ~(1 * 1024 * 1024 - 1); diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 69cbc1a81201..8dc7ee1ef336 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -597,7 +597,12 @@ static __init void memory_setup(void) } #ifdef CONFIG_MPU +#if defined(CONFIG_ROMFS_ON_MTD) && defined(CONFIG_MTD_ROM) + page_mask_nelts = (((_ramend + ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE - + ASYNC_BANK0_BASE) >> PAGE_SHIFT) + 31) / 32; +#else page_mask_nelts = ((_ramend >> PAGE_SHIFT) + 31) / 32; +#endif page_mask_order = get_order(3 * page_mask_nelts * sizeof(long)); #endif -- cgit v1.2.3 From 5792ab2a0a22fdaef33056ca2b31847a28b1af60 Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 9 Dec 2009 07:01:50 +0000 Subject: Blackfin: MPU: handle caches for reserved memory We weren't handling the user-specified cache behavior for the reserved memory regions (via mem=/max_mem=). The no-MPU code already takes care of this, so add support to the MPU code as well. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/cplb-mpu/cplbmgr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c index d4cc53a0ef89..7e6383dc7b20 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c @@ -131,7 +131,9 @@ static noinline int dcplb_miss(unsigned int cpu) } else return CPLB_PROT_VIOL; } else if (addr >= _ramend) { - d_data |= CPLB_USER_RD | CPLB_USER_WR; + d_data |= CPLB_USER_RD | CPLB_USER_WR; + if (reserved_mem_dcache_on) + d_data |= CPLB_L1_CHBL; } else { mask = current_rwx_mask[cpu]; if (mask) { @@ -231,6 +233,8 @@ static noinline int icplb_miss(unsigned int cpu) return CPLB_PROT_VIOL; } else if (addr >= _ramend) { i_data |= CPLB_USER_RD; + if (reserved_mem_icache_on) + i_data |= CPLB_L1_CHBL; } else { /* * Two cases to distinguish - a supervisor access must -- cgit v1.2.3 From a3a6a590190ca77aedf9de871d941c1139a5a24c Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Wed, 16 Dec 2009 07:52:52 +0000 Subject: Blackfin: dma-mapping: fix thinko in constant optimization Make sure the non-constant version of the dma_sync functions actually complete instead of recursively calling itself forever. Signed-off-by: Sonic Zhang Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/dma-mapping.h | 15 +++++++++------ arch/blackfin/kernel/dma-mapping.c | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/dma-mapping.h b/arch/blackfin/include/asm/dma-mapping.h index f9172ff30e5c..e63f6d9fdab8 100644 --- a/arch/blackfin/include/asm/dma-mapping.h +++ b/arch/blackfin/include/asm/dma-mapping.h @@ -44,13 +44,8 @@ dma_mapping_error(struct device *dev, dma_addr_t dma_addr) extern void __dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir); static inline void -_dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir) +__dma_sync_inline(dma_addr_t addr, size_t size, enum dma_data_direction dir) { - if (!__builtin_constant_p(dir)) { - __dma_sync(addr, size, dir); - return; - } - switch (dir) { case DMA_NONE: BUG(); @@ -64,6 +59,14 @@ _dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir) break; } } +static inline void +_dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir) +{ + if (__builtin_constant_p(dir)) + __dma_sync_inline(addr, size, dir); + else + __dma_sync(addr, size, dir); +} /* * Map a single buffer of the indicated size for DMA in streaming mode. diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c index e937f323d82c..04ddcfeb7981 100644 --- a/arch/blackfin/kernel/dma-mapping.c +++ b/arch/blackfin/kernel/dma-mapping.c @@ -116,7 +116,7 @@ EXPORT_SYMBOL(dma_free_coherent); void __dma_sync(dma_addr_t addr, size_t size, enum dma_data_direction dir) { - _dma_sync(addr, size, dir); + __dma_sync_inline(addr, size, dir); } EXPORT_SYMBOL(__dma_sync); -- cgit v1.2.3 From edd07992504e631b50d18d130c62addbcb16269e Mon Sep 17 00:00:00 2001 From: Michael Hennerich Date: Wed, 16 Dec 2009 08:45:17 +0000 Subject: Blackfin: gpio: use shorter name The gpio label size is 16 char, but the current code uses a longer name resulting in chopped display. So use a shorter name. Reported-by: Peter Meerwald Signed-off-by: Michael Hennerich Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/bfin_gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index a174596cc009..0dd9cf913503 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -1320,7 +1320,7 @@ void bfin_gpiolib_gpio_free(struct gpio_chip *chip, unsigned gpio) } static struct gpio_chip bfin_chip = { - .label = "Blackfin-GPIOlib", + .label = "BFIN-GPIO", .direction_input = bfin_gpiolib_direction_input, .get = bfin_gpiolib_get_value, .direction_output = bfin_gpiolib_direction_output, -- cgit v1.2.3 From 0d152c27e336b5fd777da7dd3e814617e7305afd Mon Sep 17 00:00:00 2001 From: Yi Li Date: Mon, 28 Dec 2009 10:21:49 +0000 Subject: Blackfin: SMP: make core timers per-cpu clock events for HRT SMP systems require per-cpu local clock event devices in order to enable HRT support. One a BF561, we can use local core timer for this purpose. Originally, there was one global core-timer clock event device set up for core A. To accomplish this feat, we need to split the gptimer0/core timer logic so that each is a standalone clock event. There is no requirement that we only have one clock event source anyways. Once we have this, we just define per-cpu clock event devices for each local core timer. Signed-off-by: Yi Li Signed-off-by: Mike Frysinger --- arch/blackfin/Kconfig | 26 ++-- arch/blackfin/include/asm/time.h | 6 +- arch/blackfin/kernel/time-ts.c | 197 +++++++++++++++------------- arch/blackfin/mach-bf561/include/mach/smp.h | 2 + arch/blackfin/mach-bf561/smp.c | 18 +++ arch/blackfin/mach-common/ints-priority.c | 3 - arch/blackfin/mach-common/smp.c | 17 +-- 7 files changed, 146 insertions(+), 123 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index b483639c80b3..0bd26dbca09f 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -236,7 +236,7 @@ endchoice config SMP depends on BF561 - select GENERIC_CLOCKEVENTS + select TICKSOURCE_CORETMR bool "Symmetric multi-processing support" ---help--- This enables support for systems with more than one CPU, @@ -610,23 +610,23 @@ config GENERIC_CLOCKEVENTS bool "Generic clock events" default y -choice - prompt "Kernel Tick Source" +menu "Clock event device" depends on GENERIC_CLOCKEVENTS - default TICKSOURCE_CORETMR - config TICKSOURCE_GPTMR0 - bool "Gptimer0 (SCLK domain)" + bool "GPTimer0" + depends on !SMP select BFIN_GPTIMERS config TICKSOURCE_CORETMR - bool "Core timer (CCLK domain)" - -endchoice + bool "Core timer" + default y +endmenu -config CYCLES_CLOCKSOURCE - bool "Use 'CYCLES' as a clocksource" +menu "Clock souce" depends on GENERIC_CLOCKEVENTS +config CYCLES_CLOCKSOURCE + bool "CYCLES" + default y depends on !BFIN_SCRATCH_REG_CYCLES depends on !SMP help @@ -637,10 +637,10 @@ config CYCLES_CLOCKSOURCE writing the registers will most likely crash the kernel. config GPTMR0_CLOCKSOURCE - bool "Use GPTimer0 as a clocksource" + bool "GPTimer0" select BFIN_GPTIMERS - depends on GENERIC_CLOCKEVENTS depends on !TICKSOURCE_GPTMR0 +endmenu config ARCH_USES_GETTIMEOFFSET depends on !GENERIC_CLOCKEVENTS diff --git a/arch/blackfin/include/asm/time.h b/arch/blackfin/include/asm/time.h index 589e937ed1eb..767b938ccf8c 100644 --- a/arch/blackfin/include/asm/time.h +++ b/arch/blackfin/include/asm/time.h @@ -37,5 +37,9 @@ extern unsigned long long __bfin_cycles_off; extern unsigned int __bfin_cycles_mod; #endif -extern void __init setup_core_timer(void); +#if defined(CONFIG_TICKSOURCE_CORETMR) +extern void bfin_coretmr_init(void); +extern void bfin_coretmr_clockevent_init(void); +#endif + #endif diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c index 17c38c5b5b22..a351f97c87a3 100644 --- a/arch/blackfin/kernel/time-ts.c +++ b/arch/blackfin/kernel/time-ts.c @@ -132,7 +132,6 @@ static int __init bfin_cs_gptimer0_init(void) # define bfin_cs_gptimer0_init() #endif - #if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE) /* prefer to use cycles since it has higher rating */ notrace unsigned long long sched_clock(void) @@ -145,47 +144,8 @@ notrace unsigned long long sched_clock(void) } #endif -#ifdef CONFIG_CORE_TIMER_IRQ_L1 -__attribute__((l1_text)) -#endif -irqreturn_t timer_interrupt(int irq, void *dev_id); - -static int bfin_timer_set_next_event(unsigned long, \ - struct clock_event_device *); - -static void bfin_timer_set_mode(enum clock_event_mode, \ - struct clock_event_device *); - -static struct clock_event_device clockevent_bfin = { -#if defined(CONFIG_TICKSOURCE_GPTMR0) - .name = "bfin_gptimer0", - .rating = 300, - .irq = IRQ_TIMER0, -#else - .name = "bfin_core_timer", - .rating = 350, - .irq = IRQ_CORETMR, -#endif - .shift = 32, - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = bfin_timer_set_next_event, - .set_mode = bfin_timer_set_mode, -}; - -static struct irqaction bfin_timer_irq = { -#if defined(CONFIG_TICKSOURCE_GPTMR0) - .name = "Blackfin GPTimer0", -#else - .name = "Blackfin CoreTimer", -#endif - .flags = IRQF_DISABLED | IRQF_TIMER | \ - IRQF_IRQPOLL | IRQF_PERCPU, - .handler = timer_interrupt, - .dev_id = &clockevent_bfin, -}; - #if defined(CONFIG_TICKSOURCE_GPTMR0) -static int bfin_timer_set_next_event(unsigned long cycles, +static int bfin_gptmr0_set_next_event(unsigned long cycles, struct clock_event_device *evt) { disable_gptimers(TIMER0bit); @@ -196,7 +156,7 @@ static int bfin_timer_set_next_event(unsigned long cycles, return 0; } -static void bfin_timer_set_mode(enum clock_event_mode mode, +static void bfin_gptmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { switch (mode) { @@ -224,25 +184,65 @@ static void bfin_timer_set_mode(enum clock_event_mode mode, } } -static void bfin_timer_ack(void) +static void bfin_gptmr0_ack(void) { set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0); } -static void __init bfin_timer_init(void) +static void __init bfin_gptmr0_init(void) { disable_gptimers(TIMER0bit); } -static unsigned long __init bfin_clockevent_check(void) +#ifdef CONFIG_CORE_TIMER_IRQ_L1 +__attribute__((l1_text)) +#endif +irqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id) { - setup_irq(IRQ_TIMER0, &bfin_timer_irq); - return get_sclk(); + struct clock_event_device *evt = dev_id; + smp_mb(); + evt->event_handler(evt); + bfin_gptmr0_ack(); + return IRQ_HANDLED; } -#else /* CONFIG_TICKSOURCE_CORETMR */ +static struct irqaction gptmr0_irq = { + .name = "Blackfin GPTimer0", + .flags = IRQF_DISABLED | IRQF_TIMER | \ + IRQF_IRQPOLL | IRQF_PERCPU, + .handler = bfin_gptmr0_interrupt, +}; -static int bfin_timer_set_next_event(unsigned long cycles, +static struct clock_event_device clockevent_gptmr0 = { + .name = "bfin_gptimer0", + .rating = 300, + .irq = IRQ_TIMER0, + .shift = 32, + .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = bfin_gptmr0_set_next_event, + .set_mode = bfin_gptmr0_set_mode, +}; + +static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt) +{ + unsigned long clock_tick; + + clock_tick = get_sclk(); + evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift); + evt->max_delta_ns = clockevent_delta2ns(-1, evt); + evt->min_delta_ns = clockevent_delta2ns(100, evt); + + evt->cpumask = cpumask_of(0); + + clockevents_register_device(evt); +} +#endif /* CONFIG_TICKSOURCE_GPTMR0 */ + +#if defined(CONFIG_TICKSOURCE_CORETMR) +/* per-cpu local core timer */ +static DEFINE_PER_CPU(struct clock_event_device, coretmr_events); + +static int bfin_coretmr_set_next_event(unsigned long cycles, struct clock_event_device *evt) { bfin_write_TCNTL(TMPWR); @@ -253,7 +253,7 @@ static int bfin_timer_set_next_event(unsigned long cycles, return 0; } -static void bfin_timer_set_mode(enum clock_event_mode mode, +static void bfin_coretmr_set_mode(enum clock_event_mode mode, struct clock_event_device *evt) { switch (mode) { @@ -285,19 +285,13 @@ static void bfin_timer_set_mode(enum clock_event_mode mode, } } -static void bfin_timer_ack(void) -{ -} - -static void __init bfin_timer_init(void) +void bfin_coretmr_init(void) { /* power up the timer, but don't enable it just yet */ bfin_write_TCNTL(TMPWR); CSYNC(); - /* - * the TSCALE prescaler counter. - */ + /* the TSCALE prescaler counter. */ bfin_write_TSCALE(TIME_SCALE - 1); bfin_write_TPERIOD(0); bfin_write_TCOUNT(0); @@ -305,48 +299,51 @@ static void __init bfin_timer_init(void) CSYNC(); } -static unsigned long __init bfin_clockevent_check(void) -{ - setup_irq(IRQ_CORETMR, &bfin_timer_irq); - return get_cclk() / TIME_SCALE; -} - -void __init setup_core_timer(void) +#ifdef CONFIG_CORE_TIMER_IRQ_L1 +__attribute__((l1_text)) +#endif +irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id) { - bfin_timer_init(); - bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL); -} -#endif /* CONFIG_TICKSOURCE_GPTMR0 */ + int cpu = smp_processor_id(); + struct clock_event_device *evt = &per_cpu(coretmr_events, cpu); -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick - */ -irqreturn_t timer_interrupt(int irq, void *dev_id) -{ - struct clock_event_device *evt = dev_id; smp_mb(); evt->event_handler(evt); - bfin_timer_ack(); return IRQ_HANDLED; } -static int __init bfin_clockevent_init(void) -{ - unsigned long timer_clk; - - timer_clk = bfin_clockevent_check(); - - bfin_timer_init(); - - clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift); - clockevent_bfin.max_delta_ns = clockevent_delta2ns(-1, &clockevent_bfin); - clockevent_bfin.min_delta_ns = clockevent_delta2ns(100, &clockevent_bfin); - clockevent_bfin.cpumask = cpumask_of(0); - clockevents_register_device(&clockevent_bfin); +static struct irqaction coretmr_irq = { + .name = "Blackfin CoreTimer", + .flags = IRQF_DISABLED | IRQF_TIMER | \ + IRQF_IRQPOLL | IRQF_PERCPU, + .handler = bfin_coretmr_interrupt, +}; - return 0; +void bfin_coretmr_clockevent_init(void) +{ + unsigned long clock_tick; + unsigned int cpu = smp_processor_id(); + struct clock_event_device *evt = &per_cpu(coretmr_events, cpu); + + evt->name = "bfin_core_timer"; + evt->rating = 350; + evt->irq = -1; + evt->shift = 32; + evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + evt->set_next_event = bfin_coretmr_set_next_event; + evt->set_mode = bfin_coretmr_set_mode; + + clock_tick = get_cclk() / TIME_SCALE; + evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift); + evt->max_delta_ns = clockevent_delta2ns(-1, evt); + evt->min_delta_ns = clockevent_delta2ns(100, evt); + + evt->cpumask = cpumask_of(cpu); + + clockevents_register_device(evt); } +#endif /* CONFIG_TICKSOURCE_CORETMR */ + void __init time_init(void) { @@ -370,5 +367,21 @@ void __init time_init(void) bfin_cs_cycles_init(); bfin_cs_gptimer0_init(); - bfin_clockevent_init(); + +#if defined(CONFIG_TICKSOURCE_CORETMR) + bfin_coretmr_init(); + setup_irq(IRQ_CORETMR, &coretmr_irq); + bfin_coretmr_clockevent_init(); +#endif + +#if defined(CONFIG_TICKSOURCE_GPTMR0) + bfin_gptmr0_init(); + setup_irq(IRQ_TIMER0, &gptmr0_irq); + gptmr0_irq.dev_id = &clockevent_gptmr0; + bfin_gptmr0_clockevent_init(&clockevent_gptmr0); +#endif + +#if !defined(CONFIG_TICKSOURCE_CORETMR) && !defined(CONFIG_TICKSOURCE_GPTMR0) +# error at least one clock event device is required +#endif } diff --git a/arch/blackfin/mach-bf561/include/mach/smp.h b/arch/blackfin/mach-bf561/include/mach/smp.h index 390c7f4ae7b3..2c8c514dd386 100644 --- a/arch/blackfin/mach-bf561/include/mach/smp.h +++ b/arch/blackfin/mach-bf561/include/mach/smp.h @@ -25,4 +25,6 @@ void platform_send_ipi_cpu(unsigned int cpu); void platform_clear_ipi(unsigned int cpu); +void bfin_local_timer_setup(void); + #endif /* !_MACH_BF561_SMP */ diff --git a/arch/blackfin/mach-bf561/smp.c b/arch/blackfin/mach-bf561/smp.c index ec93f3ef8fa3..90369429ee66 100644 --- a/arch/blackfin/mach-bf561/smp.c +++ b/arch/blackfin/mach-bf561/smp.c @@ -11,6 +11,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(boot_lock); @@ -144,3 +145,20 @@ void platform_clear_ipi(unsigned int cpu) bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (10 + cpu))); SSYNC(); } + +/* + * Setup core B's local core timer. + * In SMP, core timer is used for clock event device. + */ +void __cpuinit bfin_local_timer_setup(void) +{ +#if defined(CONFIG_TICKSOURCE_CORETMR) + bfin_coretmr_init(); + bfin_coretmr_clockevent_init(); + get_irq_chip(IRQ_CORETMR)->unmask(IRQ_CORETMR); +#else + /* Power down the core timer, just to play safe. */ + bfin_write_TCNTL(0); +#endif + +} diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index a5d243409d23..efbdb6a19418 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -1073,9 +1073,6 @@ int __init init_arch_irq(void) #endif #ifdef CONFIG_SMP -#ifdef CONFIG_TICKSOURCE_GPTMR0 - case IRQ_TIMER0: -#endif #ifdef CONFIG_TICKSOURCE_CORETMR case IRQ_CORETMR: #endif diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index eddb720c718e..b343ab3764a1 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -365,9 +365,6 @@ int __cpuinit __cpu_up(unsigned int cpu) static void __cpuinit setup_secondary(unsigned int cpu) { -#if !defined(CONFIG_TICKSOURCE_GPTMR0) - struct irq_desc *timer_desc; -#endif unsigned long ilat; bfin_write_IMASK(0); @@ -382,17 +379,6 @@ static void __cpuinit setup_secondary(unsigned int cpu) bfin_irq_flags |= IMASK_IVG15 | IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; - -#if defined(CONFIG_TICKSOURCE_GPTMR0) - /* Power down the core timer, just to play safe. */ - bfin_write_TCNTL(0); - - /* system timer0 has been setup by CoreA. */ -#else - timer_desc = irq_desc + IRQ_CORETMR; - setup_core_timer(); - timer_desc->chip->enable(IRQ_CORETMR); -#endif } void __cpuinit secondary_start_kernel(void) @@ -435,6 +421,9 @@ void __cpuinit secondary_start_kernel(void) platform_secondary_init(cpu); + /* setup local core timer */ + bfin_local_timer_setup(); + local_irq_enable(); /* -- cgit v1.2.3 From 0afc272cc6044b7a4f1318eadbfb10c4be654441 Mon Sep 17 00:00:00 2001 From: Jie Zhang Date: Tue, 5 Jan 2010 04:22:33 +0000 Subject: Blackfin: fix relocation errors with large initramfs images Since we are now discarding .exit.text at runtime instead of link time, we need to place all .text sections ahead of the .data sections. Otherwise, a really large attached initramfs may cause link errors as it pushes the PC relative relocations behind the limits of the Blackfin ISA (~16meg). The instructions in the .exit.text are unable to call back into the .text sections leading to a link failure. Signed-off-by: Jie Zhang Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/vmlinux.lds.S | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index 66799e763dc9..be4b1bbb3918 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S @@ -104,18 +104,21 @@ SECTIONS ___init_begin = .; INIT_TEXT_SECTION(PAGE_SIZE) - . = ALIGN(16); - INIT_DATA_SECTION(16) - PERCPU(4) - /* we have to discard exit text and such at runtime, not link time, to + /* We have to discard exit text and such at runtime, not link time, to * handle embedded cross-section references (alt instructions, bug - * table, eh_frame, etc...) + * table, eh_frame, etc...). We need all of our .text up front and + * .data after it for PCREL call issues. */ .exit.text : { EXIT_TEXT } + + . = ALIGN(16); + INIT_DATA_SECTION(16) + PERCPU(4) + .exit.data : { EXIT_DATA -- cgit v1.2.3 From 6feda3a6530204ad73a2dc1713c051462a1d9c49 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Tue, 5 Jan 2010 07:05:50 +0000 Subject: Blackfin: replace harcoded define with proper THREAD_SIZE macro Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index 8dc7ee1ef336..a0bc7d3e1bff 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -635,7 +635,7 @@ static __init void memory_setup(void) __bss_start, __bss_stop, _sdata, _edata, (void *)&init_thread_union, - (void *)((int)(&init_thread_union) + 0x2000), + (void *)((int)(&init_thread_union) + THREAD_SIZE), __init_begin, __init_end, (void *)_ramstart, (void *)memory_end #ifdef CONFIG_MTD_UCLINUX -- cgit v1.2.3 From 8916a1499d958fcb9086a2c49a5fa3000689bb81 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Tue, 5 Jan 2010 07:16:32 +0000 Subject: Blackfin: fix the section name of init_thread_union Use the common attribute rather than setting the section name directly. The common linker script defines expect the newer naming. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/init_task.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/init_task.c b/arch/blackfin/kernel/init_task.c index 118c5b9dedac..d3970e8acd1a 100644 --- a/arch/blackfin/kernel/init_task.c +++ b/arch/blackfin/kernel/init_task.c @@ -28,5 +28,5 @@ EXPORT_SYMBOL(init_task); * "init_task" linker map entry. */ union thread_union init_thread_union - __attribute__ ((__section__(".init_task.data"))) = { + __init_task_data = { INIT_THREAD_INFO(init_task)}; -- cgit v1.2.3 From d86bfb1600db38e8387beee0aaab4263cfd728a2 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 7 Jan 2010 04:11:17 +0000 Subject: Blackfin: initial XIP support Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- arch/blackfin/Kconfig | 16 ++++++--- arch/blackfin/Makefile | 6 +++- arch/blackfin/boot/Makefile | 23 +++++++++--- arch/blackfin/include/asm/context.S | 10 ++++++ arch/blackfin/include/asm/sections.h | 3 ++ arch/blackfin/kernel/cplb-mpu/cplbinit.c | 9 +++++ arch/blackfin/kernel/cplb-nompu/cplbinit.c | 9 +++++ arch/blackfin/kernel/entry.S | 8 ++--- arch/blackfin/kernel/setup.c | 16 +++++++-- arch/blackfin/kernel/vmlinux.lds.S | 57 ++++++++++++++++++++++++++++++ arch/blackfin/mach-common/entry.S | 17 ++++----- arch/blackfin/mach-common/head.S | 5 +++ arch/blackfin/mach-common/interrupt.S | 10 +++--- 13 files changed, 160 insertions(+), 29 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index c0d6d966adec..f46db59eac8a 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -26,9 +26,9 @@ config BLACKFIN select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER select HAVE_IDE - select HAVE_KERNEL_GZIP - select HAVE_KERNEL_BZIP2 - select HAVE_KERNEL_LZMA + select HAVE_KERNEL_GZIP if RAMKERNEL + select HAVE_KERNEL_BZIP2 if RAMKERNEL + select HAVE_KERNEL_LZMA if RAMKERNEL select HAVE_OPROFILE select ARCH_WANT_OPTIONAL_GPIOLIB @@ -407,10 +407,18 @@ config BOOT_LOAD config ROM_BASE hex "Kernel ROM Base" depends on ROMKERNEL - default "0x20040000" + default "0x20040040" range 0x20000000 0x20400000 if !(BF54x || BF561) range 0x20000000 0x30000000 if (BF54x || BF561) help + Make sure your ROM base does not include any file-header + information that is prepended to the kernel. + + For example, the bootable U-Boot format (created with + mkimage) has a 64 byte header (0x40). So while the image + you write to flash might start at say 0x20080000, you have + to add 0x40 to get the kernel's ROM base as it will come + after the header. comment "Clock/PLL Setup" diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile index d4c7177e7656..ba84206d0554 100644 --- a/arch/blackfin/Makefile +++ b/arch/blackfin/Makefile @@ -14,6 +14,9 @@ OBJCOPYFLAGS := -O binary -R .note -R .comment -S GZFLAGS := -9 KBUILD_CFLAGS += $(call cc-option,-mno-fdpic) +ifeq ($(CONFIG_ROMKERNEL),y) +KBUILD_CFLAGS += -mlong-calls +endif KBUILD_AFLAGS += $(call cc-option,-mno-fdpic) CFLAGS_MODULE += -mlong-calls LDFLAGS_MODULE += -m elf32bfin @@ -138,7 +141,7 @@ archclean: INSTALL_PATH ?= /tftpboot boot := arch/$(ARCH)/boot -BOOT_TARGETS = vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma +BOOT_TARGETS = vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma vmImage.xip PHONY += $(BOOT_TARGETS) install KBUILD_IMAGE := $(boot)/vmImage @@ -156,6 +159,7 @@ define archhelp echo ' vmImage.bz2 - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.bz2)' echo '* vmImage.gz - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.gz)' echo ' vmImage.lzma - Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.lzma)' + echo ' vmImage.xip - XIP Kernel-only image for U-Boot (arch/$(ARCH)/boot/vmImage.xip)' echo ' install - Install kernel using' echo ' (your) ~/bin/$(INSTALLKERNEL) or' echo ' (distribution) PATH: $(INSTALLKERNEL) or' diff --git a/arch/blackfin/boot/Makefile b/arch/blackfin/boot/Makefile index e9c48c6f8c1f..d1b3d6051fdf 100644 --- a/arch/blackfin/boot/Makefile +++ b/arch/blackfin/boot/Makefile @@ -8,14 +8,18 @@ MKIMAGE := $(srctree)/scripts/mkuboot.sh -targets := vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma -extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma +targets := vmImage vmImage.bin vmImage.bz2 vmImage.gz vmImage.lzma vmImage.xip +extra-y += vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma vmlinux.bin.xip + +UIMAGE_OPTS-y := +UIMAGE_OPTS-$(CONFIG_RAMKERNEL) += -a $(CONFIG_BOOT_LOAD) +UIMAGE_OPTS-$(CONFIG_ROMKERNEL) += -a $(CONFIG_ROM_BASE) -x quiet_cmd_uimage = UIMAGE $@ cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(ARCH) -O linux -T kernel \ - -C $(2) -n '$(MACHINE)-$(KERNELRELEASE)' -a $(CONFIG_BOOT_LOAD) \ + -C $(2) -n '$(MACHINE)-$(KERNELRELEASE)' \ -e $(shell $(NM) vmlinux | awk '$$NF == "__start" {print $$1}') \ - -d $< $@ + $(UIMAGE_OPTS-y) -d $< $@ $(obj)/vmlinux.bin: vmlinux FORCE $(call if_changed,objcopy) @@ -29,6 +33,12 @@ $(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE $(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE $(call if_changed,lzma) +# The mkimage tool wants 64bytes prepended to the image +quiet_cmd_mk_bin_xip = BIN $@ + cmd_mk_bin_xip = ( printf '%64s' | tr ' ' '\377' ; cat $< ) > $@ +$(obj)/vmlinux.bin.xip: $(obj)/vmlinux.bin FORCE + $(call if_changed,mk_bin_xip) + $(obj)/vmImage.bin: $(obj)/vmlinux.bin $(call if_changed,uimage,none) @@ -41,10 +51,15 @@ $(obj)/vmImage.gz: $(obj)/vmlinux.bin.gz $(obj)/vmImage.lzma: $(obj)/vmlinux.bin.lzma $(call if_changed,uimage,lzma) +$(obj)/vmImage.xip: $(obj)/vmlinux.bin.xip + $(call if_changed,uimage,none) + suffix-y := bin suffix-$(CONFIG_KERNEL_GZIP) := gz suffix-$(CONFIG_KERNEL_BZIP2) := bz2 suffix-$(CONFIG_KERNEL_LZMA) := lzma +suffix-$(CONFIG_ROMKERNEL) := xip + $(obj)/vmImage: $(obj)/vmImage.$(suffix-y) @ln -sf $(notdir $<) $@ diff --git a/arch/blackfin/include/asm/context.S b/arch/blackfin/include/asm/context.S index 5dffaf582a22..fada8e974a73 100644 --- a/arch/blackfin/include/asm/context.S +++ b/arch/blackfin/include/asm/context.S @@ -374,3 +374,13 @@ (R7:0, P5:0) = [SP++]; .endm + +.macro pseudo_long_call func:req, scratch:req +#ifdef CONFIG_ROMKERNEL + \scratch\().l = \func; + \scratch\().h = \func; + call (\scratch); +#else + call \func; +#endif +.endm diff --git a/arch/blackfin/include/asm/sections.h b/arch/blackfin/include/asm/sections.h index 42f6c53c59c6..14a3e66d9167 100644 --- a/arch/blackfin/include/asm/sections.h +++ b/arch/blackfin/include/asm/sections.h @@ -21,6 +21,9 @@ extern unsigned long memory_start, memory_end, physical_mem_end; extern char _stext_l1[], _etext_l1[], _text_l1_lma[], __weak _text_l1_len[]; extern char _sdata_l1[], _edata_l1[], _sbss_l1[], _ebss_l1[], _data_l1_lma[], __weak _data_l1_len[]; +#ifdef CONFIG_ROMKERNEL +extern char _data_lma[], _data_len[], _sinitdata[], _einitdata[], _init_data_lma[], _init_data_len[]; +#endif extern char _sdata_b_l1[], _edata_b_l1[], _sbss_b_l1[], _ebss_b_l1[], _data_b_l1_lma[], __weak _data_b_l1_len[]; extern char _stext_l2[], _etext_l2[], _sdata_l2[], _edata_l2[], diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c index 8d42b9e50dfa..30fd6417f069 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c @@ -64,6 +64,15 @@ void __init generate_cplb_tables_cpu(unsigned int cpu) icplb_tbl[cpu][i_i++].data = i_data | (addr == 0 ? CPLB_USER_RD : 0); } +#ifdef CONFIG_ROMKERNEL + /* Cover kernel XIP flash area */ + addr = CONFIG_ROM_BASE & ~(4 * 1024 * 1024 - 1); + dcplb_tbl[cpu][i_d].addr = addr; + dcplb_tbl[cpu][i_d++].data = d_data | CPLB_USER_RD; + icplb_tbl[cpu][i_i].addr = addr; + icplb_tbl[cpu][i_i++].data = i_data | CPLB_USER_RD; +#endif + /* Cover L1 memory. One 4M area for code and data each is enough. */ #if L1_DATA_A_LENGTH > 0 || L1_DATA_B_LENGTH > 0 dcplb_tbl[cpu][i_d].addr = get_l1_data_a_start_cpu(cpu); diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c index 282a7919821b..bfe75af4e8bd 100644 --- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c +++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c @@ -56,6 +56,15 @@ void __init generate_cplb_tables_cpu(unsigned int cpu) i_tbl[i_i++].data = SDRAM_IGENERIC | PAGE_SIZE_4MB; } +#ifdef CONFIG_ROMKERNEL + /* Cover kernel XIP flash area */ + addr = CONFIG_ROM_BASE & ~(4 * 1024 * 1024 - 1); + d_tbl[i_d].addr = addr; + d_tbl[i_d++].data = SDRAM_DGENERIC | PAGE_SIZE_4MB; + i_tbl[i_i].addr = addr; + i_tbl[i_i++].data = SDRAM_IGENERIC | PAGE_SIZE_4MB; +#endif + /* Cover L1 memory. One 4M area for code and data each is enough. */ if (cpu == 0) { if (L1_DATA_A_LENGTH || L1_DATA_B_LENGTH) { diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S index f27dc2292e1b..686478f5f66b 100644 --- a/arch/blackfin/kernel/entry.S +++ b/arch/blackfin/kernel/entry.S @@ -44,7 +44,7 @@ ENTRY(_ret_from_fork) sti r4; #endif /* CONFIG_IPIPE */ SP += -12; - call _schedule_tail; + pseudo_long_call _schedule_tail, p5; SP += 12; r0 = [sp + PT_IPEND]; cc = bittst(r0,1); @@ -79,7 +79,7 @@ ENTRY(_sys_vfork) r0 += 24; [--sp] = rets; SP += -12; - call _bfin_vfork; + pseudo_long_call _bfin_vfork, p2; SP += 12; rets = [sp++]; rts; @@ -90,7 +90,7 @@ ENTRY(_sys_clone) r0 += 24; [--sp] = rets; SP += -12; - call _bfin_clone; + pseudo_long_call _bfin_clone, p2; SP += 12; rets = [sp++]; rts; @@ -101,7 +101,7 @@ ENTRY(_sys_rt_sigreturn) r0 += 24; [--sp] = rets; SP += -12; - call _do_rt_sigreturn; + pseudo_long_call _do_rt_sigreturn, p2; SP += 12; rets = [sp++]; rts; diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index a0bc7d3e1bff..b54ba45db5f1 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -220,6 +220,16 @@ void __init bfin_relocate_l1_mem(void) memcpy(_stext_l2, _l2_lma, l2_len); } +#ifdef CONFIG_ROMKERNEL +void __init bfin_relocate_xip_data(void) +{ + early_shadow_stamp(); + + memcpy(_sdata, _data_lma, (unsigned long)_data_len - THREAD_SIZE + sizeof(struct thread_info)); + memcpy(_sinitdata, _init_data_lma, (unsigned long)_init_data_len); +} +#endif + /* add_memory_region to memmap */ static void __init add_memory_region(unsigned long long start, unsigned long long size, int type) @@ -504,7 +514,7 @@ static __init void memory_setup(void) #endif unsigned long max_mem; - _rambase = (unsigned long)_stext; + _rambase = CONFIG_BOOT_LOAD; _ramstart = (unsigned long)_end; if (DMA_UNCACHED_REGION > (_ramend - _ramstart)) { @@ -1261,8 +1271,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) seq_printf(m, "board memory\t: %ld kB (0x%p -> 0x%p)\n", physical_mem_end >> 10, (void *)0, (void *)physical_mem_end); seq_printf(m, "kernel memory\t: %d kB (0x%p -> 0x%p)\n", - ((int)memory_end - (int)_stext) >> 10, - _stext, + ((int)memory_end - (int)_rambase) >> 10, + (void *)_rambase, (void *)memory_end); seq_printf(m, "\n"); diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index be4b1bbb3918..984c78172397 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S @@ -15,7 +15,12 @@ _jiffies = _jiffies_64; SECTIONS { +#ifdef CONFIG_RAMKERNEL . = CONFIG_BOOT_LOAD; +#else + . = CONFIG_ROM_BASE; +#endif + /* Neither the text, ro_data or bss section need to be aligned * So pack them back to back */ @@ -31,6 +36,12 @@ SECTIONS LOCK_TEXT IRQENTRY_TEXT KPROBES_TEXT +#ifdef CONFIG_ROMKERNEL + __sinittext = .; + INIT_TEXT + __einittext = .; + EXIT_TEXT +#endif *(.text.*) *(.fixup) @@ -50,8 +61,14 @@ SECTIONS /* Just in case the first read only is a 32-bit access */ RO_DATA(4) + __rodata_end = .; +#ifdef CONFIG_ROMKERNEL + . = CONFIG_BOOT_LOAD; + .bss : AT(__rodata_end) +#else .bss : +#endif { . = ALIGN(4); ___bss_start = .; @@ -67,7 +84,11 @@ SECTIONS ___bss_stop = .; } +#if defined(CONFIG_ROMKERNEL) + .data : AT(LOADADDR(.bss) + SIZEOF(.bss)) +#else .data : +#endif { __sdata = .; /* This gets done first, so the glob doesn't suck it in */ @@ -94,6 +115,8 @@ SECTIONS __edata = .; } + __data_lma = LOADADDR(.data); + __data_len = SIZEOF(.data); /* The init section should be last, so when we free it, it goes into * the general memory pool, and (hopefully) will decrease fragmentation @@ -103,6 +126,7 @@ SECTIONS . = ALIGN(PAGE_SIZE); ___init_begin = .; +#ifdef CONFIG_RAMKERNEL INIT_TEXT_SECTION(PAGE_SIZE) /* We have to discard exit text and such at runtime, not link time, to @@ -125,6 +149,35 @@ SECTIONS } .text_l1 L1_CODE_START : AT(LOADADDR(.exit.data) + SIZEOF(.exit.data)) +#else + .init.data : AT(__data_lma + __data_len) + { + __sinitdata = .; + INIT_DATA + INIT_SETUP(16) + INIT_CALLS + CON_INITCALL + SECURITY_INITCALL + INIT_RAM_FS + + . = ALIGN(4); + ___per_cpu_load = .; + ___per_cpu_start = .; + *(.data.percpu.first) + *(.data.percpu.page_aligned) + *(.data.percpu) + *(.data.percpu.shared_aligned) + ___per_cpu_end = .; + + EXIT_DATA + __einitdata = .; + } + __init_data_lma = LOADADDR(.init.data); + __init_data_len = SIZEOF(.init.data); + __init_data_end = .; + + .text_l1 L1_CODE_START : AT(__init_data_lma + __init_data_len) +#endif { . = ALIGN(4); __stext_l1 = .; @@ -205,7 +258,11 @@ SECTIONS /* Force trailing alignment of our init section so that when we * free our init memory, we don't leave behind a partial page. */ +#ifdef CONFIG_RAMKERNEL . = __l2_lma + __l2_len; +#else + . = __init_data_end; +#endif . = ALIGN(PAGE_SIZE); ___init_end = .; diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 0df7ef200f9d..ccfa7c490ff9 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -405,7 +405,7 @@ ENTRY(_double_fault) r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; - call _double_fault_c; + pseudo_long_call _double_fault_c, p5; SP += 12; .L_double_fault_panic: JUMP .L_double_fault_panic @@ -447,7 +447,7 @@ ENTRY(_exception_to_level5) r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; - call _trap_c; + pseudo_long_call _trap_c, p4; SP += 12; /* If interrupts were off during the exception (IPEND[4] = 1), turn them off @@ -551,7 +551,7 @@ ENTRY(_kernel_execve) p0 = sp; sp += -16; [sp + 12] = p0; - call _do_execve; + pseudo_long_call _do_execve, p5; SP += 16; cc = r0 == 0; if ! cc jump .Lexecve_failed; @@ -704,7 +704,7 @@ ENTRY(_system_call) sp += 4; SP += -12; - call _schedule; + pseudo_long_call _schedule, p4; SP += 12; jump .Lresume_userspace_1; @@ -723,7 +723,7 @@ ENTRY(_system_call) r0 = sp; SP += -12; - call _do_notify_resume; + pseudo_long_call _do_notify_resume, p5; SP += 12; .Lsyscall_really_exit: @@ -736,7 +736,7 @@ ENDPROC(_system_call) * this symbol need not be global anyways, so ... */ _sys_trace: - call _syscall_trace; + pseudo_long_call _syscall_trace, p5; /* Execute the appropriate system call */ @@ -760,7 +760,7 @@ _sys_trace: SP += 24; [sp + PT_R0] = r0; - call _syscall_trace; + pseudo_long_call _syscall_trace, p5; jump .Lresume_userspace; ENDPROC(_sys_trace) @@ -1007,7 +1007,8 @@ ENTRY(_schedule_and_signal_from_int) r0 = sp; sp += -12; - call _finish_atomic_sections; + + pseudo_long_call _finish_atomic_sections, p5; sp += 12; jump.s .Lresume_userspace; ENDPROC(_schedule_and_signal_from_int) diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S index cf037782c8ad..4391621d9048 100644 --- a/arch/blackfin/mach-common/head.S +++ b/arch/blackfin/mach-common/head.S @@ -186,6 +186,11 @@ ENTRY(__start) /* Put The Code for PLL Programming and SDRAM Programming in L1 ISRAM */ call _bfin_relocate_l1_mem; + +#ifdef CONFIG_ROMKERNEL + call _bfin_relocate_xip_data; +#endif + #ifdef CONFIG_BFIN_KERNEL_CLOCK /* Only use on-chip scratch space for stack when absolutely required * to avoid Anomaly 05000227 ... we know the init_clocks() func only diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 8085ff1cce00..df984960cf90 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -109,10 +109,10 @@ __common_int_entry: cc = r0 == 0; if cc jump .Lcommon_restore_context; #else /* CONFIG_IPIPE */ - call _do_irq; + pseudo_long_call _do_irq, p2; SP += 12; #endif /* CONFIG_IPIPE */ - call _return_from_int; + pseudo_long_call _return_from_int, p2; .Lcommon_restore_context: RESTORE_CONTEXT rti; @@ -168,7 +168,7 @@ ENTRY(_evt_ivhw) r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */ SP += -12; - call _trap_c; + pseudo_long_call _trap_c, p5; SP += 12; #ifdef EBIU_ERRMST @@ -179,7 +179,7 @@ ENTRY(_evt_ivhw) w[p0] = r0.l; #endif - call _ret_from_exception; + pseudo_long_call _ret_from_exception, p2; .Lcommon_restore_all_sys: RESTORE_ALL_SYS @@ -223,7 +223,7 @@ ENTRY(_evt_system_call) #ifdef CONFIG_FRAME_POINTER fp = 0; #endif - call _system_call; + pseudo_long_call _system_call, p2; jump .Lcommon_restore_context; ENDPROC(_evt_system_call) -- cgit v1.2.3 From 48a74f9d1b381471397097851531c4e392f97451 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 8 Jan 2010 20:06:22 +0100 Subject: Blackfin: fix decoding of opcodes 41-47 in decode_instruction() This condition allowed only decoding of opcode 0x0040 Signed-off-by: Roel Kluin Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index d3cbcd6bd985..870d74b1b407 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -712,7 +712,7 @@ static void decode_instruction(unsigned short *address) verbose_printk("RTE"); else if (opcode == 0x0025) verbose_printk("EMUEXCPT"); - else if (opcode == 0x0040 && opcode <= 0x0047) + else if (opcode >= 0x0040 && opcode <= 0x0047) verbose_printk("STI R%i", opcode & 7); else if (opcode >= 0x0050 && opcode <= 0x0057) verbose_printk("JUMP (P%i)", opcode & 7); -- cgit v1.2.3 From 8d0177dbcbad26ffd451b607c8fa74295d81e7b9 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sat, 9 Jan 2010 00:48:01 +0000 Subject: Blackfin: kgdb: mark all local funcs/structs static Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/kgdb.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c index 34c7c3ed2c9c..2c501ceb1e55 100644 --- a/arch/blackfin/kernel/kgdb.c +++ b/arch/blackfin/kernel/kgdb.c @@ -145,7 +145,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) #endif } -struct hw_breakpoint { +static struct hw_breakpoint { unsigned int occupied:1; unsigned int skip:1; unsigned int enabled:1; @@ -155,7 +155,7 @@ struct hw_breakpoint { unsigned int addr; } breakinfo[HW_WATCHPOINT_NUM]; -int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type) +static int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type) { int breakno; int bfin_type; @@ -202,7 +202,7 @@ int bfin_set_hw_break(unsigned long addr, int len, enum kgdb_bptype type) return -ENOSPC; } -int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type) +static int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type) { int breakno; int bfin_type; @@ -230,7 +230,7 @@ int bfin_remove_hw_break(unsigned long addr, int len, enum kgdb_bptype type) return 0; } -void bfin_remove_all_hw_break(void) +static void bfin_remove_all_hw_break(void) { int breakno; @@ -242,7 +242,7 @@ void bfin_remove_all_hw_break(void) breakinfo[breakno].type = TYPE_DATA_WATCHPOINT; } -void bfin_correct_hw_break(void) +static void bfin_correct_hw_break(void) { int breakno; unsigned int wpiactl = 0; -- cgit v1.2.3 From c6669c223a409199a45bb8f31a2e160ee26d19cc Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 13 Jan 2010 06:09:34 +0000 Subject: Blackfin: fix up mm locking in address dumping The locking code in the address dumper needs to grab the mm's mmap_sem so that other CPUs do not get an inconsistent view. On UP systems this really wasn't a problem, but it is easy to trigger a race on SMP systems when another CPU removes a mapping. Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/traps.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 870d74b1b407..85766805b03a 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -138,6 +138,12 @@ static void decode_address(char *buf, unsigned long address) if (!mm) continue; + if (!down_read_trylock(&mm->mmap_sem)) { + if (!in_atomic) + mmput(mm); + continue; + } + for (n = rb_first(&mm->mm_rb); n; n = rb_next(n)) { struct vm_area_struct *vma; @@ -177,6 +183,7 @@ static void decode_address(char *buf, unsigned long address) sprintf(buf, "[ %s vma:0x%lx-0x%lx]", name, vma->vm_start, vma->vm_end); + up_read(&mm->mmap_sem); if (!in_atomic) mmput(mm); @@ -186,11 +193,16 @@ static void decode_address(char *buf, unsigned long address) goto done; } } + + up_read(&mm->mmap_sem); if (!in_atomic) mmput(mm); } - /* we were unable to find this address anywhere */ + /* + * we were unable to find this address anywhere, + * or some MMs were skipped because they were in use. + */ sprintf(buf, "/* kernel dynamic memory */"); done: -- cgit v1.2.3 From 5e8d3210b5bffbe64afca9152241284a46611c7e Mon Sep 17 00:00:00 2001 From: Barry Song Date: Tue, 19 Jan 2010 11:01:08 +0000 Subject: Blackfin: fill out the signal si_addr when sending a SIGBUS/SIGSEGV Some userspace applications use this member in diagnosing crashes. It also makes some LTP tests pass (i.e. the Blackfin arch behaves more like everyone else). Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/traps.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 85766805b03a..4eaca2d1deed 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -260,9 +260,7 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON int j; #endif -#ifdef CONFIG_DEBUG_HUNT_FOR_ZERO unsigned int cpu = raw_smp_processor_id(); -#endif const char *strerror = NULL; int sig = 0; siginfo_t info; @@ -651,7 +649,17 @@ asmlinkage notrace void trap_c(struct pt_regs *fp) { info.si_signo = sig; info.si_errno = 0; - info.si_addr = (void __user *)fp->pc; + switch (trapnr) { + case VEC_CPLB_VL: + case VEC_MISALI_D: + case VEC_CPLB_M: + case VEC_CPLB_MHIT: + info.si_addr = (void __user *)cpu_pda[cpu].dcplb_fault_addr; + break; + default: + info.si_addr = (void __user *)fp->pc; + break; + } force_sig_info(sig, &info, current); } -- cgit v1.2.3 From 726e96561e4704278bc5197238f6459e1a63aa77 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 20 Jan 2010 07:25:31 +0000 Subject: Blackfin: respect the L1 kconfig optimization in the MPU code Restore support for CONFIG_EXCPT_IRQ_SYSC_L1 in the MPU CPLB manager. Signed-off-by: Barry Song Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/cplb-mpu/cplbmgr.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c index 7e6383dc7b20..87b25b1b30ed 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c @@ -31,6 +31,12 @@ int nr_dcplb_miss[NR_CPUS], nr_icplb_miss[NR_CPUS]; int nr_icplb_supv_miss[NR_CPUS], nr_dcplb_prot[NR_CPUS]; int nr_cplb_flush[NR_CPUS]; +#ifdef CONFIG_EXCPT_IRQ_SYSC_L1 +#define MGR_ATTR __attribute__((l1_text)) +#else +#define MGR_ATTR +#endif + /* * Given the contents of the status register, return the index of the * CPLB that caused the fault. @@ -59,7 +65,7 @@ static int icplb_rr_index[NR_CPUS], dcplb_rr_index[NR_CPUS]; /* * Find an ICPLB entry to be evicted and return its index. */ -static int evict_one_icplb(unsigned int cpu) +MGR_ATTR static int evict_one_icplb(unsigned int cpu) { int i; for (i = first_switched_icplb; i < MAX_CPLBS; i++) @@ -74,7 +80,7 @@ static int evict_one_icplb(unsigned int cpu) return i; } -static int evict_one_dcplb(unsigned int cpu) +MGR_ATTR static int evict_one_dcplb(unsigned int cpu) { int i; for (i = first_switched_dcplb; i < MAX_CPLBS; i++) @@ -89,7 +95,7 @@ static int evict_one_dcplb(unsigned int cpu) return i; } -static noinline int dcplb_miss(unsigned int cpu) +MGR_ATTR static noinline int dcplb_miss(unsigned int cpu) { unsigned long addr = bfin_read_DCPLB_FAULT_ADDR(); int status = bfin_read_DCPLB_STATUS(); @@ -163,7 +169,7 @@ static noinline int dcplb_miss(unsigned int cpu) return 0; } -static noinline int icplb_miss(unsigned int cpu) +MGR_ATTR static noinline int icplb_miss(unsigned int cpu) { unsigned long addr = bfin_read_ICPLB_FAULT_ADDR(); int status = bfin_read_ICPLB_STATUS(); @@ -269,7 +275,7 @@ static noinline int icplb_miss(unsigned int cpu) return 0; } -static noinline int dcplb_protection_fault(unsigned int cpu) +MGR_ATTR static noinline int dcplb_protection_fault(unsigned int cpu) { int status = bfin_read_DCPLB_STATUS(); @@ -289,7 +295,7 @@ static noinline int dcplb_protection_fault(unsigned int cpu) return CPLB_PROT_VIOL; } -int cplb_hdr(int seqstat, struct pt_regs *regs) +MGR_ATTR int cplb_hdr(int seqstat, struct pt_regs *regs) { int cause = seqstat & 0x3f; unsigned int cpu = raw_smp_processor_id(); -- cgit v1.2.3 From 60ffdb36547da2397d6cfefe9c752ebad16524f6 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 20 Jan 2010 10:56:24 +0000 Subject: Blackfin: implement nmi_watchdog for SMP on BF561 Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger --- arch/blackfin/Kconfig.debug | 9 + arch/blackfin/include/asm/irq.h | 4 + arch/blackfin/include/asm/nmi.h | 12 ++ arch/blackfin/include/asm/smp.h | 1 + arch/blackfin/kernel/Makefile | 1 + arch/blackfin/kernel/nmi.c | 313 ++++++++++++++++++++++++++++++++++ arch/blackfin/kernel/time-ts.c | 4 + arch/blackfin/mach-common/interrupt.S | 18 +- 8 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 arch/blackfin/include/asm/nmi.h create mode 100644 arch/blackfin/kernel/nmi.c (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig.debug b/arch/blackfin/Kconfig.debug index 87f195ee2e06..1460d7b5edc1 100644 --- a/arch/blackfin/Kconfig.debug +++ b/arch/blackfin/Kconfig.debug @@ -238,6 +238,15 @@ config EARLY_PRINTK all of this lives in the init section and is thrown away after the kernel boots completely. +config NMI_WATCHDOG + bool "Enable NMI watchdog to help debugging lockup on SMP" + default n + depends on (SMP && !BFIN_SCRATCH_REG_RETN) + help + If any CPU in the system does not execute the period local timer + interrupt for more than 5 seconds, then the NMI handler dumps debug + information. This information can be used to debug the lockup. + config CPLB_INFO bool "Display the CPLB information" help diff --git a/arch/blackfin/include/asm/irq.h b/arch/blackfin/include/asm/irq.h index 89de539ed010..12f4060a31b0 100644 --- a/arch/blackfin/include/asm/irq.h +++ b/arch/blackfin/include/asm/irq.h @@ -38,4 +38,8 @@ #include +#ifdef CONFIG_NMI_WATCHDOG +# define ARCH_HAS_NMI_WATCHDOG +#endif + #endif /* _BFIN_IRQ_H_ */ diff --git a/arch/blackfin/include/asm/nmi.h b/arch/blackfin/include/asm/nmi.h new file mode 100644 index 000000000000..b9caac4fcfd8 --- /dev/null +++ b/arch/blackfin/include/asm/nmi.h @@ -0,0 +1,12 @@ +/* + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 + */ + +#ifndef _BFIN_NMI_H_ +#define _BFIN_NMI_H_ + +#include + +#endif diff --git a/arch/blackfin/include/asm/smp.h b/arch/blackfin/include/asm/smp.h index 29fb88219470..7f26de09ca9c 100644 --- a/arch/blackfin/include/asm/smp.h +++ b/arch/blackfin/include/asm/smp.h @@ -22,6 +22,7 @@ extern char coreb_trampoline_start, coreb_trampoline_end; struct corelock_slot { int lock; }; +extern struct corelock_slot corelock; void smp_icache_flush_range_others(unsigned long start, unsigned long end); diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index a8ddbc8ed5af..346a421f1562 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_CPLB_INFO) += cplbinfo.o obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_KGDB) += kgdb.o obj-$(CONFIG_KGDB_TESTS) += kgdb_test.o +obj-$(CONFIG_NMI_WATCHDOG) += nmi.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_EARLY_PRINTK) += shadow_console.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/blackfin/kernel/nmi.c b/arch/blackfin/kernel/nmi.c new file mode 100644 index 000000000000..19093c17632b --- /dev/null +++ b/arch/blackfin/kernel/nmi.c @@ -0,0 +1,313 @@ +/* + * Blackfin nmi_watchdog Driver + * + * Originally based on bfin_wdt.c + * Copyright 2010-2010 Analog Devices Inc. + * Graff Yang + * + * Enter bugs at http://blackfin.uclinux.org/ + * + * Licensed under the GPL-2 or later. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */ +#define WDOG_EXPIRED 0x8000 + +/* Masks for WDEV field in WDOG_CTL register */ +#define ICTL_RESET 0x0 +#define ICTL_NMI 0x2 +#define ICTL_GPI 0x4 +#define ICTL_NONE 0x6 +#define ICTL_MASK 0x6 + +/* Masks for WDEN field in WDOG_CTL register */ +#define WDEN_MASK 0x0FF0 +#define WDEN_ENABLE 0x0000 +#define WDEN_DISABLE 0x0AD0 + +#define DRV_NAME "nmi-wdt" + +#define NMI_WDT_TIMEOUT 5 /* 5 seconds */ +#define NMI_CHECK_TIMEOUT (4 * HZ) /* 4 seconds in jiffies */ +static int nmi_wdt_cpu = 1; + +static unsigned int timeout = NMI_WDT_TIMEOUT; +static int nmi_active; + +static unsigned short wdoga_ctl; +static unsigned int wdoga_cnt; +static struct corelock_slot saved_corelock; +static atomic_t nmi_touched[NR_CPUS]; +static struct timer_list ntimer; + +enum { + COREA_ENTER_NMI = 0, + COREA_EXIT_NMI, + COREB_EXIT_NMI, + + NMI_EVENT_NR, +}; +static unsigned long nmi_event __attribute__ ((__section__(".l2.bss"))); + +/* we are in nmi, non-atomic bit ops is safe */ +static inline void set_nmi_event(int event) +{ + __set_bit(event, &nmi_event); +} + +static inline void wait_nmi_event(int event) +{ + while (!test_bit(event, &nmi_event)) + barrier(); + __clear_bit(event, &nmi_event); +} + +static inline void send_corea_nmi(void) +{ + wdoga_ctl = bfin_read_WDOGA_CTL(); + wdoga_cnt = bfin_read_WDOGA_CNT(); + + bfin_write_WDOGA_CTL(WDEN_DISABLE); + bfin_write_WDOGA_CNT(0); + bfin_write_WDOGA_CTL(WDEN_ENABLE | ICTL_NMI); +} + +static inline void restore_corea_nmi(void) +{ + bfin_write_WDOGA_CTL(WDEN_DISABLE); + bfin_write_WDOGA_CTL(WDOG_EXPIRED | WDEN_DISABLE | ICTL_NONE); + + bfin_write_WDOGA_CNT(wdoga_cnt); + bfin_write_WDOGA_CTL(wdoga_ctl); +} + +static inline void save_corelock(void) +{ + saved_corelock = corelock; + corelock.lock = 0; +} + +static inline void restore_corelock(void) +{ + corelock = saved_corelock; +} + + +static inline void nmi_wdt_keepalive(void) +{ + bfin_write_WDOGB_STAT(0); +} + +static inline void nmi_wdt_stop(void) +{ + bfin_write_WDOGB_CTL(WDEN_DISABLE); +} + +/* before calling this function, you must stop the WDT */ +static inline void nmi_wdt_clear(void) +{ + /* clear TRO bit, disable event generation */ + bfin_write_WDOGB_CTL(WDOG_EXPIRED | WDEN_DISABLE | ICTL_NONE); +} + +static inline void nmi_wdt_start(void) +{ + bfin_write_WDOGB_CTL(WDEN_ENABLE | ICTL_NMI); +} + +static inline int nmi_wdt_running(void) +{ + return ((bfin_read_WDOGB_CTL() & WDEN_MASK) != WDEN_DISABLE); +} + +static inline int nmi_wdt_set_timeout(unsigned long t) +{ + u32 cnt, max_t, sclk; + int run; + + sclk = get_sclk(); + max_t = -1 / sclk; + cnt = t * sclk; + if (t > max_t) { + pr_warning("NMI: timeout value is too large\n"); + return -EINVAL; + } + + run = nmi_wdt_running(); + nmi_wdt_stop(); + bfin_write_WDOGB_CNT(cnt); + if (run) + nmi_wdt_start(); + + timeout = t; + + return 0; +} + +int check_nmi_wdt_touched(void) +{ + unsigned int this_cpu = smp_processor_id(); + unsigned int cpu; + + cpumask_t mask = cpu_online_map; + + if (!atomic_read(&nmi_touched[this_cpu])) + return 0; + + atomic_set(&nmi_touched[this_cpu], 0); + + cpu_clear(this_cpu, mask); + for_each_cpu_mask(cpu, mask) { + invalidate_dcache_range((unsigned long)(&nmi_touched[cpu]), + (unsigned long)(&nmi_touched[cpu])); + if (!atomic_read(&nmi_touched[cpu])) + return 0; + atomic_set(&nmi_touched[cpu], 0); + } + + return 1; +} + +static void nmi_wdt_timer(unsigned long data) +{ + if (check_nmi_wdt_touched()) + nmi_wdt_keepalive(); + + mod_timer(&ntimer, jiffies + NMI_CHECK_TIMEOUT); +} + +static int __init init_nmi_wdt(void) +{ + nmi_wdt_set_timeout(timeout); + nmi_wdt_start(); + nmi_active = true; + + init_timer(&ntimer); + ntimer.function = nmi_wdt_timer; + ntimer.expires = jiffies + NMI_CHECK_TIMEOUT; + add_timer(&ntimer); + + pr_info("nmi_wdt: initialized: timeout=%d sec\n", timeout); + return 0; +} +device_initcall(init_nmi_wdt); + +void touch_nmi_watchdog(void) +{ + atomic_set(&nmi_touched[smp_processor_id()], 1); +} + +/* Suspend/resume support */ +#ifdef CONFIG_PM +static int nmi_wdt_suspend(struct sys_device *dev, pm_message_t state) +{ + nmi_wdt_stop(); + return 0; +} + +static int nmi_wdt_resume(struct sys_device *dev) +{ + if (nmi_active) + nmi_wdt_start(); + return 0; +} + +static struct sysdev_class nmi_sysclass = { + .name = DRV_NAME, + .resume = nmi_wdt_resume, + .suspend = nmi_wdt_suspend, +}; + +static struct sys_device device_nmi_wdt = { + .id = 0, + .cls = &nmi_sysclass, +}; + +static int __init init_nmi_wdt_sysfs(void) +{ + int error; + + if (!nmi_active) + return 0; + + error = sysdev_class_register(&nmi_sysclass); + if (!error) + error = sysdev_register(&device_nmi_wdt); + return error; +} +late_initcall(init_nmi_wdt_sysfs); + +#endif /* CONFIG_PM */ + + +asmlinkage notrace void do_nmi(struct pt_regs *fp) +{ + unsigned int cpu = smp_processor_id(); + nmi_enter(); + + cpu_pda[cpu].__nmi_count += 1; + + if (cpu == nmi_wdt_cpu) { + /* CoreB goes here first */ + + /* reload the WDOG_STAT */ + nmi_wdt_keepalive(); + + /* clear nmi interrupt for CoreB */ + nmi_wdt_stop(); + nmi_wdt_clear(); + + /* trigger NMI interrupt of CoreA */ + send_corea_nmi(); + + /* waiting CoreB to enter NMI */ + wait_nmi_event(COREA_ENTER_NMI); + + /* recover WDOGA's settings */ + restore_corea_nmi(); + + save_corelock(); + + /* corelock is save/cleared, CoreA is dummping messages */ + + wait_nmi_event(COREA_EXIT_NMI); + } else { + /* OK, CoreA entered NMI */ + set_nmi_event(COREA_ENTER_NMI); + } + + pr_emerg("\nNMI Watchdog detected LOCKUP, dump for CPU %d\n", cpu); + dump_bfin_process(fp); + dump_bfin_mem(fp); + show_regs(fp); + dump_bfin_trace_buffer(); + show_stack(current, (unsigned long *)fp); + + if (cpu == nmi_wdt_cpu) { + pr_emerg("This fault is not recoverable, sorry!\n"); + + /* CoreA dump finished, restore the corelock */ + restore_corelock(); + + set_nmi_event(COREB_EXIT_NMI); + } else { + /* CoreB dump finished, notice the CoreA we are done */ + set_nmi_event(COREA_EXIT_NMI); + + /* synchronize with CoreA */ + wait_nmi_event(COREB_EXIT_NMI); + } + + nmi_exit(); +} diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c index a351f97c87a3..41a907596c70 100644 --- a/arch/blackfin/kernel/time-ts.c +++ b/arch/blackfin/kernel/time-ts.c @@ -21,6 +21,7 @@ #include #include #include +#include /* Accelerators for sched_clock() * convert from cycles(64bits) => nanoseconds (64bits) @@ -309,6 +310,9 @@ irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id) smp_mb(); evt->event_handler(evt); + + touch_nmi_watchdog(); + return IRQ_HANDLED; } diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 0a0c088ead8c..cee62cf4acd4 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -194,12 +194,28 @@ ENTRY(_evt_ivhw) ENDPROC(_evt_ivhw) /* Interrupt routine for evt2 (NMI). - * We don't actually use this, so just return. * For inner circle type details, please see: * http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:nmi */ ENTRY(_evt_nmi) +#ifndef CONFIG_NMI_WATCHDOG .weak _evt_nmi +#else + /* Not take account of CPLBs, this handler will not return */ + SAVE_ALL_SYS + r0 = sp; + r1 = retn; + [sp + PT_PC] = r1; + trace_buffer_save(p4,r5); + + ANOMALY_283_315_WORKAROUND(p4, r5) + + SP += -12; + call _do_nmi; + SP += 12; +1: + jump 1b; +#endif rtn; ENDPROC(_evt_nmi) -- cgit v1.2.3 From aebfef03249819886a7f9c981940cbd48d82ea47 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 22 Jan 2010 07:35:20 -0500 Subject: Blackfin: implement ftrace mcount test Signed-off-by: Mike Frysinger --- arch/blackfin/Kconfig | 1 + arch/blackfin/kernel/ftrace-entry.S | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index f46db59eac8a..3123aa49ff79 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -25,6 +25,7 @@ config BLACKFIN def_bool y select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER + select HAVE_FUNCTION_TRACE_MCOUNT_TEST select HAVE_IDE select HAVE_KERNEL_GZIP if RAMKERNEL select HAVE_KERNEL_BZIP2 if RAMKERNEL diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S index 76dd4fbcd17a..db3a51b0af21 100644 --- a/arch/blackfin/kernel/ftrace-entry.S +++ b/arch/blackfin/kernel/ftrace-entry.S @@ -1,7 +1,7 @@ /* * mcount and friends -- ftrace stuff * - * Copyright (C) 2009 Analog Devices Inc. + * Copyright (C) 2009-2010 Analog Devices Inc. * Licensed under the GPL-2 or later. */ @@ -21,6 +21,15 @@ * function will be waiting there. mmmm pie. */ ENTRY(__mcount) +#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST + /* optional micro optimization: return if stopped */ + p1.l = _function_trace_stop; + p1.h = _function_trace_stop; + r3 = [p1]; + cc = r3 == 0; + if ! cc jump _ftrace_stub (bp); +#endif + /* save third function arg early so we can do testing below */ [--sp] = r2; -- cgit v1.2.3 From b73faf74493fd1bc75a8938aa5d296facf50a650 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 22 Jan 2010 07:59:32 -0500 Subject: Blackfin: support new ftrace frame pointer semantics Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/ftrace-entry.S | 12 +++++++++--- arch/blackfin/kernel/ftrace.c | 6 ++++-- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S index db3a51b0af21..d66446b572c0 100644 --- a/arch/blackfin/kernel/ftrace-entry.S +++ b/arch/blackfin/kernel/ftrace-entry.S @@ -115,9 +115,12 @@ ENTRY(_ftrace_graph_caller) [--sp] = r1; [--sp] = rets; - /* prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) */ - r0 = sp; - r1 = rets; + /* prepare_ftrace_return(parent, self_addr, frame_pointer) */ + r0 = sp; /* unsigned long *parent */ + r1 = rets; /* unsigned long self_addr */ +#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST + r2 = fp; /* unsigned long frame_pointer */ +#endif r0 += 16; /* skip the 4 local regs on stack */ r1 += -MCOUNT_INSN_SIZE; call _prepare_ftrace_return; @@ -136,6 +139,9 @@ ENTRY(_return_to_handler) [--sp] = r1; /* get original return address */ +#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST + r0 = fp; /* Blackfin is sane, so omit this */ +#endif call _ftrace_return_to_handler; rets = r0; diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c index f2c85ac6f2da..a61d948ea925 100644 --- a/arch/blackfin/kernel/ftrace.c +++ b/arch/blackfin/kernel/ftrace.c @@ -16,7 +16,8 @@ * Hook the return address and push it in the stack of return addrs * in current thread info. */ -void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, + unsigned long frame_pointer) { struct ftrace_graph_ent trace; unsigned long return_hooker = (unsigned long)&return_to_handler; @@ -24,7 +25,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) if (unlikely(atomic_read(¤t->tracing_graph_pause))) return; - if (ftrace_push_return_trace(*parent, self_addr, &trace.depth, 0) == -EBUSY) + if (ftrace_push_return_trace(*parent, self_addr, &trace.depth, + frame_pointer) == -EBUSY) return; trace.func = self_addr; -- cgit v1.2.3 From 64b33a00dc39dceac04dbd7622ab14017e074712 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Mon, 25 Jan 2010 03:47:43 +0000 Subject: Blackfin: split watchdog definitions into a dedicated header file This allows things to be shared between the different watchdog sources. Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/bfin_watchdog.h | 30 ++++++++++++++++++++++++++++++ arch/blackfin/kernel/nmi.c | 16 +--------------- 2 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 arch/blackfin/include/asm/bfin_watchdog.h (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/bfin_watchdog.h b/arch/blackfin/include/asm/bfin_watchdog.h new file mode 100644 index 000000000000..dce09829a095 --- /dev/null +++ b/arch/blackfin/include/asm/bfin_watchdog.h @@ -0,0 +1,30 @@ +/* + * bfin_watchdog.h - Blackfin watchdog definitions + * + * Copyright 2006-2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef _BFIN_WATCHDOG_H +#define _BFIN_WATCHDOG_H + +/* Bit in SWRST that indicates boot caused by watchdog */ +#define SWRST_RESET_WDOG 0x4000 + +/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */ +#define WDOG_EXPIRED 0x8000 + +/* Masks for WDEV field in WDOG_CTL register */ +#define ICTL_RESET 0x0 +#define ICTL_NMI 0x2 +#define ICTL_GPI 0x4 +#define ICTL_NONE 0x6 +#define ICTL_MASK 0x6 + +/* Masks for WDEN field in WDOG_CTL register */ +#define WDEN_MASK 0x0FF0 +#define WDEN_ENABLE 0x0000 +#define WDEN_DISABLE 0x0AD0 + +#endif diff --git a/arch/blackfin/kernel/nmi.c b/arch/blackfin/kernel/nmi.c index 19093c17632b..0b5f72f17fd0 100644 --- a/arch/blackfin/kernel/nmi.c +++ b/arch/blackfin/kernel/nmi.c @@ -20,21 +20,7 @@ #include #include #include - -/* Bit in WDOG_CTL that indicates watchdog has expired (WDR0) */ -#define WDOG_EXPIRED 0x8000 - -/* Masks for WDEV field in WDOG_CTL register */ -#define ICTL_RESET 0x0 -#define ICTL_NMI 0x2 -#define ICTL_GPI 0x4 -#define ICTL_NONE 0x6 -#define ICTL_MASK 0x6 - -/* Masks for WDEN field in WDOG_CTL register */ -#define WDEN_MASK 0x0FF0 -#define WDEN_ENABLE 0x0000 -#define WDEN_DISABLE 0x0AD0 +#include #define DRV_NAME "nmi-wdt" -- cgit v1.2.3 From 6c2b7072a7035837998da38809f98e4182e4c41c Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 27 Jan 2010 11:16:32 +0000 Subject: Blackfin: add support for cpufreq on SMP systems Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger --- arch/blackfin/Kconfig | 1 - arch/blackfin/include/asm/time.h | 7 +- arch/blackfin/kernel/time-ts.c | 4 + arch/blackfin/mach-common/cpufreq.c | 155 +++++++++++++++++++++--------------- 4 files changed, 101 insertions(+), 66 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index ed339b83f5af..970df5b5c525 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -1237,7 +1237,6 @@ config PM_BFIN_WAKE_GP endmenu menu "CPU Frequency scaling" - depends on !SMP source "drivers/cpufreq/Kconfig" diff --git a/arch/blackfin/include/asm/time.h b/arch/blackfin/include/asm/time.h index 767b938ccf8c..9ca7db844d10 100644 --- a/arch/blackfin/include/asm/time.h +++ b/arch/blackfin/include/asm/time.h @@ -23,9 +23,7 @@ */ #ifndef CONFIG_CPU_FREQ -#define TIME_SCALE 1 -#define __bfin_cycles_off (0) -#define __bfin_cycles_mod (0) +# define TIME_SCALE 1 #else /* * Blackfin CPU frequency scaling supports max Core Clock 1, 1/2 and 1/4 . @@ -33,8 +31,11 @@ * adjust the Core Timer Presale Register. This way we don't lose time. */ #define TIME_SCALE 4 + +# ifdef CONFIG_CYCLES_CLOCKSOURCE extern unsigned long long __bfin_cycles_off; extern unsigned int __bfin_cycles_mod; +# endif #endif #if defined(CONFIG_TICKSOURCE_CORETMR) diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c index 41a907596c70..cb7a01d4f009 100644 --- a/arch/blackfin/kernel/time-ts.c +++ b/arch/blackfin/kernel/time-ts.c @@ -51,7 +51,11 @@ static notrace cycle_t bfin_read_cycles(struct clocksource *cs) { +#ifdef CONFIG_CPU_FREQ return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod); +#else + return get_cycles(); +#endif } static struct clocksource bfin_cs_cycles = { diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c index 777582897253..5d7f8ab5509a 100644 --- a/arch/blackfin/mach-common/cpufreq.c +++ b/arch/blackfin/mach-common/cpufreq.c @@ -15,6 +15,8 @@ #include #include +#define CPUFREQ_CPU 0 + /* this is the table of CCLK frequencies, in Hz */ /* .index is the entry in the auxillary dpm_state_table[] */ static struct cpufreq_frequency_table bfin_freq_table[] = { @@ -41,64 +43,114 @@ static struct bfin_dpm_state { unsigned int tscale; /* change the divider on the core timer interrupt */ } dpm_state_table[3]; +#if defined(CONFIG_CYCLES_CLOCKSOURCE) /* - normalized to maximum frequncy offset for CYCLES, - used in time-ts cycles clock source, but could be used - somewhere also. + * normalized to maximum frequncy offset for CYCLES, + * used in time-ts cycles clock source, but could be used + * somewhere also. */ unsigned long long __bfin_cycles_off; unsigned int __bfin_cycles_mod; +#endif /**************************************************************************/ +static void __init bfin_init_tables(unsigned long cclk, unsigned long sclk) +{ -static unsigned int bfin_getfreq_khz(unsigned int cpu) + unsigned long csel, min_cclk; + int index; + + /* Anomaly 273 seems to still exist on non-BF54x w/dcache turned on */ +#if ANOMALY_05000273 || ANOMALY_05000274 || \ + (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_EXTMEM_DCACHEABLE)) + min_cclk = sclk * 2; +#else + min_cclk = sclk; +#endif + csel = ((bfin_read_PLL_DIV() & CSEL) >> 4); + + for (index = 0; (cclk >> index) >= min_cclk && csel <= 3; index++, csel++) { + bfin_freq_table[index].frequency = cclk >> index; + dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */ + dpm_state_table[index].tscale = (TIME_SCALE / (1 << csel)) - 1; + + pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n", + bfin_freq_table[index].frequency, + dpm_state_table[index].csel, + dpm_state_table[index].tscale); + } + return; +} + +static void bfin_adjust_core_timer(void *info) { - /* The driver only support single cpu */ - if (cpu != 0) - return -1; + unsigned int tscale; + unsigned int index = *(unsigned int *)info; + + /* we have to adjust the core timer, because it is using cclk */ + tscale = dpm_state_table[index].tscale; + bfin_write_TSCALE(tscale); + return; +} +static unsigned int bfin_getfreq_khz(unsigned int cpu) +{ + /* Both CoreA/B have the same core clock */ return get_cclk() / 1000; } -static int bfin_target(struct cpufreq_policy *policy, +static int bfin_target(struct cpufreq_policy *poli, unsigned int target_freq, unsigned int relation) { - unsigned int index, plldiv, tscale; + unsigned int index, plldiv, cpu; unsigned long flags, cclk_hz; struct cpufreq_freqs freqs; +#if defined(CONFIG_CYCLES_CLOCKSOURCE) cycles_t cycles; +#endif - if (cpufreq_frequency_table_target(policy, bfin_freq_table, - target_freq, relation, &index)) - return -EINVAL; - - cclk_hz = bfin_freq_table[index].frequency; - - freqs.old = bfin_getfreq_khz(0); - freqs.new = cclk_hz; - freqs.cpu = 0; - - pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n", - cclk_hz, target_freq, freqs.old); - - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - local_irq_save_hw(flags); - plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel; - tscale = dpm_state_table[index].tscale; - bfin_write_PLL_DIV(plldiv); - /* we have to adjust the core timer, because it is using cclk */ - bfin_write_TSCALE(tscale); - cycles = get_cycles(); - SSYNC(); - cycles += 10; /* ~10 cycles we lose after get_cycles() */ - __bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index); - __bfin_cycles_mod = index; - local_irq_restore_hw(flags); - /* TODO: just test case for cycles clock source, remove later */ - pr_debug("cpufreq: done\n"); - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + for_each_online_cpu(cpu) { + struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); + + if (!policy) + continue; + + if (cpufreq_frequency_table_target(policy, bfin_freq_table, + target_freq, relation, &index)) + return -EINVAL; + + cclk_hz = bfin_freq_table[index].frequency; + + freqs.old = bfin_getfreq_khz(0); + freqs.new = cclk_hz; + freqs.cpu = cpu; + + pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n", + cclk_hz, target_freq, freqs.old); + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + if (cpu == CPUFREQ_CPU) { + local_irq_save_hw(flags); + plldiv = (bfin_read_PLL_DIV() & SSEL) | + dpm_state_table[index].csel; + bfin_write_PLL_DIV(plldiv); + on_each_cpu(bfin_adjust_core_timer, &index, 1); +#if defined(CONFIG_CYCLES_CLOCKSOURCE) + cycles = get_cycles(); + SSYNC(); + cycles += 10; /* ~10 cycles we lose after get_cycles() */ + __bfin_cycles_off += + (cycles << __bfin_cycles_mod) - (cycles << index); + __bfin_cycles_mod = index; +#endif + local_irq_restore_hw(flags); + } + /* TODO: just test case for cycles clock source, remove later */ + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + pr_debug("cpufreq: done\n"); return 0; } @@ -110,37 +162,16 @@ static int bfin_verify_speed(struct cpufreq_policy *policy) static int __init __bfin_cpu_init(struct cpufreq_policy *policy) { - unsigned long cclk, sclk, csel, min_cclk; - int index; - - if (policy->cpu != 0) - return -EINVAL; + unsigned long cclk, sclk; cclk = get_cclk() / 1000; sclk = get_sclk() / 1000; -#if ANOMALY_05000273 || ANOMALY_05000274 || \ - (!defined(CONFIG_BF54x) && defined(CONFIG_BFIN_EXTMEM_DCACHEABLE)) - min_cclk = sclk * 2; -#else - min_cclk = sclk; -#endif - csel = ((bfin_read_PLL_DIV() & CSEL) >> 4); - - for (index = 0; (cclk >> index) >= min_cclk && csel <= 3; index++, csel++) { - bfin_freq_table[index].frequency = cclk >> index; - dpm_state_table[index].csel = csel << 4; /* Shift now into PLL_DIV bitpos */ - dpm_state_table[index].tscale = (TIME_SCALE / (1 << csel)) - 1; - - pr_debug("cpufreq: freq:%d csel:0x%x tscale:%d\n", - bfin_freq_table[index].frequency, - dpm_state_table[index].csel, - dpm_state_table[index].tscale); - } + if (policy->cpu == CPUFREQ_CPU) + bfin_init_tables(cclk, sclk); policy->cpuinfo.transition_latency = 50000; /* 50us assumed */ - /*Now ,only support one cpu */ policy->cur = cclk; cpufreq_frequency_table_get_attr(bfin_freq_table, policy->cpu); return cpufreq_frequency_table_cpuinfo(policy, bfin_freq_table); -- cgit v1.2.3 From 718340f62900ed44046d2b0f74d0dec7cf844194 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Mon, 1 Feb 2010 06:07:50 +0000 Subject: Blackfin: rewrite resync_core_{i,d}cache() SMP logic to avoid per_cpu data This functions are implicitly called by core functions like cpu_relax(), and since those functions may be called early on before common code has initialized the per-cpu data area, we need to tweak the stats gathering. Now the statistics are maintained in common bss which makes these funcs safe to use as soon as the C runtime env is setup. Signed-off-by: Graf Yang Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/cpu.h | 2 -- arch/blackfin/include/asm/smp.h | 7 +++++++ arch/blackfin/kernel/setup.c | 4 ++-- arch/blackfin/mach-common/smp.c | 6 ++++-- 4 files changed, 13 insertions(+), 6 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/cpu.h b/arch/blackfin/include/asm/cpu.h index b191dc662bd8..16883e582e3c 100644 --- a/arch/blackfin/include/asm/cpu.h +++ b/arch/blackfin/include/asm/cpu.h @@ -17,8 +17,6 @@ struct blackfin_cpudata { struct task_struct *idle; unsigned int imemctl; unsigned int dmemctl; - unsigned long dcache_invld_count; - unsigned long icache_invld_count; }; DECLARE_PER_CPU(struct blackfin_cpudata, cpu_data); diff --git a/arch/blackfin/include/asm/smp.h b/arch/blackfin/include/asm/smp.h index 7f26de09ca9c..f5b537967116 100644 --- a/arch/blackfin/include/asm/smp.h +++ b/arch/blackfin/include/asm/smp.h @@ -24,6 +24,13 @@ struct corelock_slot { }; extern struct corelock_slot corelock; +#ifdef __ARCH_SYNC_CORE_ICACHE +extern unsigned long icache_invld_count[NR_CPUS]; +#endif +#ifdef __ARCH_SYNC_CORE_DCACHE +extern unsigned long dcache_invld_count[NR_CPUS]; +#endif + void smp_icache_flush_range_others(unsigned long start, unsigned long end); #ifdef CONFIG_HOTPLUG_CPU diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c index b54ba45db5f1..8e2efceb364b 100644 --- a/arch/blackfin/kernel/setup.c +++ b/arch/blackfin/kernel/setup.c @@ -1239,10 +1239,10 @@ static int show_cpuinfo(struct seq_file *m, void *v) dsup_banks, BFIN_DSUBBANKS, BFIN_DWAYS, BFIN_DLINES); #ifdef __ARCH_SYNC_CORE_DCACHE - seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", cpudata->dcache_invld_count); + seq_printf(m, "SMP Dcache Flushes\t: %lu\n\n", dcache_invld_count[cpu_num]); #endif #ifdef __ARCH_SYNC_CORE_ICACHE - seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", cpudata->icache_invld_count); + seq_printf(m, "SMP Icache Flushes\t: %lu\n\n", icache_invld_count[cpu_num]); #endif if (cpu_num != num_possible_cpus() - 1) diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index efc47ffd066d..7803f22d2ca7 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -474,24 +474,26 @@ void smp_icache_flush_range_others(unsigned long start, unsigned long end) EXPORT_SYMBOL_GPL(smp_icache_flush_range_others); #ifdef __ARCH_SYNC_CORE_ICACHE +unsigned long icache_invld_count[NR_CPUS]; void resync_core_icache(void) { unsigned int cpu = get_cpu(); blackfin_invalidate_entire_icache(); - ++per_cpu(cpu_data, cpu).icache_invld_count; + icache_invld_count[cpu]++; put_cpu(); } EXPORT_SYMBOL(resync_core_icache); #endif #ifdef __ARCH_SYNC_CORE_DCACHE +unsigned long dcache_invld_count[NR_CPUS]; unsigned long barrier_mask __attribute__ ((__section__(".l2.bss"))); void resync_core_dcache(void) { unsigned int cpu = get_cpu(); blackfin_invalidate_entire_dcache(); - ++per_cpu(cpu_data, cpu).dcache_invld_count; + dcache_invld_count[cpu]++; put_cpu(); } EXPORT_SYMBOL(resync_core_dcache); -- cgit v1.2.3 From f5b99627a3065858ad5c678703ed7af5363dca39 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 3 Feb 2010 09:15:57 +0000 Subject: Blackfin: use generic ptrace_resume code Use the generic ptrace_resume code for PTRACE_SYSCALL, PTRACE_CONT, PTRACE_KILL and PTRACE_SINGLESTEP. This implies defining arch_has_single_step in and implementing the user_enable_single_step and user_disable_single_step functions, which also causes the breakpoint information to be cleared on fork, which could be considered a bug fix. Also the TIF_SYSCALL_TRACE thread flag is now cleared on PTRACE_KILL which it previously wasn't which is consistent with all architectures using the modern ptrace code. Signed-off-by: Christoph Hellwig Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/ptrace.c | 44 ------------------------------------------- 1 file changed, 44 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 65567dc4b9f5..895302df21c1 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -354,50 +354,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = put_reg(child, addr, data); break; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: /* restart after signal. */ - pr_debug("ptrace: syscall/cont\n"); - - ret = -EIO; - if (!valid_signal(data)) - break; - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - child->exit_code = data; - ptrace_disable(child); - pr_debug("ptrace: before wake_up_process\n"); - wake_up_process(child); - ret = 0; - break; - - /* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to - * exit. - */ - case PTRACE_KILL: - ret = 0; - if (child->exit_state == EXIT_ZOMBIE) /* already dead */ - break; - child->exit_code = SIGKILL; - ptrace_disable(child); - wake_up_process(child); - break; - - case PTRACE_SINGLESTEP: /* set the trap flag. */ - pr_debug("ptrace: single step\n"); - ret = -EIO; - if (!valid_signal(data)) - break; - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - ptrace_enable(child); - child->exit_code = data; - wake_up_process(child); - ret = 0; - break; - case PTRACE_GETREGS: /* Get all gp regs from the child. */ ret = ptrace_getregs(child, datap); -- cgit v1.2.3 From 5f09c77d2ad69397498b6555f0d3cd697304253c Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 14 Feb 2010 22:49:59 +0000 Subject: Blackfin: simplify SYSCFG code a bit and ignore attempts to change it We don't want to let user space modify the SYSCFG register arbitrarily as the settings are system wide (SNEN/CNEN) and can cause misbehavior. The only other bit here (SSSTEP) has proper controls via PTRACE_SINGLESTEP. Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/ptrace.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 895302df21c1..14118e40f18f 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -31,12 +31,6 @@ * in exit.c or in signal.c. */ -/* determines which bits in the SYSCFG reg the user has access to. */ -/* 1 = access 0 = no access */ -#define SYSCFG_MASK 0x0007 /* SYSCFG reg */ -/* sets the trace bits. */ -#define TRACE_BITS 0x0001 - /* Find the stack offset for a register, relative to thread.esp0. */ #define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) @@ -162,9 +156,8 @@ static inline int is_user_addr_valid(struct task_struct *child, void ptrace_enable(struct task_struct *child) { - unsigned long tmp; - tmp = get_reg(child, PT_SYSCFG) | (TRACE_BITS); - put_reg(child, PT_SYSCFG, tmp); + struct pt_regs *regs = task_pt_regs(child); + regs->syscfg |= SYSCFG_SSSTEP; } /* @@ -174,10 +167,8 @@ void ptrace_enable(struct task_struct *child) */ void ptrace_disable(struct task_struct *child) { - unsigned long tmp; - /* make sure the single step bit is not set. */ - tmp = get_reg(child, PT_SYSCFG) & ~TRACE_BITS; - put_reg(child, PT_SYSCFG, tmp); + struct pt_regs *regs = task_pt_regs(child); + regs->syscfg &= ~SYSCFG_SSSTEP; } long arch_ptrace(struct task_struct *child, long request, long addr, long data) @@ -343,14 +334,11 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - if (addr >= (sizeof(struct pt_regs))) { + /* Ignore writes to SYSCFG and other pseudo regs */ + if (addr >= PT_SYSCFG) { ret = 0; break; } - if (addr == PT_SYSCFG) { - data &= SYSCFG_MASK; - data |= get_reg(child, PT_SYSCFG); - } ret = put_reg(child, addr, data); break; -- cgit v1.2.3 From f2ce48024a9a6d3e92a023ded0f7b1e99da1cd16 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 14 Feb 2010 22:56:24 +0000 Subject: Blackfin: simplify PTRACE_{PEEK,POKE}USR in preperation for regset support Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/ptrace.h | 2 + arch/blackfin/kernel/ptrace.c | 118 ++++++++++++++++--------------------- 2 files changed, 53 insertions(+), 67 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/ptrace.h b/arch/blackfin/include/asm/ptrace.h index b33a4488f498..c1aebdb981c7 100644 --- a/arch/blackfin/include/asm/ptrace.h +++ b/arch/blackfin/include/asm/ptrace.h @@ -173,4 +173,6 @@ extern void show_regs(struct pt_regs *); #define PT_FDPIC_EXEC 232 #define PT_FDPIC_INTERP 236 +#define PT_LAST_PSEUDO PT_FDPIC_INTERP + #endif /* _BFIN_PTRACE_H */ diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 14118e40f18f..9536c1e2d1c7 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -25,7 +25,6 @@ #include #include -#define TEXT_OFFSET 0 /* * does not yet catch signals sent when the child dies. * in exit.c or in signal.c. @@ -43,7 +42,7 @@ * kernel stack will not be empty on entry to the kernel, so * ptracing these tasks will fail. */ -static inline struct pt_regs *get_user_regs(struct task_struct *task) +static inline struct pt_regs *task_pt_regs(struct task_struct *task) { return (struct pt_regs *) ((unsigned long)task_stack_page(task) + @@ -56,7 +55,7 @@ static inline struct pt_regs *get_user_regs(struct task_struct *task) static inline int ptrace_getregs(struct task_struct *tsk, void __user *uregs) { struct pt_regs regs; - memcpy(®s, get_user_regs(tsk), sizeof(regs)); + memcpy(®s, task_pt_regs(tsk), sizeof(regs)); regs.usp = tsk->thread.usp; return copy_to_user(uregs, ®s, sizeof(struct pt_regs)) ? -EFAULT : 0; } @@ -69,40 +68,49 @@ static inline int ptrace_getregs(struct task_struct *tsk, void __user *uregs) /* * Get contents of register REGNO in task TASK. */ -static inline long get_reg(struct task_struct *task, int regno) +static inline long +get_reg(struct task_struct *task, long regno, unsigned long __user *datap) { - unsigned char *reg_ptr; + long tmp; + struct pt_regs *regs = task_pt_regs(task); - struct pt_regs *regs = - (struct pt_regs *)((unsigned long)task_stack_page(task) + - (THREAD_SIZE - sizeof(struct pt_regs))); - reg_ptr = (char *)regs; + if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0) + return -EIO; switch (regno) { + case PT_TEXT_ADDR: + tmp = task->mm->start_code; + break; + case PT_TEXT_END_ADDR: + tmp = task->mm->end_code; + break; + case PT_DATA_ADDR: + tmp = task->mm->start_data; + break; case PT_USP: - return task->thread.usp; + tmp = task->thread.usp; + break; default: - if (regno <= 216) - return *(long *)(reg_ptr + regno); + if (regno < sizeof(*regs)) { + void *reg_ptr = regs; + tmp = *(long *)(reg_ptr + regno); + } else + return -EIO; } - /* slight mystery ... never seems to come here but kernel misbehaves without this code! */ - printk(KERN_WARNING "Request to get for unknown register %d\n", regno); - return 0; + return put_user(tmp, datap); } /* * Write contents of register REGNO in task TASK. */ static inline int -put_reg(struct task_struct *task, int regno, unsigned long data) +put_reg(struct task_struct *task, long regno, unsigned long data) { - char *reg_ptr; + struct pt_regs *regs = task_pt_regs(task); - struct pt_regs *regs = - (struct pt_regs *)((unsigned long)task_stack_page(task) + - (THREAD_SIZE - sizeof(struct pt_regs))); - reg_ptr = (char *)regs; + if (regno & 3 || regno > PT_LAST_PSEUDO || regno < 0) + return -EIO; switch (regno) { case PT_PC: @@ -119,10 +127,18 @@ put_reg(struct task_struct *task, int regno, unsigned long data) regs->usp = data; task->thread.usp = data; break; + case PT_SYSCFG: /* don't let userspace screw with this */ + if ((data & ~1) != 0x6) + pr_warning("ptrace: ignore syscfg write of %#lx\n", data); + break; /* regs->syscfg = data; break; */ default: - if (regno <= 216) - *(long *)(reg_ptr + regno) = data; + if (regno < sizeof(*regs)) { + void *reg_offset = regs; + *(long *)(reg_offset + regno) = data; + } + /* Ignore writes to pseudo registers */ } + return 0; } @@ -231,40 +247,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: - { - unsigned long tmp; - ret = -EIO; - tmp = 0; - if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) { - printk(KERN_WARNING "ptrace error : PEEKUSR : temporarily returning " - "0 - %x sizeof(pt_regs) is %lx\n", - (int)addr, sizeof(struct pt_regs)); - break; - } - if (addr == sizeof(struct pt_regs)) { - /* PT_TEXT_ADDR */ - tmp = child->mm->start_code + TEXT_OFFSET; - } else if (addr == (sizeof(struct pt_regs) + 4)) { - /* PT_TEXT_END_ADDR */ - tmp = child->mm->end_code; - } else if (addr == (sizeof(struct pt_regs) + 8)) { - /* PT_DATA_ADDR */ - tmp = child->mm->start_data; -#ifdef CONFIG_BINFMT_ELF_FDPIC - } else if (addr == (sizeof(struct pt_regs) + 12)) { - goto case_PTRACE_GETFDPIC_EXEC; - } else if (addr == (sizeof(struct pt_regs) + 16)) { - goto case_PTRACE_GETFDPIC_INTERP; -#endif - } else { - tmp = get_reg(child, addr); - } - ret = put_user(tmp, datap); - break; - } - #ifdef CONFIG_BINFMT_ELF_FDPIC case PTRACE_GETFDPIC: { unsigned long tmp = 0; @@ -327,19 +309,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; } - case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - ret = -EIO; - if ((addr & 3) || (addr > (sizeof(struct pt_regs) + 16))) { - printk(KERN_WARNING "ptrace error : POKEUSR: temporarily returning 0\n"); - break; + case PTRACE_PEEKUSR: + switch (addr) { +#ifdef CONFIG_BINFMT_ELF_FDPIC /* backwards compat */ + case PT_FDPIC_EXEC: goto case_PTRACE_GETFDPIC_EXEC; + case PT_FDPIC_INTERP: goto case_PTRACE_GETFDPIC_INTERP; +#endif + default: + ret = get_reg(child, addr, datap); } + pr_debug("ptrace: PEEKUSR reg %li with %#lx = %i\n", addr, data, ret); + break; - /* Ignore writes to SYSCFG and other pseudo regs */ - if (addr >= PT_SYSCFG) { - ret = 0; - break; - } + case PTRACE_POKEUSR: ret = put_reg(child, addr, data); + pr_debug("ptrace: POKEUSR reg %li with %li = %i\n", addr, data, ret); break; case PTRACE_GETREGS: -- cgit v1.2.3 From e50e2f25c5b90abd00a1e5871c45094cf5207afc Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 14 Feb 2010 22:58:02 +0000 Subject: Blackfin: initial regset support We don't support core dumps (yet?), but this should make things easier. Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/elf.h | 8 ++- arch/blackfin/kernel/process.c | 7 --- arch/blackfin/kernel/ptrace.c | 113 ++++++++++++++++++++++++++++++++-------- 3 files changed, 97 insertions(+), 31 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/elf.h b/arch/blackfin/include/asm/elf.h index 5b50f0ecacf8..117713adea7f 100644 --- a/arch/blackfin/include/asm/elf.h +++ b/arch/blackfin/include/asm/elf.h @@ -22,12 +22,15 @@ #define EF_BFIN_CODE_IN_L2 0x00000040 /* --code-in-l2 */ #define EF_BFIN_DATA_IN_L2 0x00000080 /* --data-in-l2 */ +#if 1 /* core dumps not supported, but linux/elfcore.h needs these */ typedef unsigned long elf_greg_t; -#define ELF_NGREG 40 /* (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) */ +#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t)) typedef elf_greg_t elf_gregset_t[ELF_NGREG]; typedef struct { } elf_fpregset_t; +#endif + /* * This is used to ensure we don't load something for the wrong architecture. */ @@ -55,6 +58,9 @@ do { \ _regs->p2 = _dynamic_addr; \ } while(0) +#if 0 +#define CORE_DUMP_USE_REGSET +#endif #define ELF_FDPIC_CORE_EFLAGS EF_BFIN_FDPIC #define ELF_EXEC_PAGESIZE 4096 diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index b56b0e485e0b..29705cec91de 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -98,13 +98,6 @@ void cpu_idle(void) } } -/* Fill in the fpu structure for a core dump. */ - -int dump_fpu(struct pt_regs *regs, elf_fpregset_t * fpregs) -{ - return 1; -} - /* * This gets run with P1 containing the * function to call, and R1 containing diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 9536c1e2d1c7..92b4ca0b5af6 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -9,9 +9,11 @@ #include #include #include +#include #include #include #include +#include #include #include @@ -49,22 +51,6 @@ static inline struct pt_regs *task_pt_regs(struct task_struct *task) (THREAD_SIZE - sizeof(struct pt_regs))); } -/* - * Get all user integer registers. - */ -static inline int ptrace_getregs(struct task_struct *tsk, void __user *uregs) -{ - struct pt_regs regs; - memcpy(®s, task_pt_regs(tsk), sizeof(regs)); - regs.usp = tsk->thread.usp; - return copy_to_user(uregs, ®s, sizeof(struct pt_regs)) ? -EFAULT : 0; -} - -/* Mapping from PT_xxx to the stack offset at which the register is - * saved. Notice that usp has no stack-slot and needs to be treated - * specially (see get_reg/put_reg below). - */ - /* * Get contents of register REGNO in task TASK. */ @@ -170,6 +156,84 @@ static inline int is_user_addr_valid(struct task_struct *child, return -EIO; } +/* + * retrieve the contents of Blackfin userspace general registers + */ +static int genregs_get(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + int ret; + + /* This sucks ... */ + regs->usp = target->thread.usp; + + ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, + regs, 0, sizeof(*regs)); + if (ret < 0) + return ret; + + return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, + sizeof(*regs), -1); +} + +/* + * update the contents of the Blackfin userspace general registers + */ +static int genregs_set(struct task_struct *target, + const struct user_regset *regset, + unsigned int pos, unsigned int count, + const void *kbuf, const void __user *ubuf) +{ + struct pt_regs *regs = task_pt_regs(target); + int ret; + + /* Don't let people set SYSCFG (it's at the end of pt_regs) */ + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, + regs, 0, PT_SYSCFG); + if (ret < 0) + return ret; + + /* This sucks ... */ + target->thread.usp = regs->usp; + /* regs->retx = regs->pc; */ + + return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, + PT_SYSCFG, -1); +} + +/* + * Define the register sets available on the Blackfin under Linux + */ +enum bfin_regset { + REGSET_GENERAL, +}; + +static const struct user_regset bfin_regsets[] = { + [REGSET_GENERAL] = { + .core_note_type = NT_PRSTATUS, + .n = sizeof(struct pt_regs) / sizeof(long), + .size = sizeof(long), + .align = sizeof(long), + .get = genregs_get, + .set = genregs_set, + }, +}; + +static const struct user_regset_view user_bfin_native_view = { + .name = "Blackfin", + .e_machine = EM_BLACKFIN, + .regsets = bfin_regsets, + .n = ARRAY_SIZE(bfin_regsets), +}; + +const struct user_regset_view *task_user_regset_view(struct task_struct *task) +{ + return &user_bfin_native_view; +} + void ptrace_enable(struct task_struct *child) { struct pt_regs *regs = task_pt_regs(child); @@ -327,15 +391,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) break; case PTRACE_GETREGS: - /* Get all gp regs from the child. */ - ret = ptrace_getregs(child, datap); - break; + pr_debug("ptrace: PTRACE_GETREGS\n"); + return copy_regset_to_user(child, &user_bfin_native_view, + REGSET_GENERAL, + 0, sizeof(struct pt_regs), + (void __user *)data); case PTRACE_SETREGS: - printk(KERN_WARNING "ptrace: SETREGS: **** NOT IMPLEMENTED ***\n"); - /* Set all gp regs in the child. */ - ret = 0; - break; + pr_debug("ptrace: PTRACE_SETREGS\n"); + return copy_regset_from_user(child, &user_bfin_native_view, + REGSET_GENERAL, + 0, sizeof(struct pt_regs), + (const void __user *)data); default: ret = ptrace_request(child, request, addr, data); -- cgit v1.2.3 From e8f263dfd32a784a816fe68956e564f8ede4a9fc Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 26 Jan 2010 07:33:53 +0000 Subject: Blackfin: initial tracehook support Signed-off-by: Mike Frysinger --- arch/blackfin/Kconfig | 1 + arch/blackfin/include/asm/ptrace.h | 23 +++++++++ arch/blackfin/include/asm/syscall.h | 96 +++++++++++++++++++++++++++++++++++++ arch/blackfin/kernel/ptrace.c | 66 +++++++------------------ arch/blackfin/kernel/signal.c | 14 ++---- arch/blackfin/mach-common/entry.S | 6 ++- 6 files changed, 144 insertions(+), 62 deletions(-) create mode 100644 arch/blackfin/include/asm/syscall.h (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index 970df5b5c525..c078849df7f9 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig @@ -24,6 +24,7 @@ config RWSEM_XCHGADD_ALGORITHM config BLACKFIN def_bool y select HAVE_ARCH_KGDB + select HAVE_ARCH_TRACEHOOK select HAVE_FUNCTION_GRAPH_TRACER select HAVE_FUNCTION_TRACER select HAVE_FUNCTION_TRACE_MCOUNT_TEST diff --git a/arch/blackfin/include/asm/ptrace.h b/arch/blackfin/include/asm/ptrace.h index c1aebdb981c7..aaa1c6c2bc19 100644 --- a/arch/blackfin/include/asm/ptrace.h +++ b/arch/blackfin/include/asm/ptrace.h @@ -24,6 +24,8 @@ #ifndef __ASSEMBLY__ +struct task_struct; + /* this struct defines the way the registers are stored on the stack during a system call. */ @@ -101,9 +103,30 @@ struct pt_regs { master interrupt enable. */ #define user_mode(regs) (!(((regs)->ipend & ~0x10) & (((regs)->ipend & ~0x10) - 1))) #define instruction_pointer(regs) ((regs)->pc) +#define user_stack_pointer(regs) ((regs)->usp) #define profile_pc(regs) instruction_pointer(regs) extern void show_regs(struct pt_regs *); +#define arch_has_single_step() (1) +extern void user_enable_single_step(struct task_struct *child); +extern void user_disable_single_step(struct task_struct *child); +/* common code demands this function */ +#define ptrace_disable(child) user_disable_single_step(child) + +/* + * Get the address of the live pt_regs for the specified task. + * These are saved onto the top kernel stack when the process + * is not running. + * + * Note: if a user thread is execve'd from kernel space, the + * kernel stack will not be empty on entry to the kernel, so + * ptracing these tasks will fail. + */ +#define task_pt_regs(task) \ + (struct pt_regs *) \ + ((unsigned long)task_stack_page(task) + \ + (THREAD_SIZE - sizeof(struct pt_regs))) + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ diff --git a/arch/blackfin/include/asm/syscall.h b/arch/blackfin/include/asm/syscall.h new file mode 100644 index 000000000000..4921a4815cce --- /dev/null +++ b/arch/blackfin/include/asm/syscall.h @@ -0,0 +1,96 @@ +/* + * Magic syscall break down functions + * + * Copyright 2010 Analog Devices Inc. + * + * Licensed under the GPL-2 or later. + */ + +#ifndef __ASM_BLACKFIN_SYSCALL_H__ +#define __ASM_BLACKFIN_SYSCALL_H__ + +/* + * Blackfin syscalls are simple: + * enter: + * p0: syscall number + * r{0,1,2,3,4,5}: syscall args 0,1,2,3,4,5 + * exit: + * r0: return/error value + */ + +#include +#include +#include + +static inline long +syscall_get_nr(struct task_struct *task, struct pt_regs *regs) +{ + return regs->p0; +} + +static inline void +syscall_rollback(struct task_struct *task, struct pt_regs *regs) +{ + regs->p0 = regs->orig_p0; +} + +static inline long +syscall_get_error(struct task_struct *task, struct pt_regs *regs) +{ + return IS_ERR_VALUE(regs->r0) ? regs->r0 : 0; +} + +static inline long +syscall_get_return_value(struct task_struct *task, struct pt_regs *regs) +{ + return regs->r0; +} + +static inline void +syscall_set_return_value(struct task_struct *task, struct pt_regs *regs, + int error, long val) +{ + regs->r0 = error ? -error : val; +} + +/** + * syscall_get_arguments() + * @task: unused + * @regs: the register layout to extract syscall arguments from + * @i: first syscall argument to extract + * @n: number of syscall arguments to extract + * @args: array to return the syscall arguments in + * + * args[0] gets i'th argument, args[n - 1] gets the i+n-1'th argument + */ +static inline void +syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, + unsigned int i, unsigned int n, unsigned long *args) +{ + /* + * Assume the ptrace layout doesn't change -- r5 is first in memory, + * then r4, ..., then r0. So we simply reverse the ptrace register + * array in memory to store into the args array. + */ + long *aregs = ®s->r0 - i; + + BUG_ON(i > 5 || i + n > 6); + + while (n--) + *args++ = *aregs--; +} + +/* See syscall_get_arguments() comments */ +static inline void +syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, + unsigned int i, unsigned int n, const unsigned long *args) +{ + long *aregs = ®s->r0 - i; + + BUG_ON(i > 5 || i + n > 6); + + while (n--) + *aregs-- = *args++; +} + +#endif diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c index 92b4ca0b5af6..0618b8287e34 100644 --- a/arch/blackfin/kernel/ptrace.c +++ b/arch/blackfin/kernel/ptrace.c @@ -1,6 +1,6 @@ /* * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * these modifications are Copyright 2004-2009 Analog Devices Inc. + * these modifications are Copyright 2004-2010 Analog Devices Inc. * * Licensed under the GPL-2 */ @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -32,25 +33,6 @@ * in exit.c or in signal.c. */ -/* Find the stack offset for a register, relative to thread.esp0. */ -#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) - -/* - * Get the address of the live pt_regs for the specified task. - * These are saved onto the top kernel stack when the process - * is not running. - * - * Note: if a user thread is execve'd from kernel space, the - * kernel stack will not be empty on entry to the kernel, so - * ptracing these tasks will fail. - */ -static inline struct pt_regs *task_pt_regs(struct task_struct *task) -{ - return (struct pt_regs *) - ((unsigned long)task_stack_page(task) + - (THREAD_SIZE - sizeof(struct pt_regs))); -} - /* * Get contents of register REGNO in task TASK. */ @@ -234,18 +216,13 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) return &user_bfin_native_view; } -void ptrace_enable(struct task_struct *child) +void user_enable_single_step(struct task_struct *child) { struct pt_regs *regs = task_pt_regs(child); regs->syscfg |= SYSCFG_SSSTEP; } -/* - * Called by kernel/ptrace.c when detaching.. - * - * Make sure the single step bit is not set. - */ -void ptrace_disable(struct task_struct *child) +void user_disable_single_step(struct task_struct *child) { struct pt_regs *regs = task_pt_regs(child); regs->syscfg &= ~SYSCFG_SSSTEP; @@ -412,27 +389,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } -asmlinkage void syscall_trace(void) +asmlinkage int syscall_trace_enter(struct pt_regs *regs) { - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - return; - - if (!(current->ptrace & PT_PTRACED)) - return; - - /* the 0x80 provides a way for the tracing parent to distinguish - * between a syscall stop and SIGTRAP delivery - */ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } + int ret = 0; + + if (test_thread_flag(TIF_SYSCALL_TRACE)) + ret = tracehook_report_syscall_entry(regs); + + return ret; +} + +asmlinkage void syscall_trace_leave(struct pt_regs *regs) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, 0); } diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index e0fd63e9e38a..e60990c0a1f0 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c @@ -1,5 +1,5 @@ /* - * Copyright 2004-2009 Analog Devices Inc. + * Copyright 2004-2010 Analog Devices Inc. * * Licensed under the GPL-2 or later */ @@ -206,16 +206,6 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t * info, regs->r1 = (unsigned long)(&frame->info); regs->r2 = (unsigned long)(&frame->uc); - /* - * Clear the trace flag when entering the signal handler, but - * notify any tracer that was single-stepping it. The tracer - * may want to single-step inside the handler too. - */ - if (regs->syscfg & TRACE_BITS) { - regs->syscfg &= ~TRACE_BITS; - ptrace_notify(SIGTRAP); - } - return 0; give_sigsegv: @@ -315,6 +305,8 @@ asmlinkage void do_signal(struct pt_regs *regs) * clear the TIF_RESTORE_SIGMASK flag */ if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); + + tracehook_signal_handler(signr, &info, &ka, regs, 1); } return; diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 1fa414f7852f..0df5b834d34e 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -736,7 +736,8 @@ ENDPROC(_system_call) * this symbol need not be global anyways, so ... */ _sys_trace: - pseudo_long_call _syscall_trace, p5; + r0 = sp; + pseudo_long_call _syscall_trace_enter, p5; /* Execute the appropriate system call */ @@ -760,7 +761,8 @@ _sys_trace: SP += 24; [sp + PT_R0] = r0; - pseudo_long_call _syscall_trace, p5; + r0 = sp; + pseudo_long_call _syscall_trace_leave, p5; jump .Lresume_userspace; ENDPROC(_sys_trace) -- cgit v1.2.3 From 600482c13d3d3612d71f39d8aaec47f63aafa801 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 17 Feb 2010 10:44:22 +0000 Subject: Blackfin: fix single stepping over system calls On Blackfin systems, the hardware single step exception triggers before the system call exception, so we need to save this info to process it later on. Otherwise, single stepping in userspace misses a few insns right after the system call. This is based a bit on the SuperH code added in commit 4b505db9c4c72dbd. Reported-by: Roland McGrath Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/thread_info.h | 2 ++ arch/blackfin/kernel/ptrace.c | 11 +++++++++-- arch/blackfin/kernel/signal.c | 3 ++- arch/blackfin/mach-common/entry.S | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h index 0149c92ceeb0..e9a5614cdbb1 100644 --- a/arch/blackfin/include/asm/thread_info.h +++ b/arch/blackfin/include/asm/thread_info.h @@ -103,6 +103,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_FREEZE 6 /* is freezing for suspend */ #define TIF_IRQ_SYNC 7 /* sync pipeline stage */ #define TIF_NOTIFY_RESUME 8 /* callback before returning to user */ +#define TIF_SINGLESTEP 9 /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<syscfg |= SYSCFG_SSSTEP; + + set_tsk_thread_flag(child, TIF_SINGLESTEP); } void user_disable_single_step(struct task_struct *child) { struct pt_regs *regs = task_pt_regs(child); regs->syscfg &= ~SYSCFG_SSSTEP; + + clear_tsk_thread_flag(child, TIF_SINGLESTEP); } long arch_ptrace(struct task_struct *child, long request, long addr, long data) @@ -401,6 +405,9 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs) asmlinkage void syscall_trace_leave(struct pt_regs *regs) { - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(regs, 0); + int step; + + step = test_thread_flag(TIF_SINGLESTEP); + if (step || test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, step); } diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index e60990c0a1f0..28d6f28c058c 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c @@ -306,7 +306,8 @@ asmlinkage void do_signal(struct pt_regs *regs) if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); - tracehook_signal_handler(signr, &info, &ka, regs, 1); + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLESTEP)); } return; diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 0df5b834d34e..0a9e458d0f7e 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -642,6 +642,8 @@ ENTRY(_system_call) r7 = [p2+TI_FLAGS]; CC = BITTST(r7,TIF_SYSCALL_TRACE); if CC JUMP _sys_trace; + CC = BITTST(r7,TIF_SINGLESTEP); + if CC JUMP _sys_trace; /* Execute the appropriate system call */ -- cgit v1.2.3 From ddaebcabbc18811ac4ac6e84fb9c327e8393a1dc Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 29 Jan 2010 01:33:54 +0000 Subject: Blackfin: add support for restart_syscall() Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/signal.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c index 28d6f28c058c..d536f35d1f43 100644 --- a/arch/blackfin/kernel/signal.c +++ b/arch/blackfin/kernel/signal.c @@ -17,6 +17,7 @@ #include #include #include +#include #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) @@ -50,6 +51,9 @@ rt_restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *p unsigned long usp = 0; int err = 0; + /* Always make any pending restarted system calls return -EINTR */ + current_thread_info()->restart_block.fn = do_no_restart_syscall; + #define RESTORE(x) err |= __get_user(regs->x, &sc->sc_##x) /* restore passed registers */ @@ -237,6 +241,11 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) regs->r0 = regs->orig_r0; regs->pc -= 2; break; + + case -ERESTART_RESTARTBLOCK: + regs->p0 = __NR_restart_syscall; + regs->pc -= 2; + break; } } -- cgit v1.2.3 From 2bc4affe9c374983220c1a5d5566ce67c95384fc Mon Sep 17 00:00:00 2001 From: Frans Pop Date: Sat, 6 Feb 2010 18:47:18 +0100 Subject: Blackfin: remove trailing space in messages Signed-off-by: Frans Pop Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/bfin_dma_5xx.c | 10 +++++----- arch/blackfin/kernel/traps.c | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c index 924c00286bab..26403d1c9e65 100644 --- a/arch/blackfin/kernel/bfin_dma_5xx.c +++ b/arch/blackfin/kernel/bfin_dma_5xx.c @@ -91,7 +91,7 @@ late_initcall(proc_dma_init); */ int request_dma(unsigned int channel, const char *device_id) { - pr_debug("request_dma() : BEGIN \n"); + pr_debug("request_dma() : BEGIN\n"); if (device_id == NULL) printk(KERN_WARNING "request_dma(%u): no device_id given\n", channel); @@ -107,7 +107,7 @@ int request_dma(unsigned int channel, const char *device_id) #endif if (atomic_cmpxchg(&dma_ch[channel].chan_status, 0, 1)) { - pr_debug("DMA CHANNEL IN USE \n"); + pr_debug("DMA CHANNEL IN USE\n"); return -EBUSY; } @@ -131,7 +131,7 @@ int request_dma(unsigned int channel, const char *device_id) * you have to request DMA, before doing any operations on * descriptor/channel */ - pr_debug("request_dma() : END \n"); + pr_debug("request_dma() : END\n"); return 0; } EXPORT_SYMBOL(request_dma); @@ -171,7 +171,7 @@ static void clear_dma_buffer(unsigned int channel) void free_dma(unsigned int channel) { - pr_debug("freedma() : BEGIN \n"); + pr_debug("freedma() : BEGIN\n"); BUG_ON(channel >= MAX_DMA_CHANNELS || !atomic_read(&dma_ch[channel].chan_status)); @@ -185,7 +185,7 @@ void free_dma(unsigned int channel) /* Clear the DMA Variable in the Channel */ atomic_set(&dma_ch[channel].chan_status, 0); - pr_debug("freedma() : END \n"); + pr_debug("freedma() : END\n"); } EXPORT_SYMBOL(free_dma); diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 4eaca2d1deed..ba70c4bc2699 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -1116,7 +1116,7 @@ void dump_bfin_mem(struct pt_regs *fp) /* And the last RETI points to the current userspace context */ if ((fp + 1)->pc >= current->mm->start_code && (fp + 1)->pc <= current->mm->end_code) { - verbose_printk(KERN_NOTICE "It might be better to look around here : \n"); + verbose_printk(KERN_NOTICE "It might be better to look around here :\n"); verbose_printk(KERN_NOTICE "-------------------------------------------\n"); show_regs(fp + 1); verbose_printk(KERN_NOTICE "-------------------------------------------\n"); -- cgit v1.2.3 From 7f4f69f991146fa976cbc914a50285b2afc0ad93 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 10 Feb 2010 12:31:41 +0100 Subject: Blackfin: GPIO: implement to_irq handler This makes it possible to support IRQs coming from off-chip GPIO controllers. Signed-off-by: Joachim Eastwood Signed-off-by: Mike Frysinger --- arch/blackfin/include/asm/gpio.h | 17 +++++++++++++---- arch/blackfin/kernel/bfin_gpio.c | 6 ++++++ 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h index 539468a05057..91bd2d7b9d55 100644 --- a/arch/blackfin/include/asm/gpio.h +++ b/arch/blackfin/include/asm/gpio.h @@ -70,6 +70,8 @@ #ifndef __ASSEMBLY__ +#include + /*********************************************************** * * FUNCTIONS: Blackfin General Purpose Ports Access Functions @@ -223,6 +225,9 @@ int bfin_gpio_direction_output(unsigned gpio, int value); int bfin_gpio_get_value(unsigned gpio); void bfin_gpio_set_value(unsigned gpio, int value); +#include +#include + #ifdef CONFIG_GPIOLIB #include /* cansleep wrappers */ @@ -247,6 +252,11 @@ static inline int gpio_cansleep(unsigned int gpio) return __gpio_cansleep(gpio); } +static inline int gpio_to_irq(unsigned gpio) +{ + return __gpio_to_irq(gpio); +} + #else /* !CONFIG_GPIOLIB */ static inline int gpio_request(unsigned gpio, const char *label) @@ -279,10 +289,6 @@ static inline void gpio_set_value(unsigned gpio, int value) return bfin_gpio_set_value(gpio, value); } -#include /* cansleep wrappers */ -#endif /* !CONFIG_GPIOLIB */ -#include - static inline int gpio_to_irq(unsigned gpio) { if (likely(gpio < MAX_BLACKFIN_GPIOS)) @@ -291,6 +297,9 @@ static inline int gpio_to_irq(unsigned gpio) return -EINVAL; } +#include /* cansleep wrappers */ +#endif /* !CONFIG_GPIOLIB */ + static inline int irq_to_gpio(unsigned irq) { return (irq - GPIO_IRQ_BASE); diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 0dd9cf913503..6dcb344001f0 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -1319,6 +1319,11 @@ void bfin_gpiolib_gpio_free(struct gpio_chip *chip, unsigned gpio) return bfin_gpio_free(gpio); } +int bfin_gpiolib_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + return gpio + GPIO_IRQ_BASE; +} + static struct gpio_chip bfin_chip = { .label = "BFIN-GPIO", .direction_input = bfin_gpiolib_direction_input, @@ -1327,6 +1332,7 @@ static struct gpio_chip bfin_chip = { .set = bfin_gpiolib_set_value, .request = bfin_gpiolib_gpio_request, .free = bfin_gpiolib_gpio_free, + .to_irq = bfin_gpiolib_gpio_to_irq, .base = 0, .ngpio = MAX_BLACKFIN_GPIOS, }; -- cgit v1.2.3 From f9c29e872b1c468d09c04ed452dc58961914c9d7 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Thu, 11 Feb 2010 12:41:11 +0100 Subject: Blackfin: mark gpio lib functions static Signed-off-by: Joachim Eastwood Signed-off-by: Mike Frysinger --- arch/blackfin/kernel/bfin_gpio.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'arch/blackfin/kernel') diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 6dcb344001f0..e35e20f00d9b 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -1289,37 +1289,37 @@ __initcall(gpio_register_proc); #endif #ifdef CONFIG_GPIOLIB -int bfin_gpiolib_direction_input(struct gpio_chip *chip, unsigned gpio) +static int bfin_gpiolib_direction_input(struct gpio_chip *chip, unsigned gpio) { return bfin_gpio_direction_input(gpio); } -int bfin_gpiolib_direction_output(struct gpio_chip *chip, unsigned gpio, int level) +static int bfin_gpiolib_direction_output(struct gpio_chip *chip, unsigned gpio, int level) { return bfin_gpio_direction_output(gpio, level); } -int bfin_gpiolib_get_value(struct gpio_chip *chip, unsigned gpio) +static int bfin_gpiolib_get_value(struct gpio_chip *chip, unsigned gpio) { return bfin_gpio_get_value(gpio); } -void bfin_gpiolib_set_value(struct gpio_chip *chip, unsigned gpio, int value) +static void bfin_gpiolib_set_value(struct gpio_chip *chip, unsigned gpio, int value) { return bfin_gpio_set_value(gpio, value); } -int bfin_gpiolib_gpio_request(struct gpio_chip *chip, unsigned gpio) +static int bfin_gpiolib_gpio_request(struct gpio_chip *chip, unsigned gpio) { return bfin_gpio_request(gpio, chip->label); } -void bfin_gpiolib_gpio_free(struct gpio_chip *chip, unsigned gpio) +static void bfin_gpiolib_gpio_free(struct gpio_chip *chip, unsigned gpio) { return bfin_gpio_free(gpio); } -int bfin_gpiolib_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +static int bfin_gpiolib_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) { return gpio + GPIO_IRQ_BASE; } -- cgit v1.2.3