summary refs log tree commit diff
path: root/arch/blackfin/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel')
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c52
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c99
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbinit.c2
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbmgr.c13
-rw-r--r--arch/blackfin/kernel/cplb-nompu/cplbinit.c31
-rw-r--r--arch/blackfin/kernel/dma-mapping.c68
-rw-r--r--arch/blackfin/kernel/gptimers.c32
-rw-r--r--arch/blackfin/kernel/ipipe.c67
-rw-r--r--arch/blackfin/kernel/kgdb.c17
-rw-r--r--arch/blackfin/kernel/kgdb_test.c67
-rw-r--r--arch/blackfin/kernel/process.c95
-rw-r--r--arch/blackfin/kernel/ptrace.c13
-rw-r--r--arch/blackfin/kernel/setup.c46
-rw-r--r--arch/blackfin/kernel/signal.c18
-rw-r--r--arch/blackfin/kernel/time-ts.c47
-rw-r--r--arch/blackfin/kernel/time.c8
-rw-r--r--arch/blackfin/kernel/traps.c45
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S28
18 files changed, 474 insertions, 274 deletions
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index 3946aff4f414..924c00286bab 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -37,9 +37,8 @@ static int __init blackfin_dma_init(void)
 	printk(KERN_INFO "Blackfin DMA Controller\n");
 
 	for (i = 0; i < MAX_DMA_CHANNELS; i++) {
-		dma_ch[i].chan_status = DMA_CHANNEL_FREE;
+		atomic_set(&dma_ch[i].chan_status, 0);
 		dma_ch[i].regs = dma_io_base_addr[i];
-		mutex_init(&(dma_ch[i].dmalock));
 	}
 	/* Mark MEMDMA Channel 0 as requested since we're using it internally */
 	request_dma(CH_MEM_STREAM0_DEST, "Blackfin dma_memcpy");
@@ -60,7 +59,7 @@ static int proc_dma_show(struct seq_file *m, void *v)
 	int i;
 
 	for (i = 0; i < MAX_DMA_CHANNELS; ++i)
-		if (dma_ch[i].chan_status != DMA_CHANNEL_FREE)
+		if (dma_channel_active(i))
 			seq_printf(m, "%2d: %s\n", i, dma_ch[i].device_id);
 
 	return 0;
@@ -107,20 +106,11 @@ int request_dma(unsigned int channel, const char *device_id)
 	}
 #endif
 
