public inbox for linux-sh@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] sh: INTC ioremap support V2
@ 2010-03-10  9:38 Magnus Damm
  0 siblings, 0 replies; only message in thread
From: Magnus Damm @ 2010-03-10  9:38 UTC (permalink / raw)
  To: linux-sh

From: Magnus Damm <damm@opensource.se>

Extend the INTC code with ioremap() support V2.

Support INTC controllers that are not accessible through
a 1:1 virt:phys window. Needed by SH-Mobile ARM INTCS.

The INTC code behaves as usual if the io window resource
is omitted. The slow phys->virt lookup only happens during
setup. The fast path code operates on virtual addresses.

Signed-off-by: Magnus Damm <damm@opensource.se>
---

 INTC topic branch material

 Applies on top of the INTC memory error handling patch

 Changes since V1:
 - support multiple memory windows
 - use phys_addr_t and void __iomem *
 - error handling

 drivers/sh/intc.c       |   80 ++++++++++++++++++++++++++++++++++++++++++-----
 include/linux/sh_intc.h |    4 ++
 2 files changed, 76 insertions(+), 8 deletions(-)

--- 0014/drivers/sh/intc.c
+++ work/drivers/sh/intc.c	2010-03-10 17:38:40.000000000 +0900
@@ -43,6 +43,12 @@ struct intc_handle_int {
 	unsigned long handle;
 };
 
+struct intc_win {
+	phys_addr_t phys;
+	void __iomem *virt;
+	unsigned long size;
+};
+
 struct intc_desc_int {
 	struct list_head list;
 	struct sys_device sysdev;
@@ -56,6 +62,8 @@ struct intc_desc_int {
 	unsigned int nr_prio;
 	struct intc_handle_int *sense;
 	unsigned int nr_sense;
+	struct intc_win *win;
+	unsigned int nr_win;
 	struct irq_chip chip;
 };
 
@@ -420,11 +428,39 @@ static int intc_set_sense(unsigned int i
 	return 0;
 }
 
+static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
+				       unsigned long address)
+{
+	struct intc_win *win;
+	int k;
+
+	/* scan through physical windows and convert address */
+	for (k = 0; k < d->nr_win; k++) {
+		win = d->win + k;
+
+		if (address < win->phys)
+			continue;
+
+		if (address >= (win->phys + win->size))
+			continue;
+
+		address -= win->phys;
+		address += (unsigned long)win->virt;
+
+		return address;
+	}
+
+	/* no windows defined, register must be 1:1 mapped virt:phys */
+	return address;
+}
+
 static unsigned int __init intc_get_reg(struct intc_desc_int *d,
-				 unsigned long address)
+					unsigned long address)
 {
 	unsigned int k;
 
+	address = intc_phys_to_virt(d, address);
+
 	for (k = 0; k < d->nr_reg; k++) {
 		if (d->reg[k] = address)
 			return k;
@@ -774,6 +810,8 @@ static unsigned int __init save_reg(stru
 				    unsigned int smp)
 {
 	if (value) {
+		value = intc_phys_to_virt(d, value);
+
 		d->reg[cnt] = value;
 #ifdef CONFIG_SMP
 		d->smp[cnt] = smp;
@@ -794,6 +832,7 @@ int __init register_intc_controller(stru
 	unsigned int i, k, smp;
 	struct intc_hw_desc *hw = &desc->hw;
 	struct intc_desc_int *d;
+	struct resource *res;
 
 	d = kzalloc(sizeof(*d), GFP_NOWAIT);
 	if (!d)
@@ -802,6 +841,25 @@ int __init register_intc_controller(stru
 	INIT_LIST_HEAD(&d->list);
 	list_add(&d->list, &intc_list);
 
+	if (desc->num_resources) {
+		d->nr_win = desc->num_resources;
+		d->win = kzalloc(d->nr_win * sizeof(*d->win), GFP_NOWAIT);
+		if (!d->win)
+			goto err1;
+
+		for (k = 0; k < d->nr_win; k++) {
+			res = desc->resource + k;
+			WARN_ON(resource_type(res) != IORESOURCE_MEM);
+			d->win[k].phys = res->start;
+			d->win[k].size = resource_size(res);
+			d->win[k].virt = ioremap_nocache(res->start,
+							 resource_size(res));
+
+			if (!d->win[k].virt)
+				goto err2;
+		}
+	}
+
 	d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
 	d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
 	d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
@@ -809,12 +867,12 @@ int __init register_intc_controller(stru
 
 	d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
 	if (!d->reg)
-		goto err1;
+		goto err2;
 
 #ifdef CONFIG_SMP
 	d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
 	if (!d->smp)
-		goto err2;
+		goto err3;
 #endif
 	k = 0;
 
@@ -830,7 +888,7 @@ int __init register_intc_controller(stru
 		d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
 				  GFP_NOWAIT);
 		if (!d->prio)
-			goto err3;
+			goto err4;
 
 		for (i = 0; i < hw->nr_prio_regs; i++) {
 			smp = IS_SMP(hw->prio_regs[i]);
@@ -843,7 +901,7 @@ int __init register_intc_controller(stru
 		d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
 				   GFP_NOWAIT);
 		if (!d->sense)
-			goto err4;
+			goto err5;
 
 		for (i = 0; i < hw->nr_sense_regs; i++)
 			k += save_reg(d, k, hw->sense_regs[i].reg, 0);
@@ -925,14 +983,20 @@ int __init register_intc_controller(stru
 		intc_enable_disable_enum(desc, d, desc->force_enable, 1);
 
 	return 0;
- err4:
+ err5:
 	kfree(d->prio);
- err3:
+ err4:
 #ifdef CONFIG_SMP
 	kfree(d->smp);
- err2:
+ err3:
 #endif
 	kfree(d->reg);
+ err2:
+	if (d->win)
+		for (k = 0; k < d->nr_win; k++)
+			iounmap(d->win[k].virt);
+
+	kfree(d->win);
  err1:
 	kfree(d);
  err0:
--- 0014/include/linux/sh_intc.h
+++ work/include/linux/sh_intc.h	2010-03-10 17:38:16.000000000 +0900
@@ -1,6 +1,8 @@
 #ifndef __SH_INTC_H
 #define __SH_INTC_H
 
+#include <linux/ioport.h>
+
 typedef unsigned char intc_enum;
 
 struct intc_vect {
@@ -71,6 +73,8 @@ struct intc_hw_desc {
 
 struct intc_desc {
 	char *name;
+	struct resource *resource;
+	unsigned int num_resources;
 	intc_enum force_enable;
 	intc_enum force_disable;
 	struct intc_hw_desc hw;

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2010-03-10  9:38 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-10  9:38 [PATCH] sh: INTC ioremap support V2 Magnus Damm

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox