diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc/Kconfig | 20 | ||||
-rw-r--r-- | arch/sparc/Makefile | 1 | ||||
-rw-r--r-- | arch/sparc/include/asm/cmpxchg_64.h | 1 | ||||
-rw-r--r-- | arch/sparc/include/asm/head_32.h | 6 | ||||
-rw-r--r-- | arch/sparc/include/asm/hibernate.h | 23 | ||||
-rw-r--r-- | arch/sparc/include/asm/leon_pci.h | 1 | ||||
-rw-r--r-- | arch/sparc/include/asm/mmu_context_64.h | 2 | ||||
-rw-r--r-- | arch/sparc/include/asm/processor_64.h | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/asm-offsets.c | 15 | ||||
-rw-r--r-- | arch/sparc/kernel/leon_pci.c | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/leon_pci_grpci1.c | 724 | ||||
-rw-r--r-- | arch/sparc/kernel/leon_pci_grpci2.c | 5 | ||||
-rw-r--r-- | arch/sparc/kernel/leon_pmc.c | 4 | ||||
-rw-r--r-- | arch/sparc/mm/init_64.c | 7 | ||||
-rw-r--r-- | arch/sparc/power/Makefile | 3 | ||||
-rw-r--r-- | arch/sparc/power/hibernate.c | 42 | ||||
-rw-r--r-- | arch/sparc/power/hibernate_asm.S | 131 |
18 files changed, 977 insertions, 16 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index f5041d741dea..a639c0d07b8b 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -99,6 +99,9 @@ config HAVE_LATENCYTOP_SUPPORT | |||
99 | bool | 99 | bool |
100 | default y if SPARC64 | 100 | default y if SPARC64 |
101 | 101 | ||
102 | config ARCH_HIBERNATION_POSSIBLE | ||
103 | def_bool y if SPARC64 | ||
104 | |||
102 | config AUDIT_ARCH | 105 | config AUDIT_ARCH |
103 | bool | 106 | bool |
104 | default y | 107 | default y |
@@ -303,6 +306,10 @@ config ARCH_SPARSEMEM_DEFAULT | |||
303 | 306 | ||
304 | source "mm/Kconfig" | 307 | source "mm/Kconfig" |
305 | 308 | ||
309 | if SPARC64 | ||
310 | source "kernel/power/Kconfig" | ||
311 | endif | ||
312 | |||
306 | config SCHED_SMT | 313 | config SCHED_SMT |
307 | bool "SMT (Hyperthreading) scheduler support" | 314 | bool "SMT (Hyperthreading) scheduler support" |
308 | depends on SPARC64 && SMP | 315 | depends on SPARC64 && SMP |
@@ -472,7 +479,18 @@ config LEON_PCI | |||
472 | depends on PCI && SPARC_LEON | 479 | depends on PCI && SPARC_LEON |
473 | default y | 480 | default y |
474 | 481 | ||
475 | config GRPCI2 | 482 | config SPARC_GRPCI1 |
483 | bool "GRPCI Host Bridge Support" | ||
484 | depends on LEON_PCI | ||
485 | default y | ||
486 | help | ||
487 | Say Y here to include the GRPCI Host Bridge Driver. The GRPCI | ||
488 | PCI host controller is typically found in GRLIB SPARC32/LEON | ||
489 | systems. The driver has one property (all_pci_errors) controlled | ||
490 | from the bootloader that makes the GRPCI to generate interrupts | ||
491 | on detected PCI Parity and System errors. | ||
492 | |||
493 | config SPARC_GRPCI2 | ||
476 | bool "GRPCI2 Host Bridge Support" | 494 | bool "GRPCI2 Host Bridge Support" |
477 | depends on LEON_PCI | 495 | depends on LEON_PCI |
478 | default y | 496 | default y |
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile index 541b8b075c7d..9ff423678cbc 100644 --- a/arch/sparc/Makefile +++ b/arch/sparc/Makefile | |||
@@ -57,6 +57,7 @@ core-y += arch/sparc/ | |||
57 | libs-y += arch/sparc/prom/ | 57 | libs-y += arch/sparc/prom/ |
58 | libs-y += arch/sparc/lib/ | 58 | libs-y += arch/sparc/lib/ |
59 | 59 | ||
60 | drivers-$(CONFIG_PM) += arch/sparc/power/ | ||
60 | drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/ | 61 | drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/ |
61 | 62 | ||
62 | boot := arch/sparc/boot | 63 | boot := arch/sparc/boot |
diff --git a/arch/sparc/include/asm/cmpxchg_64.h b/arch/sparc/include/asm/cmpxchg_64.h index b30eb37294c5..4adefe8e2885 100644 --- a/arch/sparc/include/asm/cmpxchg_64.h +++ b/arch/sparc/include/asm/cmpxchg_64.h | |||
@@ -141,5 +141,6 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr, | |||
141 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | 141 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ |
142 | cmpxchg_local((ptr), (o), (n)); \ | 142 | cmpxchg_local((ptr), (o), (n)); \ |
143 | }) | 143 | }) |
144 | #define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n)) | ||
144 | 145 | ||
145 | #endif /* __ARCH_SPARC64_CMPXCHG__ */ | 146 | #endif /* __ARCH_SPARC64_CMPXCHG__ */ |
diff --git a/arch/sparc/include/asm/head_32.h b/arch/sparc/include/asm/head_32.h index a76874838f61..5f1dbe315bc8 100644 --- a/arch/sparc/include/asm/head_32.h +++ b/arch/sparc/include/asm/head_32.h | |||
@@ -55,15 +55,15 @@ | |||
55 | 55 | ||
56 | /* The Get Condition Codes software trap for userland. */ | 56 | /* The Get Condition Codes software trap for userland. */ |
57 | #define GETCC_TRAP \ | 57 | #define GETCC_TRAP \ |
58 | b getcc_trap_handler; mov %psr, %l0; nop; nop; | 58 | b getcc_trap_handler; rd %psr, %l0; nop; nop; |
59 | 59 | ||
60 | /* The Set Condition Codes software trap for userland. */ | 60 | /* The Set Condition Codes software trap for userland. */ |
61 | #define SETCC_TRAP \ | 61 | #define SETCC_TRAP \ |
62 | b setcc_trap_handler; mov %psr, %l0; nop; nop; | 62 | b setcc_trap_handler; rd %psr, %l0; nop; nop; |
63 | 63 | ||
64 | /* The Get PSR software trap for userland. */ | 64 | /* The Get PSR software trap for userland. */ |
65 | #define GETPSR_TRAP \ | 65 | #define GETPSR_TRAP \ |
66 | mov %psr, %i0; jmp %l2; rett %l2 + 4; nop; | 66 | rd %psr, %i0; jmp %l2; rett %l2 + 4; nop; |
67 | 67 | ||
68 | /* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and | 68 | /* This is for hard interrupts from level 1-14, 15 is non-maskable (nmi) and |
69 | * gets handled with another macro. | 69 | * gets handled with another macro. |
diff --git a/arch/sparc/include/asm/hibernate.h b/arch/sparc/include/asm/hibernate.h new file mode 100644 index 000000000000..2ec34f842249 --- /dev/null +++ b/arch/sparc/include/asm/hibernate.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * hibernate.h: Hibernaton support specific for sparc64. | ||
3 | * | ||
4 | * Copyright (C) 2013 Kirill V Tkhai (tkhai@yandex.ru) | ||
5 | */ | ||
6 | |||
7 | #ifndef ___SPARC_HIBERNATE_H | ||
8 | #define ___SPARC_HIBERNATE_H | ||
9 | |||
10 | struct saved_context { | ||
11 | unsigned long fp; | ||
12 | unsigned long cwp; | ||
13 | unsigned long wstate; | ||
14 | |||
15 | unsigned long tick; | ||
16 | unsigned long pstate; | ||
17 | |||
18 | unsigned long g4; | ||
19 | unsigned long g5; | ||
20 | unsigned long g6; | ||
21 | }; | ||
22 | |||
23 | #endif | ||
diff --git a/arch/sparc/include/asm/leon_pci.h b/arch/sparc/include/asm/leon_pci.h index f48527ebdd8f..bfd3ab3092b5 100644 --- a/arch/sparc/include/asm/leon_pci.h +++ b/arch/sparc/include/asm/leon_pci.h | |||
@@ -12,6 +12,7 @@ struct leon_pci_info { | |||
12 | struct pci_ops *ops; | 12 | struct pci_ops *ops; |
13 | struct resource io_space; | 13 | struct resource io_space; |
14 | struct resource mem_space; | 14 | struct resource mem_space; |
15 | struct resource busn; | ||
15 | int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); | 16 | int (*map_irq)(const struct pci_dev *dev, u8 slot, u8 pin); |
16 | }; | 17 | }; |
17 | 18 | ||
diff --git a/arch/sparc/include/asm/mmu_context_64.h b/arch/sparc/include/asm/mmu_context_64.h index 9191ca62ed9c..3d528f06e4b0 100644 --- a/arch/sparc/include/asm/mmu_context_64.h +++ b/arch/sparc/include/asm/mmu_context_64.h | |||
@@ -68,7 +68,7 @@ extern void smp_tsb_sync(struct mm_struct *mm); | |||
68 | 68 | ||
69 | extern void __flush_tlb_mm(unsigned long, unsigned long); | 69 | extern void __flush_tlb_mm(unsigned long, unsigned long); |
70 | 70 | ||
71 | /* Switch the current MM context. Interrupts are disabled. */ | 71 | /* Switch the current MM context. */ |
72 | static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) | 72 | static inline void switch_mm(struct mm_struct *old_mm, struct mm_struct *mm, struct task_struct *tsk) |
73 | { | 73 | { |
74 | unsigned long ctx_valid, flags; | 74 | unsigned long ctx_valid, flags; |
diff --git a/arch/sparc/include/asm/processor_64.h b/arch/sparc/include/asm/processor_64.h index cce72ce4c334..4c3f7f01c709 100644 --- a/arch/sparc/include/asm/processor_64.h +++ b/arch/sparc/include/asm/processor_64.h | |||
@@ -18,9 +18,6 @@ | |||
18 | #include <asm/ptrace.h> | 18 | #include <asm/ptrace.h> |
19 | #include <asm/page.h> | 19 | #include <asm/page.h> |
20 | 20 | ||
21 | /* Don't hold the runqueue lock over context switch */ | ||
22 | #define __ARCH_WANT_UNLOCKED_CTXSW | ||
23 | |||
24 | /* The sparc has no problems with write protection */ | 21 | /* The sparc has no problems with write protection */ |
25 | #define wp_works_ok 1 | 22 | #define wp_works_ok 1 |
26 | #define wp_works_ok__is_a_macro /* for versions in ksyms.c */ | 23 | #define wp_works_ok__is_a_macro /* for versions in ksyms.c */ |
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 5276fd4e9d03..d432fb20358e 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile | |||
@@ -74,7 +74,8 @@ obj-y += dma.o | |||
74 | 74 | ||
75 | obj-$(CONFIG_PCIC_PCI) += pcic.o | 75 | obj-$(CONFIG_PCIC_PCI) += pcic.o |
76 | obj-$(CONFIG_LEON_PCI) += leon_pci.o | 76 | obj-$(CONFIG_LEON_PCI) += leon_pci.o |
77 | obj-$(CONFIG_GRPCI2) += leon_pci_grpci2.o | 77 | obj-$(CONFIG_SPARC_GRPCI2)+= leon_pci_grpci2.o |
78 | obj-$(CONFIG_SPARC_GRPCI1)+= leon_pci_grpci1.o | ||
78 | 79 | ||
79 | obj-$(CONFIG_SMP) += trampoline_$(BITS).o smp_$(BITS).o | 80 | obj-$(CONFIG_SMP) += trampoline_$(BITS).o smp_$(BITS).o |
80 | obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o leon_smp.o | 81 | obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o leon_smp.o |
diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c index 68f7e1118e9b..961b87f99e69 100644 --- a/arch/sparc/kernel/asm-offsets.c +++ b/arch/sparc/kernel/asm-offsets.c | |||
@@ -14,6 +14,8 @@ | |||
14 | // #include <linux/mm.h> | 14 | // #include <linux/mm.h> |
15 | #include <linux/kbuild.h> | 15 | #include <linux/kbuild.h> |
16 | 16 | ||
17 | #include <asm/hibernate.h> | ||
18 | |||
17 | #ifdef CONFIG_SPARC32 | 19 | #ifdef CONFIG_SPARC32 |
18 | int sparc32_foo(void) | 20 | int sparc32_foo(void) |
19 | { | 21 | { |
@@ -24,6 +26,19 @@ int sparc32_foo(void) | |||
24 | #else | 26 | #else |
25 | int sparc64_foo(void) | 27 | int sparc64_foo(void) |
26 | { | 28 | { |
29 | #ifdef CONFIG_HIBERNATION | ||
30 | BLANK(); | ||
31 | OFFSET(SC_REG_FP, saved_context, fp); | ||
32 | OFFSET(SC_REG_CWP, saved_context, cwp); | ||
33 | OFFSET(SC_REG_WSTATE, saved_context, wstate); | ||
34 | |||
35 | OFFSET(SC_REG_TICK, saved_context, tick); | ||
36 | OFFSET(SC_REG_PSTATE, saved_context, pstate); | ||
37 | |||
38 | OFFSET(SC_REG_G4, saved_context, g4); | ||
39 | OFFSET(SC_REG_G5, saved_context, g5); | ||
40 | OFFSET(SC_REG_G6, saved_context, g6); | ||
41 | #endif | ||
27 | return 0; | 42 | return 0; |
28 | } | 43 | } |
29 | #endif | 44 | #endif |
diff --git a/arch/sparc/kernel/leon_pci.c b/arch/sparc/kernel/leon_pci.c index 852dc8430528..88aaaa57bb64 100644 --- a/arch/sparc/kernel/leon_pci.c +++ b/arch/sparc/kernel/leon_pci.c | |||
@@ -29,6 +29,8 @@ void leon_pci_init(struct platform_device *ofdev, struct leon_pci_info *info) | |||
29 | pci_add_resource_offset(&resources, &info->io_space, | 29 | pci_add_resource_offset(&resources, &info->io_space, |
30 | info->io_space.start - 0x1000); | 30 | info->io_space.start - 0x1000); |
31 | pci_add_resource(&resources, &info->mem_space); | 31 | pci_add_resource(&resources, &info->mem_space); |
32 | info->busn.flags = IORESOURCE_BUS; | ||
33 | pci_add_resource(&resources, &info->busn); | ||
32 | 34 | ||
33 | root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info, | 35 | root_bus = pci_scan_root_bus(&ofdev->dev, 0, info->ops, info, |
34 | &resources); | 36 | &resources); |
diff --git a/arch/sparc/kernel/leon_pci_grpci1.c b/arch/sparc/kernel/leon_pci_grpci1.c new file mode 100644 index 000000000000..7739a54315e2 --- /dev/null +++ b/arch/sparc/kernel/leon_pci_grpci1.c | |||
@@ -0,0 +1,724 @@ | |||
1 | /* | ||
2 | * leon_pci_grpci1.c: GRPCI1 Host PCI driver | ||
3 | * | ||
4 | * Copyright (C) 2013 Aeroflex Gaisler AB | ||
5 | * | ||
6 | * This GRPCI1 driver does not support PCI interrupts taken from | ||
7 | * GPIO pins. Interrupt generation at PCI parity and system error | ||
8 | * detection is by default turned off since some GRPCI1 cores does | ||
9 | * not support detection. It can be turned on from the bootloader | ||
10 | * using the all_pci_errors property. | ||
11 | * | ||
12 | * Contributors: Daniel Hellstrom <daniel@gaisler.com> | ||
13 | */ | ||
14 | |||
15 | #include <linux/of_device.h> | ||
16 | #include <linux/export.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/of_irq.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/pci.h> | ||
21 | |||
22 | #include <asm/leon_pci.h> | ||
23 | #include <asm/sections.h> | ||
24 | #include <asm/vaddrs.h> | ||
25 | #include <asm/leon.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | #include "irq.h" | ||
29 | |||
30 | /* Enable/Disable Debugging Configuration Space Access */ | ||
31 | #undef GRPCI1_DEBUG_CFGACCESS | ||
32 | |||
33 | /* | ||
34 | * GRPCI1 APB Register MAP | ||
35 | */ | ||
36 | struct grpci1_regs { | ||
37 | unsigned int cfg_stat; /* 0x00 Configuration / Status */ | ||
38 | unsigned int bar0; /* 0x04 BAR0 (RO) */ | ||
39 | unsigned int page0; /* 0x08 PAGE0 (RO) */ | ||
40 | unsigned int bar1; /* 0x0C BAR1 (RO) */ | ||
41 | unsigned int page1; /* 0x10 PAGE1 */ | ||
42 | unsigned int iomap; /* 0x14 IO Map */ | ||
43 | unsigned int stat_cmd; /* 0x18 PCI Status & Command (RO) */ | ||
44 | unsigned int irq; /* 0x1C Interrupt register */ | ||
45 | }; | ||
46 | |||
47 | #define REGLOAD(a) (be32_to_cpu(__raw_readl(&(a)))) | ||
48 | #define REGSTORE(a, v) (__raw_writel(cpu_to_be32(v), &(a))) | ||
49 | |||
50 | #define PAGE0_BTEN_BIT 0 | ||
51 | #define PAGE0_BTEN (1 << PAGE0_BTEN_BIT) | ||
52 | |||
53 | #define CFGSTAT_HOST_BIT 13 | ||
54 | #define CFGSTAT_CTO_BIT 8 | ||
55 | #define CFGSTAT_HOST (1 << CFGSTAT_HOST_BIT) | ||
56 | #define CFGSTAT_CTO (1 << CFGSTAT_CTO_BIT) | ||
57 | |||
58 | #define IRQ_DPE (1 << 9) | ||
59 | #define IRQ_SSE (1 << 8) | ||
60 | #define IRQ_RMA (1 << 7) | ||
61 | #define IRQ_RTA (1 << 6) | ||
62 | #define IRQ_STA (1 << 5) | ||
63 | #define IRQ_DPED (1 << 4) | ||
64 | #define IRQ_INTD (1 << 3) | ||
65 | #define IRQ_INTC (1 << 2) | ||
66 | #define IRQ_INTB (1 << 1) | ||
67 | #define IRQ_INTA (1 << 0) | ||
68 | #define IRQ_DEF_ERRORS (IRQ_RMA | IRQ_RTA | IRQ_STA) | ||
69 | #define IRQ_ALL_ERRORS (IRQ_DPED | IRQ_DEF_ERRORS | IRQ_SSE | IRQ_DPE) | ||
70 | #define IRQ_INTX (IRQ_INTA | IRQ_INTB | IRQ_INTC | IRQ_INTD) | ||
71 | #define IRQ_MASK_BIT 16 | ||
72 | |||
73 | #define DEF_PCI_ERRORS (PCI_STATUS_SIG_TARGET_ABORT | \ | ||
74 | PCI_STATUS_REC_TARGET_ABORT | \ | ||
75 | PCI_STATUS_REC_MASTER_ABORT) | ||
76 | #define ALL_PCI_ERRORS (PCI_STATUS_PARITY | PCI_STATUS_DETECTED_PARITY | \ | ||
77 | PCI_STATUS_SIG_SYSTEM_ERROR | DEF_PCI_ERRORS) | ||
78 | |||
79 | #define TGT 256 | ||
80 | |||
81 | struct grpci1_priv { | ||
82 | struct leon_pci_info info; /* must be on top of this structure */ | ||
83 | struct grpci1_regs *regs; /* GRPCI register map */ | ||
84 | struct device *dev; | ||
85 | int pci_err_mask; /* STATUS register error mask */ | ||
86 | int irq; /* LEON irqctrl GRPCI IRQ */ | ||
87 | unsigned char irq_map[4]; /* GRPCI nexus PCI INTX# IRQs */ | ||
88 | unsigned int irq_err; /* GRPCI nexus Virt Error IRQ */ | ||
89 | |||
90 | /* AHB PCI Windows */ | ||
91 | unsigned long pci_area; /* MEMORY */ | ||
92 | unsigned long pci_area_end; | ||
93 | unsigned long pci_io; /* I/O */ | ||
94 | unsigned long pci_conf; /* CONFIGURATION */ | ||
95 | unsigned long pci_conf_end; | ||
96 | unsigned long pci_io_va; | ||
97 | }; | ||
98 | |||
99 | static struct grpci1_priv *grpci1priv; | ||
100 | |||
101 | static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, | ||
102 | unsigned int devfn, int where, u32 val); | ||
103 | |||
104 | int grpci1_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | ||
105 | { | ||
106 | struct grpci1_priv *priv = dev->bus->sysdata; | ||
107 | int irq_group; | ||
108 | |||
109 | /* Use default IRQ decoding on PCI BUS0 according slot numbering */ | ||
110 | irq_group = slot & 0x3; | ||
111 | pin = ((pin - 1) + irq_group) & 0x3; | ||
112 | |||
113 | return priv->irq_map[pin]; | ||
114 | } | ||
115 | |||
116 | static int grpci1_cfg_r32(struct grpci1_priv *priv, unsigned int bus, | ||
117 | unsigned int devfn, int where, u32 *val) | ||
118 | { | ||
119 | u32 *pci_conf, tmp, cfg; | ||
120 | |||
121 | if (where & 0x3) | ||
122 | return -EINVAL; | ||
123 | |||
124 | if (bus == 0) { | ||
125 | devfn += (0x8 * 6); /* start at AD16=Device0 */ | ||
126 | } else if (bus == TGT) { | ||
127 | bus = 0; | ||
128 | devfn = 0; /* special case: bridge controller itself */ | ||
129 | } | ||
130 | |||
131 | /* Select bus */ | ||
132 | cfg = REGLOAD(priv->regs->cfg_stat); | ||
133 | REGSTORE(priv->regs->cfg_stat, (cfg & ~(0xf << 23)) | (bus << 23)); | ||
134 | |||
135 | /* do read access */ | ||
136 | pci_conf = (u32 *) (priv->pci_conf | (devfn << 8) | (where & 0xfc)); | ||
137 | tmp = LEON3_BYPASS_LOAD_PA(pci_conf); | ||
138 | |||
139 | /* check if master abort was received */ | ||
140 | if (REGLOAD(priv->regs->cfg_stat) & CFGSTAT_CTO) { | ||
141 | *val = 0xffffffff; | ||
142 | /* Clear Master abort bit in PCI cfg space (is set) */ | ||
143 | tmp = REGLOAD(priv->regs->stat_cmd); | ||
144 | grpci1_cfg_w32(priv, TGT, 0, PCI_COMMAND, tmp); | ||
145 | } else { | ||
146 | /* Bus always little endian (unaffected by byte-swapping) */ | ||
147 | *val = flip_dword(tmp); | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int grpci1_cfg_r16(struct grpci1_priv *priv, unsigned int bus, | ||
154 | unsigned int devfn, int where, u32 *val) | ||
155 | { | ||
156 | u32 v; | ||
157 | int ret; | ||
158 | |||
159 | if (where & 0x1) | ||
160 | return -EINVAL; | ||
161 | ret = grpci1_cfg_r32(priv, bus, devfn, where & ~0x3, &v); | ||
162 | *val = 0xffff & (v >> (8 * (where & 0x3))); | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | static int grpci1_cfg_r8(struct grpci1_priv *priv, unsigned int bus, | ||
167 | unsigned int devfn, int where, u32 *val) | ||
168 | { | ||
169 | u32 v; | ||
170 | int ret; | ||
171 | |||
172 | ret = grpci1_cfg_r32(priv, bus, devfn, where & ~0x3, &v); | ||
173 | *val = 0xff & (v >> (8 * (where & 3))); | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | static int grpci1_cfg_w32(struct grpci1_priv *priv, unsigned int bus, | ||
179 | unsigned int devfn, int where, u32 val) | ||
180 | { | ||
181 | unsigned int *pci_conf; | ||
182 | u32 cfg; | ||
183 | |||
184 | if (where & 0x3) | ||
185 | return -EINVAL; | ||
186 | |||
187 | if (bus == 0) { | ||
188 | devfn += (0x8 * 6); /* start at AD16=Device0 */ | ||
189 | } else if (bus == TGT) { | ||
190 | bus = 0; | ||
191 | devfn = 0; /* special case: bridge controller itself */ | ||
192 | } | ||
193 | |||
194 | /* Select bus */ | ||
195 | cfg = REGLOAD(priv->regs->cfg_stat); | ||
196 | REGSTORE(priv->regs->cfg_stat, (cfg & ~(0xf << 23)) | (bus << 23)); | ||
197 | |||
198 | pci_conf = (unsigned int *) (priv->pci_conf | | ||
199 | (devfn << 8) | (where & 0xfc)); | ||
200 | LEON3_BYPASS_STORE_PA(pci_conf, flip_dword(val)); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int grpci1_cfg_w16(struct grpci1_priv *priv, unsigned int bus, | ||
206 | unsigned int devfn, int where, u32 val) | ||
207 | { | ||
208 | int ret; | ||
209 | u32 v; | ||
210 | |||
211 | if (where & 0x1) | ||
212 | return -EINVAL; | ||
213 | ret = grpci1_cfg_r32(priv, bus, devfn, where&~3, &v); | ||
214 | if (ret) | ||
215 | return ret; | ||
216 | v = (v & ~(0xffff << (8 * (where & 0x3)))) | | ||
217 | ((0xffff & val) << (8 * (where & 0x3))); | ||
218 | return grpci1_cfg_w32(priv, bus, devfn, where & ~0x3, v); | ||
219 | } | ||
220 | |||
221 | static int grpci1_cfg_w8(struct grpci1_priv *priv, unsigned int bus, | ||
222 | unsigned int devfn, int where, u32 val) | ||
223 | { | ||
224 | int ret; | ||
225 | u32 v; | ||
226 | |||
227 | ret = grpci1_cfg_r32(priv, bus, devfn, where & ~0x3, &v); | ||
228 | if (ret != 0) | ||
229 | return ret; | ||
230 | v = (v & ~(0xff << (8 * (where & 0x3)))) | | ||
231 | ((0xff & val) << (8 * (where & 0x3))); | ||
232 | return grpci1_cfg_w32(priv, bus, devfn, where & ~0x3, v); | ||
233 | } | ||
234 | |||
235 | /* Read from Configuration Space. When entering here the PCI layer has taken | ||
236 | * the pci_lock spinlock and IRQ is off. | ||
237 | */ | ||
238 | static int grpci1_read_config(struct pci_bus *bus, unsigned int devfn, | ||
239 | int where, int size, u32 *val) | ||
240 | { | ||
241 | struct grpci1_priv *priv = grpci1priv; | ||
242 | unsigned int busno = bus->number; | ||
243 | int ret; | ||
244 | |||
245 | if (PCI_SLOT(devfn) > 15 || busno > 15) { | ||
246 | *val = ~0; | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | switch (size) { | ||
251 | case 1: | ||
252 | ret = grpci1_cfg_r8(priv, busno, devfn, where, val); | ||
253 | break; | ||
254 | case 2: | ||
255 | ret = grpci1_cfg_r16(priv, busno, devfn, where, val); | ||
256 | break; | ||
257 | case 4: | ||
258 | ret = grpci1_cfg_r32(priv, busno, devfn, where, val); | ||
259 | break; | ||
260 | default: | ||
261 | ret = -EINVAL; | ||
262 | break; | ||
263 | } | ||
264 | |||
265 | #ifdef GRPCI1_DEBUG_CFGACCESS | ||
266 | printk(KERN_INFO | ||
267 | "grpci1_read_config: [%02x:%02x:%x] ofs=%d val=%x size=%d\n", | ||
268 | busno, PCI_SLOT(devfn), PCI_FUNC(devfn), where, *val, size); | ||
269 | #endif | ||
270 | |||
271 | return ret; | ||
272 | } | ||
273 | |||
274 | /* Write to Configuration Space. When entering here the PCI layer has taken | ||
275 | * the pci_lock spinlock and IRQ is off. | ||
276 | */ | ||
277 | static int grpci1_write_config(struct pci_bus *bus, unsigned int devfn, | ||
278 | int where, int size, u32 val) | ||
279 | { | ||
280 | struct grpci1_priv *priv = grpci1priv; | ||
281 | unsigned int busno = bus->number; | ||
282 | |||
283 | if (PCI_SLOT(devfn) > 15 || busno > 15) | ||
284 | return 0; | ||
285 | |||
286 | #ifdef GRPCI1_DEBUG_CFGACCESS | ||
287 | printk(KERN_INFO | ||
288 | "grpci1_write_config: [%02x:%02x:%x] ofs=%d size=%d val=%x\n", | ||
289 | busno, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); | ||
290 | #endif | ||
291 | |||
292 | switch (size) { | ||
293 | default: | ||
294 | return -EINVAL; | ||
295 | case 1: | ||
296 | return grpci1_cfg_w8(priv, busno, devfn, where, val); | ||
297 | case 2: | ||
298 | return grpci1_cfg_w16(priv, busno, devfn, where, val); | ||
299 | case 4: | ||
300 | return grpci1_cfg_w32(priv, busno, devfn, where, val); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | static struct pci_ops grpci1_ops = { | ||
305 | .read = grpci1_read_config, | ||
306 | .write = grpci1_write_config, | ||
307 | }; | ||
308 | |||
309 | /* GENIRQ IRQ chip implementation for grpci1 irqmode=0..2. In configuration | ||
310 | * 3 where all PCI Interrupts has a separate IRQ on the system IRQ controller | ||
311 | * this is not needed and the standard IRQ controller can be used. | ||
312 | */ | ||
313 | |||
314 | static void grpci1_mask_irq(struct irq_data *data) | ||
315 | { | ||
316 | u32 irqidx; | ||
317 | struct grpci1_priv *priv = grpci1priv; | ||
318 | |||
319 | irqidx = (u32)data->chip_data - 1; | ||
320 | if (irqidx > 3) /* only mask PCI interrupts here */ | ||
321 | return; | ||
322 | irqidx += IRQ_MASK_BIT; | ||
323 | |||
324 | REGSTORE(priv->regs->irq, REGLOAD(priv->regs->irq) & ~(1 << irqidx)); | ||
325 | } | ||
326 | |||
327 | static void grpci1_unmask_irq(struct irq_data *data) | ||
328 | { | ||
329 | u32 irqidx; | ||
330 | struct grpci1_priv *priv = grpci1priv; | ||
331 | |||
332 | irqidx = (u32)data->chip_data - 1; | ||
333 | if (irqidx > 3) /* only unmask PCI interrupts here */ | ||
334 | return; | ||
335 | irqidx += IRQ_MASK_BIT; | ||
336 | |||
337 | REGSTORE(priv->regs->irq, REGLOAD(priv->regs->irq) | (1 << irqidx)); | ||
338 | } | ||
339 | |||
340 | static unsigned int grpci1_startup_irq(struct irq_data *data) | ||
341 | { | ||
342 | grpci1_unmask_irq(data); | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static void grpci1_shutdown_irq(struct irq_data *data) | ||
347 | { | ||
348 | grpci1_mask_irq(data); | ||
349 | } | ||
350 | |||
351 | static struct irq_chip grpci1_irq = { | ||
352 | .name = "grpci1", | ||
353 | .irq_startup = grpci1_startup_irq, | ||
354 | .irq_shutdown = grpci1_shutdown_irq, | ||
355 | .irq_mask = grpci1_mask_irq, | ||
356 | .irq_unmask = grpci1_unmask_irq, | ||
357 | }; | ||
358 | |||
359 | /* Handle one or multiple IRQs from the PCI core */ | ||
360 | static void grpci1_pci_flow_irq(unsigned int irq, struct irq_desc *desc) | ||
361 | { | ||
362 | struct grpci1_priv *priv = grpci1priv; | ||
363 | int i, ack = 0; | ||
364 | unsigned int irqreg; | ||
365 | |||
366 | irqreg = REGLOAD(priv->regs->irq); | ||
367 | irqreg = (irqreg >> IRQ_MASK_BIT) & irqreg; | ||
368 | |||
369 | /* Error Interrupt? */ | ||
370 | if (irqreg & IRQ_ALL_ERRORS) { | ||
371 | generic_handle_irq(priv->irq_err); | ||
372 | ack = 1; | ||
373 | } | ||
374 | |||
375 | /* PCI Interrupt? */ | ||
376 | if (irqreg & IRQ_INTX) { | ||
377 | /* Call respective PCI Interrupt handler */ | ||
378 | for (i = 0; i < 4; i++) { | ||
379 | if (irqreg & (1 << i)) | ||
380 | generic_handle_irq(priv->irq_map[i]); | ||
381 | } | ||
382 | ack = 1; | ||
383 | } | ||
384 | |||
385 | /* | ||
386 | * Call "first level" IRQ chip end-of-irq handler. It will ACK LEON IRQ | ||
387 | * Controller, this must be done after IRQ sources have been handled to | ||
388 | * avoid double IRQ generation | ||
389 | */ | ||
390 | if (ack) | ||
391 | desc->irq_data.chip->irq_eoi(&desc->irq_data); | ||
392 | } | ||
393 | |||
394 | /* Create a virtual IRQ */ | ||
395 | static unsigned int grpci1_build_device_irq(unsigned int irq) | ||
396 | { | ||
397 | unsigned int virq = 0, pil; | ||
398 | |||
399 | pil = 1 << 8; | ||
400 | virq = irq_alloc(irq, pil); | ||
401 | if (virq == 0) | ||
402 | goto out; | ||
403 | |||
404 | irq_set_chip_and_handler_name(virq, &grpci1_irq, handle_simple_irq, | ||
405 | "pcilvl"); | ||
406 | irq_set_chip_data(virq, (void *)irq); | ||
407 | |||
408 | out: | ||
409 | return virq; | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | * Initialize mappings AMBA<->PCI, clear IRQ state, setup PCI interface | ||
414 | * | ||
415 | * Target BARs: | ||
416 | * BAR0: unused in this implementation | ||
417 | * BAR1: peripheral DMA to host's memory (size at least 256MByte) | ||
418 | * BAR2..BAR5: not implemented in hardware | ||
419 | */ | ||
420 | void grpci1_hw_init(struct grpci1_priv *priv) | ||
421 | { | ||
422 | u32 ahbadr, bar_sz, data, pciadr; | ||
423 | struct grpci1_regs *regs = priv->regs; | ||
424 | |||
425 | /* set 1:1 mapping between AHB -> PCI memory space */ | ||
426 | REGSTORE(regs->cfg_stat, priv->pci_area & 0xf0000000); | ||
427 | |||
428 | /* map PCI accesses to target BAR1 to Linux kernel memory 1:1 */ | ||
429 | ahbadr = 0xf0000000 & (u32)__pa(PAGE_ALIGN((unsigned long) &_end)); | ||
430 | REGSTORE(regs->page1, ahbadr); | ||
431 | |||
432 | /* translate I/O accesses to 0, I/O Space always @ PCI low 64Kbytes */ | ||
433 | REGSTORE(regs->iomap, REGLOAD(regs->iomap) & 0x0000ffff); | ||
434 | |||
435 | /* disable and clear pending interrupts */ | ||
436 | REGSTORE(regs->irq, 0); | ||
437 | |||
438 | /* Setup BAR0 outside access range so that it does not conflict with | ||
439 | * peripheral DMA. There is no need to set up the PAGE0 register. | ||
440 | */ | ||
441 | grpci1_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_0, 0xffffffff); | ||
442 | grpci1_cfg_r32(priv, TGT, 0, PCI_BASE_ADDRESS_0, &bar_sz); | ||
443 | bar_sz = ~bar_sz + 1; | ||
444 | pciadr = priv->pci_area - bar_sz; | ||
445 | grpci1_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_0, pciadr); | ||
446 | |||
447 | /* | ||
448 | * Setup the Host's PCI Target BAR1 for other peripherals to access, | ||
449 | * and do DMA to the host's memory. | ||
450 | */ | ||
451 | grpci1_cfg_w32(priv, TGT, 0, PCI_BASE_ADDRESS_1, ahbadr); | ||
452 | |||
453 | /* | ||
454 | * Setup Latency Timer and cache line size. Default cache line | ||
455 | * size will result in poor performance (256 word fetches), 0xff | ||
456 | * will set it according to the max size of the PCI FIFO. | ||
457 | */ | ||
458 | grpci1_cfg_w8(priv, TGT, 0, PCI_CACHE_LINE_SIZE, 0xff); | ||
459 | grpci1_cfg_w8(priv, TGT, 0, PCI_LATENCY_TIMER, 0x40); | ||
460 | |||
461 | /* set as bus master, enable pci memory responses, clear status bits */ | ||
462 | grpci1_cfg_r32(priv, TGT, 0, PCI_COMMAND, &data); | ||
463 | data |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); | ||
464 | grpci1_cfg_w32(priv, TGT, 0, PCI_COMMAND, data); | ||
465 | } | ||
466 | |||
467 | static irqreturn_t grpci1_jump_interrupt(int irq, void *arg) | ||
468 | { | ||
469 | struct grpci1_priv *priv = arg; | ||
470 | dev_err(priv->dev, "Jump IRQ happened\n"); | ||
471 | return IRQ_NONE; | ||
472 | } | ||
473 | |||
474 | /* Handle GRPCI1 Error Interrupt */ | ||
475 | static irqreturn_t grpci1_err_interrupt(int irq, void *arg) | ||
476 | { | ||
477 | struct grpci1_priv *priv = arg; | ||
478 | u32 status; | ||
479 | |||
480 | grpci1_cfg_r16(priv, TGT, 0, PCI_STATUS, &status); | ||
481 | status &= priv->pci_err_mask; | ||
482 | |||
483 | if (status == 0) | ||
484 | return IRQ_NONE; | ||
485 | |||
486 | if (status & PCI_STATUS_PARITY) | ||
487 | dev_err(priv->dev, "Data Parity Error\n"); | ||
488 | |||
489 | if (status & PCI_STATUS_SIG_TARGET_ABORT) | ||
490 | dev_err(priv->dev, "Signalled Target Abort\n"); | ||
491 | |||
492 | if (status & PCI_STATUS_REC_TARGET_ABORT) | ||
493 | dev_err(priv->dev, "Received Target Abort\n"); | ||
494 | |||
495 | if (status & PCI_STATUS_REC_MASTER_ABORT) | ||
496 | dev_err(priv->dev, "Received Master Abort\n"); | ||
497 | |||
498 | if (status & PCI_STATUS_SIG_SYSTEM_ERROR) | ||
499 | dev_err(priv->dev, "Signalled System Error\n"); | ||
500 | |||
501 | if (status & PCI_STATUS_DETECTED_PARITY) | ||
502 | dev_err(priv->dev, "Parity Error\n"); | ||
503 | |||
504 | /* Clear handled INT TYPE IRQs */ | ||
505 | grpci1_cfg_w16(priv, TGT, 0, PCI_STATUS, status); | ||
506 | |||
507 | return IRQ_HANDLED; | ||
508 | } | ||
509 | |||
510 | static int grpci1_of_probe(struct platform_device *ofdev) | ||
511 | { | ||
512 | struct grpci1_regs *regs; | ||
513 | struct grpci1_priv *priv; | ||
514 | int err, len; | ||
515 | const int *tmp; | ||
516 | u32 cfg, size, err_mask; | ||
517 | struct resource *res; | ||
518 | |||
519 | if (grpci1priv) { | ||
520 | dev_err(&ofdev->dev, "only one GRPCI1 supported\n"); | ||
521 | return -ENODEV; | ||
522 | } | ||
523 | |||
524 | if (ofdev->num_resources < 3) { | ||
525 | dev_err(&ofdev->dev, "not enough APB/AHB resources\n"); | ||
526 | return -EIO; | ||
527 | } | ||
528 | |||
529 | priv = devm_kzalloc(&ofdev->dev, sizeof(*priv), GFP_KERNEL); | ||
530 | if (!priv) { | ||
531 | dev_err(&ofdev->dev, "memory allocation failed\n"); | ||
532 | return -ENOMEM; | ||
533 | } | ||
534 | platform_set_drvdata(ofdev, priv); | ||
535 | priv->dev = &ofdev->dev; | ||
536 | |||
537 | /* find device register base address */ | ||
538 | res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); | ||
539 | regs = devm_request_and_ioremap(&ofdev->dev, res); | ||
540 | if (!regs) { | ||
541 | dev_err(&ofdev->dev, "io-regs mapping failed\n"); | ||
542 | return -EADDRNOTAVAIL; | ||
543 | } | ||
544 | |||
545 | /* | ||
546 | * check that we're in Host Slot and that we can act as a Host Bridge | ||
547 | * and not only as target/peripheral. | ||
548 | */ | ||
549 | cfg = REGLOAD(regs->cfg_stat); | ||
550 | if ((cfg & CFGSTAT_HOST) == 0) { | ||
551 | dev_err(&ofdev->dev, "not in host system slot\n"); | ||
552 | return -EIO; | ||
553 | } | ||
554 | |||
555 | /* check that BAR1 support 256 MByte so that we can map kernel space */ | ||
556 | REGSTORE(regs->page1, 0xffffffff); | ||
557 | size = ~REGLOAD(regs->page1) + 1; | ||
558 | if (size < 0x10000000) { | ||
559 | dev_err(&ofdev->dev, "BAR1 must be at least 256MByte\n"); | ||
560 | return -EIO; | ||
561 | } | ||
562 | |||
563 | /* hardware must support little-endian PCI (byte-twisting) */ | ||
564 | if ((REGLOAD(regs->page0) & PAGE0_BTEN) == 0) { | ||
565 | dev_err(&ofdev->dev, "byte-twisting is required\n"); | ||
566 | return -EIO; | ||
567 | } | ||
568 | |||
569 | priv->regs = regs; | ||
570 | priv->irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); | ||
571 | dev_info(&ofdev->dev, "host found at 0x%p, irq%d\n", regs, priv->irq); | ||
572 | |||
573 | /* Find PCI Memory, I/O and Configuration Space Windows */ | ||
574 | priv->pci_area = ofdev->resource[1].start; | ||
575 | priv->pci_area_end = ofdev->resource[1].end+1; | ||
576 | priv->pci_io = ofdev->resource[2].start; | ||
577 | priv->pci_conf = ofdev->resource[2].start + 0x10000; | ||
578 | priv->pci_conf_end = priv->pci_conf + 0x10000; | ||
579 | priv->pci_io_va = (unsigned long)ioremap(priv->pci_io, 0x10000); | ||
580 | if (!priv->pci_io_va) { | ||
581 | dev_err(&ofdev->dev, "unable to map PCI I/O area\n"); | ||
582 | return -EIO; | ||
583 | } | ||
584 | |||
585 | printk(KERN_INFO | ||
586 | "GRPCI1: MEMORY SPACE [0x%08lx - 0x%08lx]\n" | ||
587 | " I/O SPACE [0x%08lx - 0x%08lx]\n" | ||
588 | " CONFIG SPACE [0x%08lx - 0x%08lx]\n", | ||
589 | priv->pci_area, priv->pci_area_end-1, | ||
590 | priv->pci_io, priv->pci_conf-1, | ||
591 | priv->pci_conf, priv->pci_conf_end-1); | ||
592 | |||
593 | /* | ||
594 | * I/O Space resources in I/O Window mapped into Virtual Adr Space | ||
595 | * We never use low 4KB because some devices seem have problems using | ||
596 | * address 0. | ||
597 | */ | ||
598 | priv->info.io_space.name = "GRPCI1 PCI I/O Space"; | ||
599 | priv->info.io_space.start = priv->pci_io_va + 0x1000; | ||
600 | priv->info.io_space.end = priv->pci_io_va + 0x10000 - 1; | ||
601 | priv->info.io_space.flags = IORESOURCE_IO; | ||
602 | |||
603 | /* | ||
604 | * grpci1 has no prefetchable memory, map everything as | ||
605 | * non-prefetchable memory | ||
606 | */ | ||
607 | priv->info.mem_space.name = "GRPCI1 PCI MEM Space"; | ||
608 | priv->info.mem_space.start = priv->pci_area; | ||
609 | priv->info.mem_space.end = priv->pci_area_end - 1; | ||
610 | priv->info.mem_space.flags = IORESOURCE_MEM; | ||
611 | |||
612 | if (request_resource(&iomem_resource, &priv->info.mem_space) < 0) { | ||
613 | dev_err(&ofdev->dev, "unable to request PCI memory area\n"); | ||
614 | err = -ENOMEM; | ||
615 | goto err1; | ||
616 | } | ||
617 | |||
618 | if (request_resource(&ioport_resource, &priv->info.io_space) < 0) { | ||
619 | dev_err(&ofdev->dev, "unable to request PCI I/O area\n"); | ||
620 | err = -ENOMEM; | ||
621 | goto err2; | ||
622 | } | ||
623 | |||
624 | /* setup maximum supported PCI buses */ | ||
625 | priv->info.busn.name = "GRPCI1 busn"; | ||
626 | priv->info.busn.start = 0; | ||
627 | priv->info.busn.end = 15; | ||
628 | |||
629 | grpci1priv = priv; | ||
630 | |||
631 | /* Initialize hardware */ | ||
632 | grpci1_hw_init(priv); | ||
633 | |||
634 | /* | ||
635 | * Get PCI Interrupt to System IRQ mapping and setup IRQ handling | ||
636 | * Error IRQ. All PCI and PCI-Error interrupts are shared using the | ||
637 | * same system IRQ. | ||
638 | */ | ||
639 | leon_update_virq_handling(priv->irq, grpci1_pci_flow_irq, "pcilvl", 0); | ||
640 | |||
641 | priv->irq_map[0] = grpci1_build_device_irq(1); | ||
642 | priv->irq_map[1] = grpci1_build_device_irq(2); | ||
643 | priv->irq_map[2] = grpci1_build_device_irq(3); | ||
644 | priv->irq_map[3] = grpci1_build_device_irq(4); | ||
645 | priv->irq_err = grpci1_build_device_irq(5); | ||
646 | |||
647 | printk(KERN_INFO " PCI INTA..D#: IRQ%d, IRQ%d, IRQ%d, IRQ%d\n", | ||
648 | priv->irq_map[0], priv->irq_map[1], priv->irq_map[2], | ||
649 | priv->irq_map[3]); | ||
650 | |||
651 | /* Enable IRQs on LEON IRQ controller */ | ||
652 | err = devm_request_irq(&ofdev->dev, priv->irq, grpci1_jump_interrupt, 0, | ||
653 | "GRPCI1_JUMP", priv); | ||
654 | if (err) { | ||
655 | dev_err(&ofdev->dev, "ERR IRQ request failed: %d\n", err); | ||
656 | goto err3; | ||
657 | } | ||
658 | |||
659 | /* Setup IRQ handler for access errors */ | ||
660 | err = devm_request_irq(&ofdev->dev, priv->irq_err, | ||
661 | grpci1_err_interrupt, IRQF_SHARED, "GRPCI1_ERR", | ||
662 | priv); | ||
663 | if (err) { | ||
664 | dev_err(&ofdev->dev, "ERR VIRQ request failed: %d\n", err); | ||
665 | goto err3; | ||
666 | } | ||
667 | |||
668 | tmp = of_get_property(ofdev->dev.of_node, "all_pci_errors", &len); | ||
669 | if (tmp && (len == 4)) { | ||
670 | priv->pci_err_mask = ALL_PCI_ERRORS; | ||
671 | err_mask = IRQ_ALL_ERRORS << IRQ_MASK_BIT; | ||
672 | } else { | ||
673 | priv->pci_err_mask = DEF_PCI_ERRORS; | ||
674 | err_mask = IRQ_DEF_ERRORS << IRQ_MASK_BIT; | ||
675 | } | ||
676 | |||
677 | /* | ||
678 | * Enable Error Interrupts. PCI interrupts are unmasked once request_irq | ||
679 | * is called by the PCI Device drivers | ||
680 | */ | ||
681 | REGSTORE(regs->irq, err_mask); | ||
682 | |||
683 | /* Init common layer and scan buses */ | ||
684 | priv->info.ops = &grpci1_ops; | ||
685 | priv->info.map_irq = grpci1_map_irq; | ||
686 | leon_pci_init(ofdev, &priv->info); | ||
687 | |||
688 | return 0; | ||
689 | |||
690 | err3: | ||
691 | release_resource(&priv->info.io_space); | ||
692 | err2: | ||
693 | release_resource(&priv->info.mem_space); | ||
694 | err1: | ||
695 | iounmap((void *)priv->pci_io_va); | ||
696 | grpci1priv = NULL; | ||
697 | return err; | ||
698 | } | ||
699 | |||
700 | static struct of_device_id grpci1_of_match[] = { | ||
701 | { | ||
702 | .name = "GAISLER_PCIFBRG", | ||
703 | }, | ||
704 | { | ||
705 | .name = "01_014", | ||
706 | }, | ||
707 | {}, | ||
708 | }; | ||
709 | |||
710 | static struct platform_driver grpci1_of_driver = { | ||
711 | .driver = { | ||
712 | .name = "grpci1", | ||
713 | .owner = THIS_MODULE, | ||
714 | .of_match_table = grpci1_of_match, | ||
715 | }, | ||
716 | .probe = grpci1_of_probe, | ||
717 | }; | ||
718 | |||
719 | static int __init grpci1_init(void) | ||
720 | { | ||
721 | return platform_driver_register(&grpci1_of_driver); | ||
722 | } | ||
723 | |||
724 | subsys_initcall(grpci1_init); | ||
diff --git a/arch/sparc/kernel/leon_pci_grpci2.c b/arch/sparc/kernel/leon_pci_grpci2.c index 4d1487138d26..5f0402aab7fb 100644 --- a/arch/sparc/kernel/leon_pci_grpci2.c +++ b/arch/sparc/kernel/leon_pci_grpci2.c | |||
@@ -799,6 +799,11 @@ static int grpci2_of_probe(struct platform_device *ofdev) | |||
799 | if (request_resource(&ioport_resource, &priv->info.io_space) < 0) | 799 | if (request_resource(&ioport_resource, &priv->info.io_space) < 0) |
800 | goto err4; | 800 | goto err4; |
801 | 801 | ||
802 | /* setup maximum supported PCI buses */ | ||
803 | priv->info.busn.name = "GRPCI2 busn"; | ||
804 | priv->info.busn.start = 0; | ||
805 | priv->info.busn.end = 255; | ||
806 | |||
802 | grpci2_hw_init(priv); | 807 | grpci2_hw_init(priv); |
803 | 808 | ||
804 | /* | 809 | /* |
diff --git a/arch/sparc/kernel/leon_pmc.c b/arch/sparc/kernel/leon_pmc.c index 708bca435219..bdf53d9a8d46 100644 --- a/arch/sparc/kernel/leon_pmc.c +++ b/arch/sparc/kernel/leon_pmc.c | |||
@@ -48,7 +48,7 @@ void pmc_leon_idle_fixup(void) | |||
48 | */ | 48 | */ |
49 | register unsigned int address = (unsigned int)leon3_irqctrl_regs; | 49 | register unsigned int address = (unsigned int)leon3_irqctrl_regs; |
50 | __asm__ __volatile__ ( | 50 | __asm__ __volatile__ ( |
51 | "mov %%g0, %%asr19\n" | 51 | "wr %%g0, %%asr19\n" |
52 | "lda [%0] %1, %%g0\n" | 52 | "lda [%0] %1, %%g0\n" |
53 | : | 53 | : |
54 | : "r"(address), "i"(ASI_LEON_BYPASS)); | 54 | : "r"(address), "i"(ASI_LEON_BYPASS)); |
@@ -61,7 +61,7 @@ void pmc_leon_idle_fixup(void) | |||
61 | void pmc_leon_idle(void) | 61 | void pmc_leon_idle(void) |
62 | { | 62 | { |
63 | /* For systems without power-down, this will be no-op */ | 63 | /* For systems without power-down, this will be no-op */ |
64 | __asm__ __volatile__ ("mov %g0, %asr19\n\t"); | 64 | __asm__ __volatile__ ("wr %g0, %asr19\n\t"); |
65 | } | 65 | } |
66 | 66 | ||
67 | /* Install LEON Power Down function */ | 67 | /* Install LEON Power Down function */ |
diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 6ac99d64a13c..cf72a8a5b3aa 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c | |||
@@ -681,10 +681,9 @@ void get_new_mmu_context(struct mm_struct *mm) | |||
681 | { | 681 | { |
682 | unsigned long ctx, new_ctx; | 682 | unsigned long ctx, new_ctx; |
683 | unsigned long orig_pgsz_bits; | 683 | unsigned long orig_pgsz_bits; |
684 | unsigned long flags; | ||
685 | int new_version; | 684 | int new_version; |
686 | 685 | ||
687 | spin_lock_irqsave(&ctx_alloc_lock, flags); | 686 | spin_lock(&ctx_alloc_lock); |
688 | orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK); | 687 | orig_pgsz_bits = (mm->context.sparc64_ctx_val & CTX_PGSZ_MASK); |
689 | ctx = (tlb_context_cache + 1) & CTX_NR_MASK; | 688 | ctx = (tlb_context_cache + 1) & CTX_NR_MASK; |
690 | new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx); | 689 | new_ctx = find_next_zero_bit(mmu_context_bmap, 1 << CTX_NR_BITS, ctx); |
@@ -720,7 +719,7 @@ void get_new_mmu_context(struct mm_struct *mm) | |||
720 | out: | 719 | out: |
721 | tlb_context_cache = new_ctx; | 720 | tlb_context_cache = new_ctx; |
722 | mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits; | 721 | mm->context.sparc64_ctx_val = new_ctx | orig_pgsz_bits; |
723 | spin_unlock_irqrestore(&ctx_alloc_lock, flags); | 722 | spin_unlock(&ctx_alloc_lock); |
724 | 723 | ||
725 | if (unlikely(new_version)) | 724 | if (unlikely(new_version)) |
726 | smp_new_mmu_context_version(); | 725 | smp_new_mmu_context_version(); |
@@ -2125,7 +2124,6 @@ void free_initmem(void) | |||
2125 | ClearPageReserved(p); | 2124 | ClearPageReserved(p); |
2126 | init_page_count(p); | 2125 | init_page_count(p); |
2127 | __free_page(p); | 2126 | __free_page(p); |
2128 | num_physpages++; | ||
2129 | totalram_pages++; | 2127 | totalram_pages++; |
2130 | } | 2128 | } |
2131 | } | 2129 | } |
@@ -2142,7 +2140,6 @@ void free_initrd_mem(unsigned long start, unsigned long end) | |||
2142 | ClearPageReserved(p); | 2140 | ClearPageReserved(p); |
2143 | init_page_count(p); | 2141 | init_page_count(p); |
2144 | __free_page(p); | 2142 | __free_page(p); |
2145 | num_physpages++; | ||
2146 | totalram_pages++; | 2143 | totalram_pages++; |
2147 | } | 2144 | } |
2148 | } | 2145 | } |
diff --git a/arch/sparc/power/Makefile b/arch/sparc/power/Makefile new file mode 100644 index 000000000000..3201ace0ddbd --- /dev/null +++ b/arch/sparc/power/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | # Makefile for Sparc-specific hibernate files. | ||
2 | |||
3 | obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate_asm.o | ||
diff --git a/arch/sparc/power/hibernate.c b/arch/sparc/power/hibernate.c new file mode 100644 index 000000000000..42b0b8ce699a --- /dev/null +++ b/arch/sparc/power/hibernate.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * hibernate.c: Hibernaton support specific for sparc64. | ||
3 | * | ||
4 | * Copyright (C) 2013 Kirill V Tkhai (tkhai@yandex.ru) | ||
5 | */ | ||
6 | |||
7 | #include <linux/mm.h> | ||
8 | |||
9 | #include <asm/hibernate.h> | ||
10 | #include <asm/visasm.h> | ||
11 | #include <asm/page.h> | ||
12 | #include <asm/tlb.h> | ||
13 | |||
14 | /* References to section boundaries */ | ||
15 | extern const void __nosave_begin, __nosave_end; | ||
16 | |||
17 | struct saved_context saved_context; | ||
18 | |||
19 | /* | ||
20 | * pfn_is_nosave - check if given pfn is in the 'nosave' section | ||
21 | */ | ||
22 | |||
23 | int pfn_is_nosave(unsigned long pfn) | ||
24 | { | ||
25 | unsigned long nosave_begin_pfn = PFN_DOWN((unsigned long)&__nosave_begin); | ||
26 | unsigned long nosave_end_pfn = PFN_DOWN((unsigned long)&__nosave_end); | ||
27 | |||
28 | return (pfn >= nosave_begin_pfn) && (pfn < nosave_end_pfn); | ||
29 | } | ||
30 | |||
31 | void save_processor_state(void) | ||
32 | { | ||
33 | save_and_clear_fpu(); | ||
34 | } | ||
35 | |||
36 | void restore_processor_state(void) | ||
37 | { | ||
38 | struct mm_struct *mm = current->active_mm; | ||
39 | |||
40 | load_secondary_context(mm); | ||
41 | tsb_context_switch(mm); | ||
42 | } | ||
diff --git a/arch/sparc/power/hibernate_asm.S b/arch/sparc/power/hibernate_asm.S new file mode 100644 index 000000000000..79942166df84 --- /dev/null +++ b/arch/sparc/power/hibernate_asm.S | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * hibernate_asm.S: Hibernaton support specific for sparc64. | ||
3 | * | ||
4 | * Copyright (C) 2013 Kirill V Tkhai (tkhai@yandex.ru) | ||
5 | */ | ||
6 | |||
7 | #include <linux/linkage.h> | ||
8 | |||
9 | #include <asm/asm-offsets.h> | ||
10 | #include <asm/cpudata.h> | ||
11 | #include <asm/page.h> | ||
12 | |||
13 | ENTRY(swsusp_arch_suspend) | ||
14 | save %sp, -128, %sp | ||
15 | save %sp, -128, %sp | ||
16 | flushw | ||
17 | |||
18 | setuw saved_context, %g3 | ||
19 | |||
20 | /* Save window regs */ | ||
21 | rdpr %cwp, %g2 | ||
22 | stx %g2, [%g3 + SC_REG_CWP] | ||
23 | rdpr %wstate, %g2 | ||
24 | stx %g2, [%g3 + SC_REG_WSTATE] | ||
25 | stx %fp, [%g3 + SC_REG_FP] | ||
26 | |||
27 | /* Save state regs */ | ||
28 | rdpr %tick, %g2 | ||
29 | stx %g2, [%g3 + SC_REG_TICK] | ||
30 | rdpr %pstate, %g2 | ||
31 | stx %g2, [%g3 + SC_REG_PSTATE] | ||
32 | |||
33 | /* Save global regs */ | ||
34 | stx %g4, [%g3 + SC_REG_G4] | ||
35 | stx %g5, [%g3 + SC_REG_G5] | ||
36 | stx %g6, [%g3 + SC_REG_G6] | ||
37 | |||
38 | call swsusp_save | ||
39 | nop | ||
40 | |||
41 | mov %o0, %i0 | ||
42 | restore | ||
43 | |||
44 | mov %o0, %i0 | ||
45 | ret | ||
46 | restore | ||
47 | |||
48 | ENTRY(swsusp_arch_resume) | ||
49 | /* Write restore_pblist to %l0 */ | ||
50 | sethi %hi(restore_pblist), %l0 | ||
51 | ldx [%l0 + %lo(restore_pblist)], %l0 | ||
52 | |||
53 | call __flush_tlb_all | ||
54 | nop | ||
55 | |||
56 | /* Write PAGE_OFFSET to %g7 */ | ||
57 | sethi %uhi(PAGE_OFFSET), %g7 | ||
58 | sllx %g7, 32, %g7 | ||
59 | |||
60 | setuw (PAGE_SIZE-8), %g3 | ||
61 | |||
62 | /* Use MMU Bypass */ | ||
63 | rd %asi, %g1 | ||
64 | wr %g0, ASI_PHYS_USE_EC, %asi | ||
65 | |||
66 | ba fill_itlb | ||
67 | nop | ||
68 | |||
69 | pbe_loop: | ||
70 | cmp %l0, %g0 | ||
71 | be restore_ctx | ||
72 | sub %l0, %g7, %l0 | ||
73 | |||
74 | ldxa [%l0 ] %asi, %l1 /* address */ | ||
75 | ldxa [%l0 + 8] %asi, %l2 /* orig_address */ | ||
76 | |||
77 | /* phys addr */ | ||
78 | sub %l1, %g7, %l1 | ||
79 | sub %l2, %g7, %l2 | ||
80 | |||
81 | mov %g3, %l3 /* PAGE_SIZE-8 */ | ||
82 | copy_loop: | ||
83 | ldxa [%l1 + %l3] ASI_PHYS_USE_EC, %g2 | ||
84 | stxa %g2, [%l2 + %l3] ASI_PHYS_USE_EC | ||
85 | cmp %l3, %g0 | ||
86 | bne copy_loop | ||
87 | sub %l3, 8, %l3 | ||
88 | |||
89 | /* next pbe */ | ||
90 | ba pbe_loop | ||
91 | ldxa [%l0 + 16] %asi, %l0 | ||
92 | |||
93 | restore_ctx: | ||
94 | setuw saved_context, %g3 | ||
95 | |||
96 | /* Restore window regs */ | ||
97 | wrpr %g0, 0, %canrestore | ||
98 | wrpr %g0, 0, %otherwin | ||
99 | wrpr %g0, 6, %cansave | ||
100 | wrpr %g0, 0, %cleanwin | ||
101 | |||
102 | ldxa [%g3 + SC_REG_CWP] %asi, %g2 | ||
103 | wrpr %g2, %cwp | ||
104 | ldxa [%g3 + SC_REG_WSTATE] %asi, %g2 | ||
105 | wrpr %g2, %wstate | ||
106 | ldxa [%g3 + SC_REG_FP] %asi, %fp | ||
107 | |||
108 | /* Restore state regs */ | ||
109 | ldxa [%g3 + SC_REG_PSTATE] %asi, %g2 | ||
110 | wrpr %g2, %pstate | ||
111 | ldxa [%g3 + SC_REG_TICK] %asi, %g2 | ||
112 | wrpr %g2, %tick | ||
113 | |||
114 | /* Restore global regs */ | ||
115 | ldxa [%g3 + SC_REG_G4] %asi, %g4 | ||
116 | ldxa [%g3 + SC_REG_G5] %asi, %g5 | ||
117 | ldxa [%g3 + SC_REG_G6] %asi, %g6 | ||
118 | |||
119 | wr %g1, %g0, %asi | ||
120 | |||
121 | restore | ||
122 | restore | ||
123 | |||
124 | wrpr %g0, 14, %pil | ||
125 | |||
126 | retl | ||
127 | mov %g0, %o0 | ||
128 | |||
129 | fill_itlb: | ||
130 | ba pbe_loop | ||
131 | wrpr %g0, 15, %pil | ||