-	mutex_lock(&(dma_ch[channel].dmalock));
-
-	if ((dma_ch[channel].chan_status == DMA_CHANNEL_REQUESTED)
-	    || (dma_ch[channel].chan_status == DMA_CHANNEL_ENABLED)) {
-		mutex_unlock(&(dma_ch[channel].dmalock));
+	if (atomic_cmpxchg(&dma_ch[channel].chan_status, 0, 1)) {
 		pr_debug("DMA CHANNEL IN USE  \n");
 		return -EBUSY;
-	} else {
-		dma_ch[channel].chan_status = DMA_CHANNEL_REQUESTED;
-		pr_debug("DMA CHANNEL IS ALLOCATED  \n");
 	}
 
-	mutex_unlock(&(dma_ch[channel].dmalock));
-
 #ifdef CONFIG_BF54x
 	if (channel >= CH_UART2_RX && channel <= CH_UART3_TX) {
 		unsigned int per_map;
@@ -148,21 +138,20 @@ EXPORT_SYMBOL(request_dma);
 
 int set_dma_callback(unsigned int channel, irq_handler_t callback, void *data)
 {
-	BUG_ON(channel >= MAX_DMA_CHANNELS ||
-			dma_ch[channel].chan_status == DMA_CHANNEL_FREE);
+	int ret;
+	unsigned int irq;
 
-	if (callback != NULL) {
-		int ret;
-		unsigned int irq = channel2irq(channel);
+	BUG_ON(channel >= MAX_DMA_CHANNELS || !callback ||
+			!atomic_read(&dma_ch[channel].chan_status));
 
-		ret = request_irq(irq, callback, IRQF_DISABLED,
-			dma_ch[channel].device_id, data);
-		if (ret)
-			return ret;
+	irq = channel2irq(channel);
+	ret = request_irq(irq, callback, 0, dma_ch[channel].device_id, data);
+	if (ret)
+		return ret;
+
+	dma_ch[channel].irq = irq;
+	dma_ch[channel].data = data;
 
-		dma_ch[channel].irq = irq;
-		dma_ch[channel].data = data;
-	}
 	return 0;
 }
 EXPORT_SYMBOL(set_dma_callback);
@@ -184,7 +173,7 @@ void free_dma(unsigned int channel)
 {
 	pr_debug("freedma() : BEGIN \n");
 	BUG_ON(channel >= MAX_DMA_CHANNELS ||
-			dma_ch[channel].chan_status == DMA_CHANNEL_FREE);
+			!atomic_read(&dma_ch[channel].chan_status));
 
 	/* Halt the DMA */
 	disable_dma(channel);
@@ -194,9 +183,7 @@ void free_dma(unsigned int channel)
 		free_irq(dma_ch[channel].irq, dma_ch[channel].data);
 
 	/* Clear the DMA Variable in the Channel */
-	mutex_lock(&(dma_ch[channel].dmalock));
-	dma_ch[channel].chan_status = DMA_CHANNEL_FREE;
-	mutex_unlock(&(dma_ch[channel].dmalock));
+	atomic_set(&dma_ch[channel].chan_status, 0);
 
 	pr_debug("freedma() : END \n");
 }
@@ -210,13 +197,14 @@ int blackfin_dma_suspend(void)
 {
 	int i;
 
-	for (i = 0; i < MAX_DMA_SUSPEND_CHANNELS; ++i) {
-		if (dma_ch[i].chan_status == DMA_CHANNEL_ENABLED) {
+	for (i = 0; i < MAX_DMA_CHANNELS; ++i) {
+		if (dma_ch[i].regs->cfg & DMAEN) {
 			printk(KERN_ERR "DMA Channel %d failed to suspend\n", i);
 			return -EBUSY;
 		}
 
-		dma_ch[i].saved_peripheral_map = dma_ch[i].regs->peripheral_map;
+		if (i < MAX_DMA_SUSPEND_CHANNELS)
+			dma_ch[i].saved_peripheral_map = dma_ch[i].regs->peripheral_map;
 	}
 
 	return 0;
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index 22705eeff34f..a174596cc009 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -100,6 +100,12 @@ u8 pmux_offset[][16] = {
 };
 # endif
 
+#elif defined(BF538_FAMILY)
+static unsigned short * const port_fer[] = {
+	(unsigned short *) PORTCIO_FER,
+	(unsigned short *) PORTDIO_FER,
+	(unsigned short *) PORTEIO_FER,
+};
 #endif
 
 static unsigned short reserved_gpio_map[GPIO_BANK_NUM];
@@ -163,6 +169,27 @@ static int cmp_label(unsigned short ident, const char *label)
 
 static void port_setup(unsigned gpio, unsigned short usage)
 {
+#if defined(BF538_FAMILY)
+	/*
+	 * BF538/9 Port C,D and E are special.
+	 * Inverted PORT_FER polarity on CDE and no PORF_FER on F
+	 * Regular PORT F GPIOs are handled here, CDE are exclusively
+	 * managed by GPIOLIB
+	 */
+
+	if (gpio < MAX_BLACKFIN_GPIOS || gpio >= MAX_RESOURCES)
+		return;
+
+	gpio -= MAX_BLACKFIN_GPIOS;
+
+	if (usage == GPIO_USAGE)
+		*port_fer[gpio_bank(gpio)] |= gpio_bit(gpio);
+	else
+		*port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+	SSYNC();
+	return;
+#endif
+
 	if (check_gpio(gpio))
 		return;
 
@@ -762,6 +789,8 @@ int peripheral_request(unsigned short per, const char *label)
 	if (!(per & P_DEFINED))
 		return -ENODEV;
 
+	BUG_ON(ident >= MAX_RESOURCES);
+
 	local_irq_save_hw(flags);
 
 	/* If a pin can be muxed as either GPIO or peripheral, make
@@ -979,6 +1008,76 @@ void bfin_gpio_free(unsigned gpio)
 }
 EXPORT_SYMBOL(bfin_gpio_free);
 
+#ifdef BFIN_SPECIAL_GPIO_BANKS
+static unsigned short reserved_special_gpio_map[gpio_bank(MAX_RESOURCES)];
+
+int bfin_special_gpio_request(unsigned gpio, const char *label)
+{
+	unsigned long flags;
+
+	local_irq_save_hw(flags);
+
+	/*
+	 * Allow that the identical GPIO can
+	 * be requested from the same driver twice
+	 * Do nothing and return -
+	 */
+
+	if (cmp_label(gpio, label) == 0) {
+		local_irq_restore_hw(flags);
+		return 0;
+	}
+
+	if (unlikely(reserved_special_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		local_irq_restore_hw(flags);
+		printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n",
+		       gpio, get_label(gpio));
+
+		return -EBUSY;
+	}
+	if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) {
+		local_irq_restore_hw(flags);
+		printk(KERN_ERR
+		       "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n",
+		       gpio, get_label(gpio));
+
+		return -EBUSY;
+	}
+
+	reserved_special_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+	reserved_peri_map[gpio_bank(gpio)] |= gpio_bit(gpio);
+
+	set_label(gpio, label);
+	local_irq_restore_hw(flags);
+	port_setup(gpio, GPIO_USAGE);
+
+	return 0;
+}
+EXPORT_SYMBOL(bfin_special_gpio_request);
+
+void bfin_special_gpio_free(unsigned gpio)
+{
+	unsigned long flags;
+
+	might_sleep();
+
+	local_irq_save_hw(flags);
+
+	if (unlikely(!(reserved_special_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) {
+		gpio_error(gpio);
+		local_irq_restore_hw(flags);
+		return;
+	}
+
+	reserved_special_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+	reserved_peri_map[gpio_bank(gpio)] &= ~gpio_bit(gpio);
+	set_label(gpio, "free");
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(bfin_special_gpio_free);
+#endif
+
+
 int bfin_gpio_irq_request(unsigned gpio, const char *label)
 {
 	unsigned long flags;
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
index b52c1f8c4bc0..8d42b9e50dfa 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
@@ -92,6 +92,6 @@ void __init generate_cplb_tables_cpu(unsigned int cpu)
 		icplb_tbl[cpu][i_i++].data = 0;
 }
 
-void generate_cplb_tables_all(void)
+void __init generate_cplb_tables_all(void)
 {
 }
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index 69e0e530d70f..930c01c06813 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -113,11 +113,11 @@ static noinline int dcplb_miss(unsigned int cpu)
 		addr = L2_START;
 		d_data = L2_DMEMORY;
 	} else if (addr >= physical_mem_end) {
-		if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE
-		    && (status & FAULT_USERSUPV)) {
-			addr &= ~0x3fffff;
+		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;
 		} 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);
@@ -203,7 +203,12 @@ static noinline int icplb_miss(unsigned int cpu)
 		addr = L2_START;
 		i_data = L2_IMEMORY;
 	} else if (addr >= physical_mem_end) {
-		if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
+		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;
+		} else if (addr >= BOOT_ROM_START && addr < BOOT_ROM_START + BOOT_ROM_LENGTH
 		    && (status & FAULT_USERSUPV)) {
 			addr &= ~(1 * 1024 * 1024 - 1);
 			i_data &= ~PAGE_SIZE_4KB;
diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
index fd9a2f31e686..282a7919821b 100644
--- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
@@ -89,15 +89,25 @@ void __init generate_cplb_tables_cpu(unsigned int cpu)
 
 void __init generate_cplb_tables_all(void)
 {
+	unsigned long uncached_end;
 	int i_d, i_i;
 
 	i_d = 0;
 	/* Normal RAM, including MTD FS.  */
 #ifdef CONFIG_MTD_UCLINUX
-	dcplb_bounds[i_d].eaddr = memory_mtd_start + mtd_size;
+	uncached_end = memory_mtd_start + mtd_size;
 #else
-	dcplb_bounds[i_d].eaddr = memory_end;
+	uncached_end = memory_end;
 #endif
+	/*
+	 * if DMA uncached is less than 1MB, mark the 1MB chunk as uncached
+	 * so that we don't have to use 4kB pages and cause CPLB thrashing
+	 */
+	if ((DMA_UNCACHED_REGION >= 1 * 1024 * 1024) || !DMA_UNCACHED_REGION ||
+	    ((_ramend - uncached_end) >= 1 * 1024 * 1024))
+		dcplb_bounds[i_d].eaddr = uncached_end;
+	else
+		dcplb_bounds[i_d].eaddr = uncached_end & ~(1 * 1024 * 1024);
 	dcplb_bounds[i_d++].data = SDRAM_DGENERIC;
 	/* DMA uncached region.  */
 	if (DMA_UNCACHED_REGION) {
@@ -135,18 +145,15 @@ void __init generate_cplb_tables_all(void)
 
 	i_i = 0;
 	/* Normal RAM, including MTD FS.  */
-#ifdef CONFIG_MTD_UCLINUX
-	icplb_bounds[i_i].eaddr = memory_mtd_start + mtd_size;
-#else
-	icplb_bounds[i_i].eaddr = memory_end;
-#endif
+	icplb_bounds[i_i].eaddr = uncached_end;
 	icplb_bounds[i_i++].data = SDRAM_IGENERIC;
-	/* DMA uncached region.  */
-	if (DMA_UNCACHED_REGION) {
-		icplb_bounds[i_i].eaddr = _ramend;
-		icplb_bounds[i_i++].data = 0;
-	}
 	if (_ramend != physical_mem_end) {
+		/* DMA uncached region.  */
+		if (DMA_UNCACHED_REGION) {
+			/* Normally this hole is caught by the async below.  */
+			icplb_bounds[i_i].eaddr = _ramend;
+			icplb_bounds[i_i++].data = 0;
+		}
 		/* Reserved memory.  */
 		icplb_bounds[i_i].eaddr = physical_mem_end;
 		icplb_bounds[i_i++].data = (reserved_mem_icache_on ?
diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c
index e74e74d7733f..e937f323d82c 100644
--- a/arch/blackfin/kernel/dma-mapping.c
+++ b/arch/blackfin/kernel/dma-mapping.c
@@ -7,30 +7,25 @@
  */
 
 #include <linux/types.h>
-#include <linux/mm.h>
+#include <linux/gfp.h>
 #include <linux/string.h>
-#include <linux/bootmem.h>
 #include <linux/spinlock.h>
-#include <linux/device.h>
 #include <linux/dma-mapping.h>
-#include <linux/io.h>
 #include <linux/scatterlist.h>
-#include <asm/cacheflush.h>
-#include <asm/bfin-global.h>
 
 static spinlock_t dma_page_lock;
-static unsigned int *dma_page;
+static unsigned long *dma_page;
 static unsigned int dma_pages;
 static unsigned long dma_base;
 static unsigned long dma_size;
 static unsigned int dma_initialized;
 
-void dma_alloc_init(unsigned long start, unsigned long end)
+static void dma_alloc_init(unsigned long start, unsigned long end)
 {
 	spin_lock_init(&dma_page_lock);
 	dma_initialized = 0;
 
-	dma_page = (unsigned int *)__get_free_page(GFP_KERNEL);
+	dma_page = (unsigned long *)__get_free_page(GFP_KERNEL);
 	memset(dma_page, 0, PAGE_SIZE);
 	dma_base = PAGE_ALIGN(start);
 	dma_size = PAGE_ALIGN(end) - PAGE_ALIGN(start);
@@ -58,10 +53,11 @@ static unsigned long __alloc_dma_pages(unsigned int pages)
 	spin_lock_irqsave(&dma_page_lock, flags);
 
 	for (i = 0; i < dma_pages;) {
-		if (dma_page[i++] == 0) {
+		if (test_bit(i++, dma_page) == 0) {
 			if (++count == pages) {
 				while (count--)
-					dma_page[--i] = 1;
+					__set_bit(--i, dma_page);
+
 				ret = dma_base + (i << PAGE_SHIFT);
 				break;
 			}
@@ -84,14 +80,14 @@ static void __free_dma_pages(unsigned long addr, unsigned int pages)
 	}
 
 	spin_lock_irqsave(&dma_page_lock, flags);
-	for (i = page; i < page + pages; i++) {
-		dma_page[i] = 0;
-	}
+	for (i = page; i < page + pages; i++)
+		__clear_bit(i, dma_page);
+
 	spin_unlock_irqrestore(&dma_page_lock, flags);
 }
 
 void *dma_alloc_coherent(struct device *dev, size_t size,
-			 dma_addr_t * dma_handle, gfp_t gfp)
+			 dma_addr_t *dma_handle, gfp_t gfp)
 {
 	void *ret;
 
@@ -115,21 +111,14 @@ dma_free_coherent(struct device *dev, size_t size, void *vaddr,
 EXPORT_SYMBOL(dma_free_coherent);
 
 /*
- * Dummy functions defined for some existing drivers
+ * Streaming DMA mappings
  */
-
-dma_addr_t
-dma_map_single(struct device *dev, void *ptr, size_t size,
-	       enum dma_data_direction direction)
+void __dma_sync(dma_addr_t addr, size_t size,
+		enum dma_data_direction dir)
 {
-	BUG_ON(direction == DMA_NONE);
-
-	invalidate_dcache_range((unsigned long)ptr,
-			(unsigned long)ptr + size);
-
-	return (dma_addr_t) ptr;
+	_dma_sync(addr, size, dir);
 }
-EXPORT_SYMBOL(dma_map_single);
+EXPORT_SYMBOL(__dma_sync);
 
 int
 dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
@@ -137,30 +126,23 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
 {
 	int i;
 
-	BUG_ON(direction == DMA_NONE);
-
 	for (i = 0; i < nents; i++, sg++) {
 		sg->dma_address = (dma_addr_t) sg_virt(sg);
-
-		invalidate_dcache_range(sg_dma_address(sg),
-					sg_dma_address(sg) +
-					sg_dma_len(sg));
+		__dma_sync(sg_dma_address(sg), sg_dma_len(sg), direction);
 	}
 
 	return nents;
 }
 EXPORT_SYMBOL(dma_map_sg);
 
-void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
-		enum dma_data_direction direction)
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+			    int nelems, enum dma_data_direction direction)
 {
-	BUG_ON(direction == DMA_NONE);
-}
-EXPORT_SYMBOL(dma_unmap_single);
+	int i;
 
-void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
-		int nhwentries, enum dma_data_direction direction)
-{
-	BUG_ON(direction == DMA_NONE);
+	for (i = 0; i < nelems; i++, sg++) {
+		sg->dma_address = (dma_addr_t) sg_virt(sg);
+		__dma_sync(sg_dma_address(sg), sg_dma_len(sg), direction);
+	}
 }
-EXPORT_SYMBOL(dma_unmap_sg);
+EXPORT_SYMBOL(dma_sync_sg_for_device);
diff --git a/arch/blackfin/kernel/gptimers.c b/arch/blackfin/kernel/gptimers.c
index 7281a91d26b5..cdbe075de1dc 100644
--- a/arch/blackfin/kernel/gptimers.c
+++ b/arch/blackfin/kernel/gptimers.c
@@ -137,7 +137,7 @@ static uint32_t const timil_mask[MAX_BLACKFIN_GPTIMERS] =
 #endif
 };
 
-void set_gptimer_pwidth(int timer_id, uint32_t value)
+void set_gptimer_pwidth(unsigned int timer_id, uint32_t value)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	timer_regs[timer_id]->width = value;
@@ -145,14 +145,14 @@ void set_gptimer_pwidth(int timer_id, uint32_t value)
 }
 EXPORT_SYMBOL(set_gptimer_pwidth);
 
-uint32_t get_gptimer_pwidth(int timer_id)
+uint32_t get_gptimer_pwidth(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	return timer_regs[timer_id]->width;
 }
 EXPORT_SYMBOL(get_gptimer_pwidth);
 
-void set_gptimer_period(int timer_id, uint32_t period)
+void set_gptimer_period(unsigned int timer_id, uint32_t period)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	timer_regs[timer_id]->period = period;
@@ -160,28 +160,28 @@ void set_gptimer_period(int timer_id, uint32_t period)
 }
 EXPORT_SYMBOL(set_gptimer_period);
 
-uint32_t get_gptimer_period(int timer_id)
+uint32_t get_gptimer_period(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	return timer_regs[timer_id]->period;
 }
 EXPORT_SYMBOL(get_gptimer_period);
 
-uint32_t get_gptimer_count(int timer_id)
+uint32_t get_gptimer_count(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	return timer_regs[timer_id]->counter;
 }
 EXPORT_SYMBOL(get_gptimer_count);
 
-uint32_t get_gptimer_status(int group)
+uint32_t get_gptimer_status(unsigned int group)
 {
 	tassert(group < BFIN_TIMER_NUM_GROUP);
 	return group_regs[group]->status;
 }
 EXPORT_SYMBOL(get_gptimer_status);
 
-void set_gptimer_status(int group, uint32_t value)
+void set_gptimer_status(unsigned int group, uint32_t value)
 {
 	tassert(group < BFIN_TIMER_NUM_GROUP);
 	group_regs[group]->status = value;
@@ -189,42 +189,42 @@ void set_gptimer_status(int group, uint32_t value)
 }
 EXPORT_SYMBOL(set_gptimer_status);
 
-int get_gptimer_intr(int timer_id)
+int get_gptimer_intr(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & timil_mask[timer_id]);
 }
 EXPORT_SYMBOL(get_gptimer_intr);
 
-void clear_gptimer_intr(int timer_id)
+void clear_gptimer_intr(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	group_regs[BFIN_TIMER_OCTET(timer_id)]->status = timil_mask[timer_id];
 }
 EXPORT_SYMBOL(clear_gptimer_intr);
 
-int get_gptimer_over(int timer_id)
+int get_gptimer_over(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & tovf_mask[timer_id]);
 }
 EXPORT_SYMBOL(get_gptimer_over);
 
-void clear_gptimer_over(int timer_id)
+void clear_gptimer_over(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	group_regs[BFIN_TIMER_OCTET(timer_id)]->status = tovf_mask[timer_id];
 }
 EXPORT_SYMBOL(clear_gptimer_over);
 
-int get_gptimer_run(int timer_id)
+int get_gptimer_run(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	return !!(group_regs[BFIN_TIMER_OCTET(timer_id)]->status & trun_mask[timer_id]);
 }
 EXPORT_SYMBOL(get_gptimer_run);
 
-void set_gptimer_config(int timer_id, uint16_t config)
+void set_gptimer_config(unsigned int timer_id, uint16_t config)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	timer_regs[timer_id]->config = config;
@@ -232,7 +232,7 @@ void set_gptimer_config(int timer_id, uint16_t config)
 }
 EXPORT_SYMBOL(set_gptimer_config);
 
-uint16_t get_gptimer_config(int timer_id)
+uint16_t get_gptimer_config(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	return timer_regs[timer_id]->config;
@@ -280,7 +280,7 @@ void disable_gptimers_sync(uint16_t mask)
 }
 EXPORT_SYMBOL(disable_gptimers_sync);
 
-void set_gptimer_pulse_hi(int timer_id)
+void set_gptimer_pulse_hi(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	timer_regs[timer_id]->config |= TIMER_PULSE_HI;
@@ -288,7 +288,7 @@ void set_gptimer_pulse_hi(int timer_id)
 }
 EXPORT_SYMBOL(set_gptimer_pulse_hi);
 
-void clear_gptimer_pulse_hi(int timer_id)
+void clear_gptimer_pulse_hi(unsigned int timer_id)
 {
 	tassert(timer_id < MAX_BLACKFIN_GPTIMERS);
 	timer_regs[timer_id]->config &= ~TIMER_PULSE_HI;
diff --git a/arch/blackfin/kernel/ipipe.c b/arch/blackfin/kernel/ipipe.c
index 5d7382396dc0..a77307a4473b 100644
--- a/arch/blackfin/kernel/ipipe.c
+++ b/arch/blackfin/kernel/ipipe.c
@@ -335,3 +335,70 @@ void __ipipe_enable_root_irqs_hw(void)
 	__clear_bit(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status));
 	bfin_sti(bfin_irq_flags);
 }
+
+/*
+ * We could use standard atomic bitops in the following root status
+ * manipulation routines, but let's prepare for SMP support in the
+ * same move, preventing CPU migration as required.
+ */
+void __ipipe_stall_root(void)
+{
+	unsigned long *p, flags;
+
+	local_irq_save_hw(flags);
+	p = &__ipipe_root_status;
+	__set_bit(IPIPE_STALL_FLAG, p);
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(__ipipe_stall_root);
+
+unsigned long __ipipe_test_and_stall_root(void)
+{
+	unsigned long *p, flags;
+	int x;
+
+	local_irq_save_hw(flags);
+	p = &__ipipe_root_status;
+	x = __test_and_set_bit(IPIPE_STALL_FLAG, p);
+	local_irq_restore_hw(flags);
+
+	return x;
+}
+EXPORT_SYMBOL(__ipipe_test_and_stall_root);
+
+unsigned long __ipipe_test_root(void)
+{
+	const unsigned long *p;
+	unsigned long flags;
+	int x;
+
+	local_irq_save_hw_smp(flags);
+	p = &__ipipe_root_status;
+	x = test_bit(IPIPE_STALL_FLAG, p);
+	local_irq_restore_hw_smp(flags);
+
+	return x;
+}
+EXPORT_SYMBOL(__ipipe_test_root);
+
+void __ipipe_lock_root(void)
+{
+	unsigned long *p, flags;
+
+	local_irq_save_hw(flags);
+	p = &__ipipe_root_status;
+	__set_bit(IPIPE_SYNCDEFER_FLAG, p);
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(__ipipe_lock_root);
+
+void __ipipe_unlock_root(void)
+{
+	unsigned long *p, flags;
+
+	local_irq_save_hw(flags);
+	p = &__ipipe_root_status;
+	__clear_bit(IPIPE_SYNCDEFER_FLAG, p);
+	local_irq_restore_hw(flags);
+}
+EXPORT_SYMBOL(__ipipe_unlock_root);
diff --git a/arch/blackfin/kernel/kgdb.c b/arch/blackfin/kernel/kgdb.c
index cce79d05b90b..f1036b6b9293 100644
--- a/arch/blackfin/kernel/kgdb.c
+++ b/arch/blackfin/kernel/kgdb.c
@@ -24,16 +24,6 @@
 #include <asm/blackfin.h>
 #include <asm/dma.h>
 
-/* Put the error code here just in case the user cares.  */
-int gdb_bfin_errcode;
-/* Likewise, the vector number here (since GDB only gets the signal
-   number through the usual means, and that's not very specific).  */
-int gdb_bfin_vector = -1;
-
-#if KGDB_MAX_NO_CPUS != 8
-#error change the definition of slavecpulocks
-#endif
-
 void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
 {
 	gdb_regs[BFIN_R0] = regs->r0;
@@ -369,13 +359,6 @@ void kgdb_roundup_cpu(int cpu, unsigned long flags)
 }
 #endif
 
-void kgdb_post_primary_code(struct pt_regs *regs, int eVector, int err_code)
-{
-	/* Master processor is completely in the debugger */
-	gdb_bfin_vector = eVector;
-	gdb_bfin_errcode = err_code;
-}
-
 int kgdb_arch_handle_exception(int vector, int signo,
 			       int err_code, char *remcom_in_buffer,
 			       char *remcom_out_buffer,
diff --git a/arch/blackfin/kernel/kgdb_test.c b/arch/blackfin/kernel/kgdb_test.c
index 59fc42dc5d6a..9a4b07594389 100644
--- a/arch/blackfin/kernel/kgdb_test.c
+++ b/arch/blackfin/kernel/kgdb_test.c
@@ -17,8 +17,9 @@
 
 #include <asm/blackfin.h>
 
+/* Symbols are here for kgdb test to poke directly */
 static char cmdline[256];
-static unsigned long len;
+static size_t len;
 
 #ifndef CONFIG_SMP
 static int num1 __attribute__((l1_data));
@@ -27,11 +28,10 @@ void kgdb_l1_test(void) __attribute__((l1_text));
 
 void kgdb_l1_test(void)
 {
-	printk(KERN_ALERT "L1(before change) : data variable addr = 0x%p, data value is %d\n", &num1, num1);
-	printk(KERN_ALERT "L1 : code function addr = 0x%p\n", kgdb_l1_test);
-	num1 = num1 + 10 ;
-	printk(KERN_ALERT "L1(after change) : data variable addr = 0x%p, data value is %d\n", &num1, num1);
-	return ;
+	pr_alert("L1(before change) : data variable addr = 0x%p, data value is %d\n", &num1, num1);
+	pr_alert("L1 : code function addr = 0x%p\n", kgdb_l1_test);
+	num1 = num1 + 10;
+	pr_alert("L1(after change) : data variable addr = 0x%p, data value is %d\n", &num1, num1);
 }
 #endif
 
@@ -42,11 +42,10 @@ void kgdb_l2_test(void) __attribute__((l2));
 
 void kgdb_l2_test(void)
 {
-	printk(KERN_ALERT "L2(before change) : data variable addr = 0x%p, data value is %d\n", &num2, num2);
-	printk(KERN_ALERT "L2 : code function addr = 0x%p\n", kgdb_l2_test);
-	num2 = num2 + 20 ;
-	printk(KERN_ALERT "L2(after change) : data variable addr = 0x%p, data value is %d\n", &num2, num2);
-	return ;
+	pr_alert("L2(before change) : data variable addr = 0x%p, data value is %d\n", &num2, num2);
+	pr_alert("L2 : code function addr = 0x%p\n", kgdb_l2_test);
+	num2 = num2 + 20;
+	pr_alert("L2(after change) : data variable addr = 0x%p, data value is %d\n", &num2, num2);
 }
 
 #endif
@@ -54,12 +53,14 @@ void kgdb_l2_test(void)
 
 int kgdb_test(char *name, int len, int count, int z)
 {
-	printk(KERN_ALERT "kgdb name(%d): %s, %d, %d\n", len, name, count, z);
+	pr_alert("kgdb name(%d): %s, %d, %d\n", len, name, count, z);
 	count = z;
 	return count;
 }
 
-static int test_proc_output(char *buf)
+static ssize_t
+kgdb_test_proc_read(struct file *file, char __user *buf,
+                    size_t count, loff_t *ppos)
 {
 	kgdb_test("hello world!", 12, 0x55, 0x10);
 #ifndef CONFIG_SMP
@@ -72,49 +73,31 @@ static int test_proc_output(char *buf)
 	return 0;
 }
 
-static int test_read_proc(char *page, char **start, off_t off,
-				 int count, int *eof, void *data)
+static ssize_t
+kgdb_test_proc_write(struct file *file, const char __user *buffer,
+                     size_t count, loff_t *pos)
 {
-	int len;
-
-	len = test_proc_output(page);
-	if (len <= off+count)
-		*eof = 1;
-	*start = page + off;
-	len -= off;
-	if (len > count)
-		len = count;
-	if (len < 0)
-		len = 0;
-	return len;
-}
-
-static int test_write_proc(struct file *file, const char *buffer,
-				 unsigned long count, void *data)
-{
-	if (count >= 256)
-		len = 255;
-	else
-		len = count;
-
+	len = min_t(size_t, 255, count);
 	memcpy(cmdline, buffer, count);
 	cmdline[len] = 0;
 
 	return len;
 }
 
+static const struct file_operations kgdb_test_proc_fops = {
+	.owner = THIS_MODULE,
+	.read  = kgdb_test_proc_read,
+	.write = kgdb_test_proc_write,
+};
+
 static int __init kgdbtest_init(void)
 {
 	struct proc_dir_entry *entry;
 
-	entry = create_proc_entry("kgdbtest", 0, NULL);
+	entry = proc_create("kgdbtest", 0, NULL, &kgdb_test_proc_fops);
 	if (entry == NULL)
 		return -ENOMEM;
 
-	entry->read_proc = test_read_proc;
-	entry->write_proc = test_write_proc;
-	entry->data = NULL;
-
 	return 0;
 }
 
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index 45876427eb2d..b56b0e485e0b 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -258,9 +258,12 @@ void finish_atomic_sections (struct pt_regs *regs)
 	int __user *up0 = (int __user *)regs->p0;
 
 	switch (regs->pc) {
+	default:
+		/* not in middle of an atomic step, so resume like normal */
+		return;
+
 	case ATOMIC_XCHG32 + 2:
 		put_user(regs->r1, up0);
-		regs->pc = ATOMIC_XCHG32 + 4;
 		break;
 
 	case ATOMIC_CAS32 + 2:
@@ -268,7 +271,6 @@ void finish_atomic_sections (struct pt_regs *regs)
 		if (regs->r0 == regs->r1)
 	case ATOMIC_CAS32 + 6:
 			put_user(regs->r2, up0);
-		regs->pc = ATOMIC_CAS32 + 8;
 		break;
 
 	case ATOMIC_ADD32 + 2:
@@ -276,7 +278,6 @@ void finish_atomic_sections (struct pt_regs *regs)
 		/* fall through */
 	case ATOMIC_ADD32 + 4:
 		put_user(regs->r0, up0);
-		regs->pc = ATOMIC_ADD32 + 6;
 		break;
 
 	case ATOMIC_SUB32 + 2:
@@ -284,7 +285,6 @@ void finish_atomic_sections (struct pt_regs *regs)
 		/* fall through */
 	case ATOMIC_SUB32 + 4:
 		put_user(regs->r0, up0);
-		regs->pc = ATOMIC_SUB32 + 6;
 		break;
 
 	case ATOMIC_IOR32 + 2:
@@ -292,7 +292,6 @@ void finish_atomic_sections (struct pt_regs *regs)
 		/* fall through */
 	case ATOMIC_IOR32 + 4:
 		put_user(regs->r0, up0);
-		regs->pc = ATOMIC_IOR32 + 6;
 		break;
 
 	case ATOMIC_AND32 + 2:
@@ -300,7 +299,6 @@ void finish_atomic_sections (struct pt_regs *regs)
 		/* fall through */
 	case ATOMIC_AND32 + 4:
 		put_user(regs->r0, up0);
-		regs->pc = ATOMIC_AND32 + 6;
 		break;
 
 	case ATOMIC_XOR32 + 2:
@@ -308,9 +306,15 @@ void finish_atomic_sections (struct pt_regs *regs)
 		/* fall through */
 	case ATOMIC_XOR32 + 4:
 		put_user(regs->r0, up0);
-		regs->pc = ATOMIC_XOR32 + 6;
 		break;
 	}
+
+	/*
+	 * We've finished the atomic section, and the only thing left for
+	 * userspace is to do a RTS, so we might as well handle that too
+	 * since we need to update the PC anyways.
+	 */
+	regs->pc = regs->rets;
 }
 
 static inline
@@ -332,12 +336,58 @@ int in_mem_const(unsigned long addr, unsigned long size,
 {
 	return in_mem_const_off(addr, size, 0, const_addr, const_size);
 }
-#define IN_ASYNC(bnum, bctlnum) \
+#define ASYNC_ENABLED(bnum, bctlnum) \
 ({ \
-	(bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? -EFAULT : \
-	bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? -EFAULT : \
-	BFIN_MEM_ACCESS_CORE; \
+	(bfin_read_EBIU_AMGCTL() & 0xe) < ((bnum + 1) << 1) ? 0 : \
+	bfin_read_EBIU_AMBCTL##bctlnum() & B##bnum##RDYEN ? 0 : \
+	1; \
 })
+/*
+ * We can't read EBIU banks that aren't enabled or we end up hanging
+ * on the access to the async space.  Make sure we validate accesses
+ * that cross async banks too.
+ *	0 - found, but unusable
+ *	1 - found & usable
+ *	2 - not found
+ */
+static
+int in_async(unsigned long addr, unsigned long size)
+{
+	if (addr >= ASYNC_BANK0_BASE && addr < ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE) {
+		if (!ASYNC_ENABLED(0, 0))
+			return 0;
+		if (addr + size <= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE)
+			return 1;
+		size -= ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE - addr;
+		addr = ASYNC_BANK0_BASE + ASYNC_BANK0_SIZE;
+	}
+	if (addr >= ASYNC_BANK1_BASE && addr < ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE) {
+		if (!ASYNC_ENABLED(1, 0))
+			return 0;
+		if (addr + size <= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE)
+			return 1;
+		size -= ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE - addr;
+		addr = ASYNC_BANK1_BASE + ASYNC_BANK1_SIZE;
+	}
+	if (addr >= ASYNC_BANK2_BASE && addr < ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE) {
+		if (!ASYNC_ENABLED(2, 1))
+			return 0;
+		if (addr + size <= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE)
+			return 1;
+		size -= ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE - addr;
+		addr = ASYNC_BANK2_BASE + ASYNC_BANK2_SIZE;
+	}
+	if (addr >= ASYNC_BANK3_BASE && addr < ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE) {
+		if (ASYNC_ENABLED(3, 1))
+			return 0;
+		if (addr + size <= ASYNC_BANK3_BASE + ASYNC_BANK3_SIZE)
+			return 1;
+		return 0;
+	}
+
+	/* not within async bounds */
+	return 2;
+}
 
 int bfin_mem_access_type(unsigned long addr, unsigned long size)
 {
@@ -374,17 +424,11 @@ int bfin_mem_access_type(unsigned long addr, unsigned long size)
 	if (addr >= SYSMMR_BASE)
 		return BFIN_MEM_ACCESS_CORE_ONLY;
 
-	/* We can't read EBIU banks that aren't enabled or we end up hanging
-	 * on the access to the async space.
-	 */
-	if (in_mem_const(addr, size, ASYNC_BANK0_BASE, ASYNC_BANK0_SIZE))
-		return IN_ASYNC(0, 0);
-	if (in_mem_const(addr, size, ASYNC_BANK1_BASE, ASYNC_BANK1_SIZE))
-		return IN_ASYNC(1, 0);
-	if (in_mem_const(addr, size, ASYNC_BANK2_BASE, ASYNC_BANK2_SIZE))
-		return IN_ASYNC(2, 1);
-	if (in_mem_const(addr, size, ASYNC_BANK3_BASE, ASYNC_BANK3_SIZE))
-		return IN_ASYNC(3, 1);
+	switch (in_async(addr, size)) {
+	case 0: return -EFAULT;
+	case 1: return BFIN_MEM_ACCESS_CORE;
+	case 2: /* fall through */;
+	}
 
 	if (in_mem_const(addr, size, BOOT_ROM_START, BOOT_ROM_LENGTH))
 		return BFIN_MEM_ACCESS_CORE;
@@ -401,6 +445,8 @@ __attribute__((l1_text))
 /* Return 1 if access to memory range is OK, 0 otherwise */
 int _access_ok(unsigned long addr, unsigned long size)
 {
+	int aret;
+
 	if (size == 0)
 		return 1;
 	/* Check that things do not wrap around */
@@ -450,6 +496,11 @@ int _access_ok(unsigned long addr, unsigned long size)
 	if (in_mem_const(addr, size, COREB_L1_DATA_B_START, COREB_L1_DATA_B_LENGTH))
 		return 1;
 #endif
+
+	aret = in_async(addr, size);
+	if (aret < 2)
+		return aret;
+
 	if (in_mem_const_off(addr, size, _ebss_l2 - _stext_l2, L2_START, L2_LENGTH))
 		return 1;
 
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index 56b0ba12175f..65567dc4b9f5 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -316,19 +316,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 			case BFIN_MEM_ACCESS_CORE_ONLY:
 				copied = access_process_vm(child, addr, &data,
 				                           to_copy, 1);
-				if (copied)
-					break;
-
-				/* hrm, why didn't that work ... maybe no mapping */
-				if (addr >= FIXED_CODE_START &&
-				    addr + to_copy <= FIXED_CODE_END) {
-					copy_to_user_page(0, 0, 0, paddr, &data, to_copy);
-					copied = to_copy;
-				} else if (addr >= BOOT_ROM_START) {
-					memcpy(paddr, &data, to_copy);
-					copied = to_copy;
-				}
-
 				break;
 			case BFIN_MEM_ACCESS_DMA:
 				if (safe_dma_memcpy(paddr, &data, to_copy))
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index c202a44d1416..95448ae9c43a 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -178,10 +178,10 @@ void __init bfin_cache_init(void)
 
 void __init bfin_relocate_l1_mem(void)
 {
-	unsigned long l1_code_length;
-	unsigned long l1_data_a_length;
-	unsigned long l1_data_b_length;
-	unsigned long l2_length;
+	unsigned long text_l1_len = (unsigned long)_text_l1_len;
+	unsigned long data_l1_len = (unsigned long)_data_l1_len;
+	unsigned long data_b_l1_len = (unsigned long)_data_b_l1_len;
+	unsigned long l2_len = (unsigned long)_l2_len;
 
 	early_shadow_stamp();
 
@@ -201,30 +201,23 @@ void __init bfin_relocate_l1_mem(void)
 
 	blackfin_dma_early_init();
 
-	/* if necessary, copy _stext_l1 to _etext_l1 to L1 instruction SRAM */
-	l1_code_length = _etext_l1 - _stext_l1;
-	if (l1_code_length)
-		early_dma_memcpy(_stext_l1, _l1_lma_start, l1_code_length);
+	/* if necessary, copy L1 text to L1 instruction SRAM */
+	if (L1_CODE_LENGTH && text_l1_len)
+		early_dma_memcpy(_stext_l1, _text_l1_lma, text_l1_len);
 
-	/* if necessary, copy _sdata_l1 to _sbss_l1 to L1 data bank A SRAM */
-	l1_data_a_length = _sbss_l1 - _sdata_l1;
-	if (l1_data_a_length)
-		early_dma_memcpy(_sdata_l1, _l1_lma_start + l1_code_length, l1_data_a_length);
+	/* if necessary, copy L1 data to L1 data bank A SRAM */
+	if (L1_DATA_A_LENGTH && data_l1_len)
+		early_dma_memcpy(_sdata_l1, _data_l1_lma, data_l1_len);
 
-	/* if necessary, copy _sdata_b_l1 to _sbss_b_l1 to L1 data bank B SRAM */
-	l1_data_b_length = _sbss_b_l1 - _sdata_b_l1;
-	if (l1_data_b_length)
-		early_dma_memcpy(_sdata_b_l1, _l1_lma_start + l1_code_length +
-			l1_data_a_length, l1_data_b_length);
+	/* if necessary, copy L1 data B to L1 data bank B SRAM */
+	if (L1_DATA_B_LENGTH && data_b_l1_len)
+		early_dma_memcpy(_sdata_b_l1, _data_b_l1_lma, data_b_l1_len);
 
 	early_dma_memcpy_done();
 
-	/* if necessary, copy _stext_l2 to _edata_l2 to L2 SRAM */
-	if (L2_LENGTH != 0) {
-		l2_length = _sbss_l2 - _stext_l2;
-		if (l2_length)
-			memcpy(_stext_l2, _l2_lma_start, l2_length);
-	}
+	/* if necessary, copy L2 text/data to L2 SRAM */
+	if (L2_LENGTH && l2_len)
+		memcpy(_stext_l2, _l2_lma, l2_len);
 }
 
 /* add_memory_region to memmap */
@@ -608,11 +601,6 @@ static __init void memory_setup(void)
 	page_mask_order = get_order(3 * page_mask_nelts * sizeof(long));
 #endif
 
-#if !defined(CONFIG_MTD_UCLINUX)
-	/*In case there is no valid CPLB behind memory_end make sure we don't get to close*/
-	memory_end -= SIZE_4K;
-#endif
-
 	init_mm.start_code = (unsigned long)_stext;
 	init_mm.end_code = (unsigned long)_etext;
 	init_mm.end_data = (unsigned long)_edata;
@@ -917,7 +905,7 @@ void __init setup_arch(char **cmdline_p)
 
 	printk(KERN_INFO "Blackfin support (C) 2004-2009 Analog Devices, Inc.\n");
 	if (bfin_compiled_revid() == 0xffff)
-		printk(KERN_INFO "Compiled for ADSP-%s Rev any\n", CPU);
+		printk(KERN_INFO "Compiled for ADSP-%s Rev any, running on 0.%d\n", CPU, bfin_revid());
 	else if (bfin_compiled_revid() == -1)
 		printk(KERN_INFO "Compiled for ADSP-%s Rev none\n", CPU);
 	else
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index 9d90c18fab23..e0fd63e9e38a 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -12,6 +12,7 @@
 #include <linux/binfmts.h>
 #include <linux/freezer.h>
 #include <linux/uaccess.h>
+#include <linux/tracehook.h>
 
 #include <asm/cacheflush.h>
 #include <asm/ucontext.h>
@@ -332,3 +333,20 @@ asmlinkage void do_signal(struct pt_regs *regs)
 		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
 	}
 }
+
+/*
+ * notification of userspace execution resumption
+ */
+asmlinkage void do_notify_resume(struct pt_regs *regs)
+{
+	if (test_thread_flag(TIF_SIGPENDING) || test_thread_flag(TIF_RESTORE_SIGMASK))
+		do_signal(regs);
+
+	if (test_thread_flag(TIF_NOTIFY_RESUME)) {
+		clear_thread_flag(TIF_NOTIFY_RESUME);
+		tracehook_notify_resume(regs);
+		if (current->replacement_session_keyring)
+			key_replace_session_keyring();
+	}
+}
+
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c
index 359cfb1815ca..17c38c5b5b22 100644
--- a/arch/blackfin/kernel/time-ts.c
+++ b/arch/blackfin/kernel/time-ts.c
@@ -22,8 +22,6 @@
 #include <asm/time.h>
 #include <asm/gptimers.h>
 
-#if defined(CONFIG_CYCLES_CLOCKSOURCE)
-
 /* Accelerators for sched_clock()
  * convert from cycles(64bits) => nanoseconds (64bits)
  *  basic equation:
@@ -46,20 +44,11 @@
  *			-johnstul@us.ibm.com "math is hard, lets go shopping!"
  */
 
-static unsigned long cyc2ns_scale;
 #define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
 
-static inline void set_cyc2ns_scale(unsigned long cpu_khz)
-{
-	cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR) / cpu_khz;
-}
-
-static inline unsigned long long cycles_2_ns(cycle_t cyc)
-{
-	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
-}
+#if defined(CONFIG_CYCLES_CLOCKSOURCE)
 
-static cycle_t bfin_read_cycles(struct clocksource *cs)
+static notrace cycle_t bfin_read_cycles(struct clocksource *cs)
 {
 	return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod);
 }
@@ -69,19 +58,18 @@ static struct clocksource bfin_cs_cycles = {
 	.rating		= 400,
 	.read		= bfin_read_cycles,
 	.mask		= CLOCKSOURCE_MASK(64),
-	.shift		= 22,
+	.shift		= CYC2NS_SCALE_FACTOR,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-unsigned long long sched_clock(void)
+static inline unsigned long long bfin_cs_cycles_sched_clock(void)
 {
-	return cycles_2_ns(bfin_read_cycles(&bfin_cs_cycles));
+	return clocksource_cyc2ns(bfin_read_cycles(&bfin_cs_cycles),
+		bfin_cs_cycles.mult, bfin_cs_cycles.shift);
 }
 
 static int __init bfin_cs_cycles_init(void)
 {
-	set_cyc2ns_scale(get_cclk() / 1000);
-
 	bfin_cs_cycles.mult = \
 		clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift);
 
@@ -108,7 +96,7 @@ void __init setup_gptimer0(void)
 	enable_gptimers(TIMER0bit);
 }
 
-static cycle_t bfin_read_gptimer0(void)
+static cycle_t bfin_read_gptimer0(struct clocksource *cs)
 {
 	return bfin_read_TIMER0_COUNTER();
 }
@@ -118,10 +106,16 @@ static struct clocksource bfin_cs_gptimer0 = {
 	.rating		= 350,
 	.read		= bfin_read_gptimer0,
 	.mask		= CLOCKSOURCE_MASK(32),
-	.shift		= 22,
+	.shift		= CYC2NS_SCALE_FACTOR,
 	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
+static inline unsigned long long bfin_cs_gptimer0_sched_clock(void)
+{
+	return clocksource_cyc2ns(bfin_read_TIMER0_COUNTER(),
+		bfin_cs_gptimer0.mult, bfin_cs_gptimer0.shift);
+}
+
 static int __init bfin_cs_gptimer0_init(void)
 {
 	setup_gptimer0();
@@ -138,6 +132,19 @@ 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)
+{
+#if defined(CONFIG_CYCLES_CLOCKSOURCE)
+	return bfin_cs_cycles_sched_clock();
+#else
+	return bfin_cs_gptimer0_sched_clock();
+#endif
+}
+#endif
+
 #ifdef CONFIG_CORE_TIMER_IRQ_L1
 __attribute__((l1_text))
 #endif
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
index bd3b53da295e..13c1ee3e6408 100644
--- a/arch/blackfin/kernel/time.c
+++ b/arch/blackfin/kernel/time.c
@@ -184,11 +184,3 @@ void __init time_init(void)
 
 	time_sched_init(timer_interrupt);
 }
-
-/*
- * Scheduler clock - returns current time in nanosec units.
- */
-unsigned long long sched_clock(void)
-{
-	return (unsigned long long)jiffies *(NSEC_PER_SEC / HZ);
-}
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 9636bace00e8..d3cbcd6bd985 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -119,6 +119,15 @@ static void decode_address(char *buf, unsigned long address)
 		return;
 	}
 
+	/*
+	 * Don't walk any of the vmas if we are oopsing, it has been known
+	 * to cause problems - corrupt vmas (kernel crashes) cause double faults
+	 */
+	if (oops_in_progress) {
+		strcat(buf, "/* kernel dynamic memory (maybe user-space) */");
+		return;
+	}
+
 	/* looks like we're off in user-land, so let's walk all the
 	 * mappings of all our processes and see if we can't be a whee
 	 * bit more specific
@@ -515,6 +524,36 @@ asmlinkage notrace void trap_c(struct pt_regs *fp)
 			break;
 		/* External Memory Addressing Error */
 		case (SEQSTAT_HWERRCAUSE_EXTERN_ADDR):
+			if (ANOMALY_05000310) {
+				static unsigned long anomaly_rets;
+
+				if ((fp->pc >= (L1_CODE_START + L1_CODE_LENGTH - 512)) &&
+				    (fp->pc < (L1_CODE_START + L1_CODE_LENGTH))) {
+					/*
+					 * A false hardware error will happen while fetching at
+					 * the L1 instruction SRAM boundary.  Ignore it.
+					 */
+					anomaly_rets = fp->rets;
+					goto traps_done;
+				} else if (fp->rets == anomaly_rets) {
+					/*
+					 * While boundary code returns to a function, at the ret
+					 * point, a new false hardware error might occur too based
+					 * on tests.  Ignore it too.
+					 */
+					goto traps_done;
+				} else if ((fp->rets >= (L1_CODE_START + L1_CODE_LENGTH - 512)) &&
+				           (fp->rets < (L1_CODE_START + L1_CODE_LENGTH))) {
+					/*
+					 * If boundary code calls a function, at the entry point,
+					 * a new false hardware error maybe happen based on tests.
+					 * Ignore it too.
+					 */
+					goto traps_done;
+				} else
+					anomaly_rets = 0;
+			}
+
 			info.si_code = BUS_ADRERR;
 			sig = SIGBUS;
 			strerror = KERN_NOTICE HWC_x3(KERN_NOTICE);
@@ -976,12 +1015,12 @@ void dump_bfin_process(struct pt_regs *fp)
 	    !((unsigned long)current & 0x3) && current->pid) {
 		verbose_printk(KERN_NOTICE "CURRENT PROCESS:\n");
 		if (current->comm >= (char *)FIXED_CODE_START)
-			verbose_printk(KERN_NOTICE "COMM=%s PID=%d\n",
+			verbose_printk(KERN_NOTICE "COMM=%s PID=%d",
 				current->comm, current->pid);
 		else
-			verbose_printk(KERN_NOTICE "COMM= invalid\n");
+			verbose_printk(KERN_NOTICE "COMM= invalid");
 
-		printk(KERN_NOTICE "CPU = %d\n", current_thread_info()->cpu);
+		printk(KERN_CONT " CPU=%d\n", current_thread_info()->cpu);
 		if (!((unsigned long)current->mm & 0x3) && (unsigned long)current->mm >= FIXED_CODE_START)
 			verbose_printk(KERN_NOTICE
 				"TEXT = 0x%p-0x%p        DATA = 0x%p-0x%p\n"
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index f39707c6590d..66799e763dc9 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -121,8 +121,6 @@ SECTIONS
 		EXIT_DATA
 	}
 
-	__l1_lma_start = .;
-
 	.text_l1 L1_CODE_START : AT(LOADADDR(.exit.data) + SIZEOF(.exit.data))
 	{
 		. = ALIGN(4);
@@ -134,9 +132,11 @@ SECTIONS
 		. = ALIGN(4);
 		__etext_l1 = .;
 	}
-	ASSERT (SIZEOF(.text_l1) <= L1_CODE_LENGTH, "L1 text overflow!")
+	__text_l1_lma = LOADADDR(.text_l1);
+	__text_l1_len = SIZEOF(.text_l1);
+	ASSERT (__text_l1_len <= L1_CODE_LENGTH, "L1 text overflow!")
 
-	.data_l1 L1_DATA_A_START : AT(LOADADDR(.text_l1) + SIZEOF(.text_l1))
+	.data_l1 L1_DATA_A_START : AT(__text_l1_lma + __text_l1_len)
 	{
 		. = ALIGN(4);
 		__sdata_l1 = .;
@@ -152,9 +152,11 @@ SECTIONS
 		. = ALIGN(4);
 		__ebss_l1 = .;
 	}
-	ASSERT (SIZEOF(.data_l1) <= L1_DATA_A_LENGTH, "L1 data A overflow!")
+	__data_l1_lma = LOADADDR(.data_l1);
+	__data_l1_len = SIZEOF(.data_l1);
+	ASSERT (__data_l1_len <= L1_DATA_A_LENGTH, "L1 data A overflow!")
 
-	.data_b_l1 L1_DATA_B_START : AT(LOADADDR(.data_l1) + SIZEOF(.data_l1))
+	.data_b_l1 L1_DATA_B_START : AT(__data_l1_lma + __data_l1_len)
 	{
 		. = ALIGN(4);
 		__sdata_b_l1 = .;
@@ -167,11 +169,11 @@ SECTIONS
 		. = ALIGN(4);
 		__ebss_b_l1 = .;
 	}
-	ASSERT (SIZEOF(.data_b_l1) <= L1_DATA_B_LENGTH, "L1 data B overflow!")
-
-	__l2_lma_start = LOADADDR(.data_b_l1) + SIZEOF(.data_b_l1);
+	__data_b_l1_lma = LOADADDR(.data_b_l1);
+	__data_b_l1_len = SIZEOF(.data_b_l1);
+	ASSERT (__data_b_l1_len <= L1_DATA_B_LENGTH, "L1 data B overflow!")
 
-	.text_data_l2 L2_START : AT(LOADADDR(.data_b_l1) + SIZEOF(.data_b_l1))
+	.text_data_l2 L2_START : AT(__data_b_l1_lma + __data_b_l1_len)
 	{
 		. = ALIGN(4);
 		__stext_l2 = .;
@@ -193,12 +195,14 @@ SECTIONS
 		. = ALIGN(4);
 		__ebss_l2 = .;
 	}
-	ASSERT (SIZEOF(.text_data_l2) <= L2_LENGTH, "L2 overflow!")
+	__l2_lma = LOADADDR(.text_data_l2);
+	__l2_len = SIZEOF(.text_data_l2);
+	ASSERT (__l2_len <= L2_LENGTH, "L2 overflow!")
 
 	/* Force trailing alignment of our init section so that when we
 	 * free our init memory, we don't leave behind a partial page.
 	 */
-	. = LOADADDR(.text_data_l2) + SIZEOF(.text_data_l2);
+	. = __l2_lma + __l2_len;
 	. = ALIGN(PAGE_SIZE);
 	___init_end = .;