aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/sh
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sh')
-rw-r--r--drivers/sh/intc.c95
1 files changed, 93 insertions, 2 deletions
diff --git a/drivers/sh/intc.c b/drivers/sh/intc.c
index a3d8677af6a5..f43850527645 100644
--- a/drivers/sh/intc.c
+++ b/drivers/sh/intc.c
@@ -44,6 +44,12 @@ struct intc_handle_int {
44 unsigned long handle; 44 unsigned long handle;
45}; 45};
46 46
47struct intc_window {
48 phys_addr_t phys;
49 void __iomem *virt;
50 unsigned long size;
51};
52
47struct intc_desc_int { 53struct intc_desc_int {
48 struct list_head list; 54 struct list_head list;
49 struct sys_device sysdev; 55 struct sys_device sysdev;
@@ -57,6 +63,8 @@ struct intc_desc_int {
57 unsigned int nr_prio; 63 unsigned int nr_prio;
58 struct intc_handle_int *sense; 64 struct intc_handle_int *sense;
59 unsigned int nr_sense; 65 unsigned int nr_sense;
66 struct intc_window *window;
67 unsigned int nr_windows;
60 struct irq_chip chip; 68 struct irq_chip chip;
61}; 69};
62 70
@@ -446,11 +454,39 @@ static int intc_set_sense(unsigned int irq, unsigned int type)
446 return 0; 454 return 0;
447} 455}
448 456
457static unsigned long intc_phys_to_virt(struct intc_desc_int *d,
458 unsigned long address)
459{
460 struct intc_window *window;
461 int k;
462
463 /* scan through physical windows and convert address */
464 for (k = 0; k < d->nr_windows; k++) {
465 window = d->window + k;
466
467 if (address < window->phys)
468 continue;
469
470 if (address >= (window->phys + window->size))
471 continue;
472
473 address -= window->phys;
474 address += (unsigned long)window->virt;
475
476 return address;
477 }
478
479 /* no windows defined, register must be 1:1 mapped virt:phys */
480 return address;
481}
482
449static unsigned int __init intc_get_reg(struct intc_desc_int *d, 483static unsigned int __init intc_get_reg(struct intc_desc_int *d,
450 unsigned long address) 484 unsigned long address)
451{ 485{
452 unsigned int k; 486 unsigned int k;
453 487
488 address = intc_phys_to_virt(d, address);
489
454 for (k = 0; k < d->nr_reg; k++) { 490 for (k = 0; k < d->nr_reg; k++) {
455 if (d->reg[k] == address) 491 if (d->reg[k] == address)
456 return k; 492 return k;
@@ -800,6 +836,8 @@ static unsigned int __init save_reg(struct intc_desc_int *d,
800 unsigned int smp) 836 unsigned int smp)
801{ 837{
802 if (value) { 838 if (value) {
839 value = intc_phys_to_virt(d, value);
840
803 d->reg[cnt] = value; 841 d->reg[cnt] = value;
804#ifdef CONFIG_SMP 842#ifdef CONFIG_SMP
805 d->smp[cnt] = smp; 843 d->smp[cnt] = smp;
@@ -815,25 +853,52 @@ static void intc_redirect_irq(unsigned int irq, struct irq_desc *desc)
815 generic_handle_irq((unsigned int)get_irq_data(irq)); 853 generic_handle_irq((unsigned int)get_irq_data(irq));
816} 854}
817 855
818void __init register_intc_controller(struct intc_desc *desc) 856int __init register_intc_controller(struct intc_desc *desc)
819{ 857{
820 unsigned int i, k, smp; 858 unsigned int i, k, smp;
821 struct intc_hw_desc *hw = &desc->hw; 859 struct intc_hw_desc *hw = &desc->hw;
822 struct intc_desc_int *d; 860 struct intc_desc_int *d;
861 struct resource *res;
823 862
824 d = kzalloc(sizeof(*d), GFP_NOWAIT); 863 d = kzalloc(sizeof(*d), GFP_NOWAIT);
864 if (!d)
865 goto err0;
825 866
826 INIT_LIST_HEAD(&d->list); 867 INIT_LIST_HEAD(&d->list);
827 list_add(&d->list, &intc_list); 868 list_add(&d->list, &intc_list);
828 869
870 if (desc->num_resources) {
871 d->nr_windows = desc->num_resources;
872 d->window = kzalloc(d->nr_windows * sizeof(*d->window),
873 GFP_NOWAIT);
874 if (!d->window)
875 goto err1;
876
877 for (k = 0; k < d->nr_windows; k++) {
878 res = desc->resource + k;
879 WARN_ON(resource_type(res) != IORESOURCE_MEM);
880 d->window[k].phys = res->start;
881 d->window[k].size = resource_size(res);
882 d->window[k].virt = ioremap_nocache(res->start,
883 resource_size(res));
884 if (!d->window[k].virt)
885 goto err2;
886 }
887 }
888
829 d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0; 889 d->nr_reg = hw->mask_regs ? hw->nr_mask_regs * 2 : 0;
830 d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0; 890 d->nr_reg += hw->prio_regs ? hw->nr_prio_regs * 2 : 0;
831 d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0; 891 d->nr_reg += hw->sense_regs ? hw->nr_sense_regs : 0;
832 d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0; 892 d->nr_reg += hw->ack_regs ? hw->nr_ack_regs : 0;
833 893
834 d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT); 894 d->reg = kzalloc(d->nr_reg * sizeof(*d->reg), GFP_NOWAIT);
895 if (!d->reg)
896 goto err2;
897
835#ifdef CONFIG_SMP 898#ifdef CONFIG_SMP
836 d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT); 899 d->smp = kzalloc(d->nr_reg * sizeof(*d->smp), GFP_NOWAIT);
900 if (!d->smp)
901 goto err3;
837#endif 902#endif
838 k = 0; 903 k = 0;
839 904
@@ -848,6 +913,8 @@ void __init register_intc_controller(struct intc_desc *desc)
848 if (hw->prio_regs) { 913 if (hw->prio_regs) {
849 d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio), 914 d->prio = kzalloc(hw->nr_vectors * sizeof(*d->prio),
850 GFP_NOWAIT); 915 GFP_NOWAIT);
916 if (!d->prio)
917 goto err4;
851 918
852 for (i = 0; i < hw->nr_prio_regs; i++) { 919 for (i = 0; i < hw->nr_prio_regs; i++) {
853 smp = IS_SMP(hw->prio_regs[i]); 920 smp = IS_SMP(hw->prio_regs[i]);
@@ -859,6 +926,8 @@ void __init register_intc_controller(struct intc_desc *desc)
859 if (hw->sense_regs) { 926 if (hw->sense_regs) {
860 d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense), 927 d->sense = kzalloc(hw->nr_vectors * sizeof(*d->sense),
861 GFP_NOWAIT); 928 GFP_NOWAIT);
929 if (!d->sense)
930 goto err5;
862 931
863 for (i = 0; i < hw->nr_sense_regs; i++) 932 for (i = 0; i < hw->nr_sense_regs; i++)
864 k += save_reg(d, k, hw->sense_regs[i].reg, 0); 933 k += save_reg(d, k, hw->sense_regs[i].reg, 0);
@@ -941,6 +1010,28 @@ void __init register_intc_controller(struct intc_desc *desc)
941 /* enable bits matching force_enable after registering irqs */ 1010 /* enable bits matching force_enable after registering irqs */
942 if (desc->force_enable) 1011 if (desc->force_enable)
943 intc_enable_disable_enum(desc, d, desc->force_enable, 1); 1012 intc_enable_disable_enum(desc, d, desc->force_enable, 1);
1013
1014 return 0;
1015err5:
1016 kfree(d->prio);
1017err4:
1018#ifdef CONFIG_SMP
1019 kfree(d->smp);
1020err3:
1021#endif
1022 kfree(d->reg);
1023err2:
1024 for (k = 0; k < d->nr_windows; k++)
1025 if (d->window[k].virt)
1026 iounmap(d->window[k].virt);
1027
1028 kfree(d->window);
1029err1:
1030 kfree(d);
1031err0:
1032 pr_err("unable to allocate INTC memory\n");
1033
1034 return -ENOMEM;
944} 1035}
945 1036
946static int intc_suspend(struct sys_device *dev, pm_message_t state) 1037static int intc_suspend(struct sys_device *dev, pm_message_t state)