Commit dec710b77c2cf04bf512acada3c14a16f11708d9

Authored by Magnus Damm
Committed by Paul Mundt
1 parent 01e9651a21

sh: INTC ioremap support

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>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>

Showing 2 changed files with 78 additions and 10 deletions Side-by-side Diff

... ... @@ -43,6 +43,12 @@
43 43 unsigned long handle;
44 44 };
45 45  
  46 +struct intc_window {
  47 + phys_addr_t phys;
  48 + void __iomem *virt;
  49 + unsigned long size;
  50 +};
  51 +
46 52 struct intc_desc_int {
47 53 struct list_head list;
48 54 struct sys_device sysdev;
... ... @@ -56,6 +62,8 @@
56 62 unsigned int nr_prio;
57 63 struct intc_handle_int *sense;
58 64 unsigned int nr_sense;
  65 + struct intc_window *window;
  66 + unsigned int nr_windows;
59 67 struct irq_chip chip;
60 68 };
61 69  
62 70  
63 71  
... ... @@ -420,11 +428,39 @@
420 428 return 0;
421 429 }
422 430  
  431 +static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
  432 + unsigned long address)
  433 +{
  434 + struct intc_window *window;
  435 + int k;
  436 +
  437 + /* scan through physical windows and convert address */
  438 + for (k = 0; k < d->nr_windows; k++) {
  439 + window = d->window + k;
  440 +
  441 + if (address < window->phys)
  442 + continue;
  443 +
  444 + if (address >= (window->phys + window->size))
  445 + continue;
  446 +
  447 + address -= window->phys;
  448 + address += (unsigned long)window->virt;
  449 +
  450 + return address;
  451 + }
  452 +
  453 + /* no windows defined, register must be 1:1 mapped virt:phys */
  454 + return address;
  455 +}
  456 +
423 457 static unsigned int __init intc_get_reg(struct intc_desc_int *d,
424   - unsigned long address)
  458 + unsigned long address)
425 459 {
426 460 unsigned int k;
427 461  
  462 + address = intc_phys_to_virt(d, address);
  463 +
428 464 for (k = 0; k < d->nr_reg; k++) {
429 465 if (d->reg[k] == address)
430 466 return k;
... ... @@ -774,6 +810,8 @@
774 810 unsigned int smp)
775 811 {
776 812 if (value) {
  813 + value = intc_phys_to_virt(d, value);
  814 +
777 815 d->reg[cnt] = value;
778 816 #ifdef CONFIG_SMP
779 817 d->smp[cnt] = smp;
... ... @@ -794,6 +832,7 @@
794 832 unsigned int i, k, smp;
795 833 struct intc_hw_desc *hw = &desc->hw;
796 834 struct intc_desc_int *d;
  835 + struct resource *res;
797 836  
798 837 d = kzalloc(sizeof(*d), GFP_NOWAIT);
799 838 if (!d)
... ... @@ -802,6 +841,25 @@
802 841 INIT_LIST_HEAD(&d->list);
803 842 list_add(&d->list, &intc_list);
804 843  
  844 + if (desc->num_resources) {
  845 + d->nr_windows = desc->num_resources;
  846 + d->window = kzalloc(d->nr_windows * sizeof(*d->window),
  847 + GFP_NOWAIT);
  848 + if (!d->window)
  849 + goto err1;
  850 +
  851 + for (k = 0; k < d->nr_windows; k++) {
  852 + res = desc->resource + k;
  853 + WARN_ON(resource_type(res) != IORESOURCE_MEM);
  854 + d->window[k].phys = res->start;
  855 + d->window[k].size = resource_size(res);
  856 + d->window[k].virt = ioremap_nocache(res->start,
  857 + resource_size(res));
  858 + if (!d->window[k].virt)
  859 + goto err2;
  860 + }
  861 + }
  862 +
805 863 d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
806 864 d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
807 865 d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
808 866  
... ... @@ -809,12 +867,12 @@
809 867  
810 868 d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
811 869 if (!d->reg)
812   - goto err1;
  870 + goto err2;
813 871  
814 872 #ifdef CONFIG_SMP
815 873 d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
816 874 if (!d->smp)
817   - goto err2;
  875 + goto err3;
818 876 #endif
819 877 k = 0;
820 878  
... ... @@ -830,7 +888,7 @@
830 888 d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
831 889 GFP_NOWAIT);
832 890 if (!d->prio)
833   - goto err3;
  891 + goto err4;
834 892  
835 893 for (i = 0; i < hw->nr_prio_regs; i++) {
836 894 smp = IS_SMP(hw->prio_regs[i]);
... ... @@ -843,7 +901,7 @@
843 901 d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
844 902 GFP_NOWAIT);
845 903 if (!d->sense)
846   - goto err4;
  904 + goto err5;
847 905  
848 906 for (i = 0; i < hw->nr_sense_regs; i++)
849 907 k += save_reg(d, k, hw->sense_regs[i].reg, 0);
850 908  
851 909  
852 910  
853 911  
... ... @@ -925,17 +983,23 @@
925 983 intc_enable_disable_enum(desc, d, desc->force_enable, 1);
926 984  
927 985 return 0;
928   - err4:
  986 +err5:
929 987 kfree(d->prio);
930   - err3:
  988 +err4:
931 989 #ifdef CONFIG_SMP
932 990 kfree(d->smp);
933   - err2:
  991 +err3:
934 992 #endif
935 993 kfree(d->reg);
936   - err1:
  994 +err2:
  995 + for (k = 0; k < d->nr_windows; k++)
  996 + if (d->window[k].virt)
  997 + iounmap(d->window[k].virt);
  998 +
  999 + kfree(d->window);
  1000 +err1:
937 1001 kfree(d);
938   - err0:
  1002 +err0:
939 1003 pr_err("unable to allocate INTC memory\n");
940 1004  
941 1005 return -ENOMEM;
include/linux/sh_intc.h
1 1 #ifndef __SH_INTC_H
2 2 #define __SH_INTC_H
3 3  
  4 +#include <linux/ioport.h>
  5 +
4 6 typedef unsigned char intc_enum;
5 7  
6 8 struct intc_vect {
... ... @@ -71,6 +73,8 @@
71 73  
72 74 struct intc_desc {
73 75 char *name;
  76 + struct resource *resource;
  77 + unsigned int num_resources;
74 78 intc_enum force_enable;
75 79 intc_enum force_disable;
76 80 struct intc_hw_desc hw;