diff options
Diffstat (limited to 'arch')
81 files changed, 7384 insertions, 1113 deletions
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c index 1aaea6ab8c46..92f79cdd9a48 100644 --- a/arch/i386/kernel/acpi/boot.c +++ b/arch/i386/kernel/acpi/boot.c | |||
@@ -62,8 +62,6 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return | |||
62 | #include <mach_mpparse.h> | 62 | #include <mach_mpparse.h> |
63 | #endif /* CONFIG_X86_LOCAL_APIC */ | 63 | #endif /* CONFIG_X86_LOCAL_APIC */ |
64 | 64 | ||
65 | static inline int gsi_irq_sharing(int gsi) { return gsi; } | ||
66 | |||
67 | #endif /* X86 */ | 65 | #endif /* X86 */ |
68 | 66 | ||
69 | #define BAD_MADT_ENTRY(entry, end) ( \ | 67 | #define BAD_MADT_ENTRY(entry, end) ( \ |
@@ -468,12 +466,7 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) | |||
468 | 466 | ||
469 | int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) | 467 | int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) |
470 | { | 468 | { |
471 | #ifdef CONFIG_X86_IO_APIC | 469 | *irq = gsi; |
472 | if (use_pci_vector() && !platform_legacy_irq(gsi)) | ||
473 | *irq = IO_APIC_VECTOR(gsi); | ||
474 | else | ||
475 | #endif | ||
476 | *irq = gsi_irq_sharing(gsi); | ||
477 | return 0; | 470 | return 0; |
478 | } | 471 | } |
479 | 472 | ||
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index ea5f4e7958d8..d07ed31f11e3 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c | |||
@@ -34,35 +34,15 @@ | |||
34 | * moves to arch independent land | 34 | * moves to arch independent land |
35 | */ | 35 | */ |
36 | 36 | ||
37 | DEFINE_SPINLOCK(i8259A_lock); | ||
38 | |||
39 | static void end_8259A_irq (unsigned int irq) | ||
40 | { | ||
41 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && | ||
42 | irq_desc[irq].action) | ||
43 | enable_8259A_irq(irq); | ||
44 | } | ||
45 | |||
46 | #define shutdown_8259A_irq disable_8259A_irq | ||
47 | |||
48 | static int i8259A_auto_eoi; | 37 | static int i8259A_auto_eoi; |
49 | 38 | DEFINE_SPINLOCK(i8259A_lock); | |
50 | static void mask_and_ack_8259A(unsigned int); | 39 | static void mask_and_ack_8259A(unsigned int); |
51 | 40 | ||
52 | unsigned int startup_8259A_irq(unsigned int irq) | 41 | static struct irq_chip i8259A_chip = { |
53 | { | 42 | .name = "XT-PIC", |
54 | enable_8259A_irq(irq); | 43 | .mask = disable_8259A_irq, |
55 | return 0; /* never anything pending */ | 44 | .unmask = enable_8259A_irq, |
56 | } | 45 | .mask_ack = mask_and_ack_8259A, |
57 | |||
58 | static struct hw_interrupt_type i8259A_irq_type = { | ||
59 | .typename = "XT-PIC", | ||
60 | .startup = startup_8259A_irq, | ||
61 | .shutdown = shutdown_8259A_irq, | ||
62 | .enable = enable_8259A_irq, | ||
63 | .disable = disable_8259A_irq, | ||
64 | .ack = mask_and_ack_8259A, | ||
65 | .end = end_8259A_irq, | ||
66 | }; | 46 | }; |
67 | 47 | ||
68 | /* | 48 | /* |
@@ -133,7 +113,7 @@ void make_8259A_irq(unsigned int irq) | |||
133 | { | 113 | { |
134 | disable_irq_nosync(irq); | 114 | disable_irq_nosync(irq); |
135 | io_apic_irqs &= ~(1<<irq); | 115 | io_apic_irqs &= ~(1<<irq); |
136 | irq_desc[irq].chip = &i8259A_irq_type; | 116 | set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq); |
137 | enable_irq(irq); | 117 | enable_irq(irq); |
138 | } | 118 | } |
139 | 119 | ||
@@ -327,12 +307,12 @@ void init_8259A(int auto_eoi) | |||
327 | outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ | 307 | outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ |
328 | if (auto_eoi) | 308 | if (auto_eoi) |
329 | /* | 309 | /* |
330 | * in AEOI mode we just have to mask the interrupt | 310 | * In AEOI mode we just have to mask the interrupt |
331 | * when acking. | 311 | * when acking. |
332 | */ | 312 | */ |
333 | i8259A_irq_type.ack = disable_8259A_irq; | 313 | i8259A_chip.mask_ack = disable_8259A_irq; |
334 | else | 314 | else |
335 | i8259A_irq_type.ack = mask_and_ack_8259A; | 315 | i8259A_chip.mask_ack = mask_and_ack_8259A; |
336 | 316 | ||
337 | udelay(100); /* wait for 8259A to initialize */ | 317 | udelay(100); /* wait for 8259A to initialize */ |
338 | 318 | ||
@@ -389,12 +369,13 @@ void __init init_ISA_irqs (void) | |||
389 | /* | 369 | /* |
390 | * 16 old-style INTA-cycle interrupts: | 370 | * 16 old-style INTA-cycle interrupts: |
391 | */ | 371 | */ |
392 | irq_desc[i].chip = &i8259A_irq_type; | 372 | set_irq_chip_and_handler(i, &i8259A_chip, |
373 | handle_level_irq); | ||
393 | } else { | 374 | } else { |
394 | /* | 375 | /* |
395 | * 'high' PCI IRQs filled in on demand | 376 | * 'high' PCI IRQs filled in on demand |
396 | */ | 377 | */ |
397 | irq_desc[i].chip = &no_irq_type; | 378 | irq_desc[i].chip = &no_irq_chip; |
398 | } | 379 | } |
399 | } | 380 | } |
400 | } | 381 | } |
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index fd0df75cfbda..b7287fb499f3 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c | |||
@@ -31,6 +31,9 @@ | |||
31 | #include <linux/acpi.h> | 31 | #include <linux/acpi.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/sysdev.h> | 33 | #include <linux/sysdev.h> |
34 | #include <linux/pci.h> | ||
35 | #include <linux/msi.h> | ||
36 | #include <linux/htirq.h> | ||
34 | 37 | ||
35 | #include <asm/io.h> | 38 | #include <asm/io.h> |
36 | #include <asm/smp.h> | 39 | #include <asm/smp.h> |
@@ -38,6 +41,8 @@ | |||
38 | #include <asm/timer.h> | 41 | #include <asm/timer.h> |
39 | #include <asm/i8259.h> | 42 | #include <asm/i8259.h> |
40 | #include <asm/nmi.h> | 43 | #include <asm/nmi.h> |
44 | #include <asm/msidef.h> | ||
45 | #include <asm/hypertransport.h> | ||
41 | 46 | ||
42 | #include <mach_apic.h> | 47 | #include <mach_apic.h> |
43 | #include <mach_apicdef.h> | 48 | #include <mach_apicdef.h> |
@@ -86,15 +91,6 @@ static struct irq_pin_list { | |||
86 | int apic, pin, next; | 91 | int apic, pin, next; |
87 | } irq_2_pin[PIN_MAP_SIZE]; | 92 | } irq_2_pin[PIN_MAP_SIZE]; |
88 | 93 | ||
89 | int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; | ||
90 | #ifdef CONFIG_PCI_MSI | ||
91 | #define vector_to_irq(vector) \ | ||
92 | (platform_legacy_irq(vector) ? vector : vector_irq[vector]) | ||
93 | #else | ||
94 | #define vector_to_irq(vector) (vector) | ||
95 | #endif | ||
96 | |||
97 | |||
98 | union entry_union { | 94 | union entry_union { |
99 | struct { u32 w1, w2; }; | 95 | struct { u32 w1, w2; }; |
100 | struct IO_APIC_route_entry entry; | 96 | struct IO_APIC_route_entry entry; |
@@ -280,7 +276,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) | |||
280 | break; | 276 | break; |
281 | entry = irq_2_pin + entry->next; | 277 | entry = irq_2_pin + entry->next; |
282 | } | 278 | } |
283 | set_irq_info(irq, cpumask); | 279 | set_native_irq_info(irq, cpumask); |
284 | spin_unlock_irqrestore(&ioapic_lock, flags); | 280 | spin_unlock_irqrestore(&ioapic_lock, flags); |
285 | } | 281 | } |
286 | 282 | ||
@@ -1181,46 +1177,45 @@ static inline int IO_APIC_irq_trigger(int irq) | |||
1181 | /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ | 1177 | /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ |
1182 | u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; | 1178 | u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; |
1183 | 1179 | ||
1184 | int assign_irq_vector(int irq) | 1180 | static int __assign_irq_vector(int irq) |
1185 | { | 1181 | { |
1186 | static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; | 1182 | static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; |
1187 | unsigned long flags; | ||
1188 | int vector; | 1183 | int vector; |
1189 | 1184 | ||
1190 | BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); | 1185 | BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); |
1191 | 1186 | ||
1192 | spin_lock_irqsave(&vector_lock, flags); | 1187 | if (IO_APIC_VECTOR(irq) > 0) |
1193 | |||
1194 | if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { | ||
1195 | spin_unlock_irqrestore(&vector_lock, flags); | ||
1196 | return IO_APIC_VECTOR(irq); | 1188 | return IO_APIC_VECTOR(irq); |
1197 | } | 1189 | |
1198 | next: | ||
1199 | current_vector += 8; | 1190 | current_vector += 8; |
1200 | if (current_vector == SYSCALL_VECTOR) | 1191 | if (current_vector == SYSCALL_VECTOR) |
1201 | goto next; | 1192 | current_vector += 8; |
1202 | 1193 | ||
1203 | if (current_vector >= FIRST_SYSTEM_VECTOR) { | 1194 | if (current_vector >= FIRST_SYSTEM_VECTOR) { |
1204 | offset++; | 1195 | offset++; |
1205 | if (!(offset%8)) { | 1196 | if (!(offset % 8)) |
1206 | spin_unlock_irqrestore(&vector_lock, flags); | ||
1207 | return -ENOSPC; | 1197 | return -ENOSPC; |
1208 | } | ||
1209 | current_vector = FIRST_DEVICE_VECTOR + offset; | 1198 | current_vector = FIRST_DEVICE_VECTOR + offset; |
1210 | } | 1199 | } |
1211 | 1200 | ||
1212 | vector = current_vector; | 1201 | vector = current_vector; |
1213 | vector_irq[vector] = irq; | 1202 | IO_APIC_VECTOR(irq) = vector; |
1214 | if (irq != AUTO_ASSIGN) | 1203 | |
1215 | IO_APIC_VECTOR(irq) = vector; | 1204 | return vector; |
1205 | } | ||
1206 | |||
1207 | static int assign_irq_vector(int irq) | ||
1208 | { | ||
1209 | unsigned long flags; | ||
1210 | int vector; | ||
1216 | 1211 | ||
1212 | spin_lock_irqsave(&vector_lock, flags); | ||
1213 | vector = __assign_irq_vector(irq); | ||
1217 | spin_unlock_irqrestore(&vector_lock, flags); | 1214 | spin_unlock_irqrestore(&vector_lock, flags); |
1218 | 1215 | ||
1219 | return vector; | 1216 | return vector; |
1220 | } | 1217 | } |
1221 | 1218 | static struct irq_chip ioapic_chip; | |
1222 | static struct hw_interrupt_type ioapic_level_type; | ||
1223 | static struct hw_interrupt_type ioapic_edge_type; | ||
1224 | 1219 | ||
1225 | #define IOAPIC_AUTO -1 | 1220 | #define IOAPIC_AUTO -1 |
1226 | #define IOAPIC_EDGE 0 | 1221 | #define IOAPIC_EDGE 0 |
@@ -1228,16 +1223,14 @@ static struct hw_interrupt_type ioapic_edge_type; | |||
1228 | 1223 | ||
1229 | static void ioapic_register_intr(int irq, int vector, unsigned long trigger) | 1224 | static void ioapic_register_intr(int irq, int vector, unsigned long trigger) |
1230 | { | 1225 | { |
1231 | unsigned idx; | ||
1232 | |||
1233 | idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq; | ||
1234 | |||
1235 | if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || | 1226 | if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || |
1236 | trigger == IOAPIC_LEVEL) | 1227 | trigger == IOAPIC_LEVEL) |
1237 | irq_desc[idx].chip = &ioapic_level_type; | 1228 | set_irq_chip_and_handler(irq, &ioapic_chip, |
1229 | handle_fasteoi_irq); | ||
1238 | else | 1230 | else |
1239 | irq_desc[idx].chip = &ioapic_edge_type; | 1231 | set_irq_chip_and_handler(irq, &ioapic_chip, |
1240 | set_intr_gate(vector, interrupt[idx]); | 1232 | handle_edge_irq); |
1233 | set_intr_gate(vector, interrupt[irq]); | ||
1241 | } | 1234 | } |
1242 | 1235 | ||
1243 | static void __init setup_IO_APIC_irqs(void) | 1236 | static void __init setup_IO_APIC_irqs(void) |
@@ -1346,7 +1339,8 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in | |||
1346 | * The timer IRQ doesn't have to know that behind the | 1339 | * The timer IRQ doesn't have to know that behind the |
1347 | * scene we have a 8259A-master in AEOI mode ... | 1340 | * scene we have a 8259A-master in AEOI mode ... |
1348 | */ | 1341 | */ |
1349 | irq_desc[0].chip = &ioapic_edge_type; | 1342 | irq_desc[0].chip = &ioapic_chip; |
1343 | set_irq_handler(0, handle_edge_irq); | ||
1350 | 1344 | ||
1351 | /* | 1345 | /* |
1352 | * Add it to the IO-APIC irq-routing table: | 1346 | * Add it to the IO-APIC irq-routing table: |
@@ -1481,17 +1475,12 @@ void __init print_IO_APIC(void) | |||
1481 | ); | 1475 | ); |
1482 | } | 1476 | } |
1483 | } | 1477 | } |
1484 | if (use_pci_vector()) | ||
1485 | printk(KERN_INFO "Using vector-based indexing\n"); | ||
1486 | printk(KERN_DEBUG "IRQ to pin mappings:\n"); | 1478 | printk(KERN_DEBUG "IRQ to pin mappings:\n"); |
1487 | for (i = 0; i < NR_IRQS; i++) { | 1479 | for (i = 0; i < NR_IRQS; i++) { |
1488 | struct irq_pin_list *entry = irq_2_pin + i; | 1480 | struct irq_pin_list *entry = irq_2_pin + i; |
1489 | if (entry->pin < 0) | 1481 | if (entry->pin < 0) |
1490 | continue; | 1482 | continue; |
1491 | if (use_pci_vector() && !platform_legacy_irq(i)) | 1483 | printk(KERN_DEBUG "IRQ%d ", i); |
1492 | printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i)); | ||
1493 | else | ||
1494 | printk(KERN_DEBUG "IRQ%d ", i); | ||
1495 | for (;;) { | 1484 | for (;;) { |
1496 | printk("-> %d:%d", entry->apic, entry->pin); | 1485 | printk("-> %d:%d", entry->apic, entry->pin); |
1497 | if (!entry->next) | 1486 | if (!entry->next) |
@@ -1918,6 +1907,8 @@ static int __init timer_irq_works(void) | |||
1918 | */ | 1907 | */ |
1919 | 1908 | ||
1920 | /* | 1909 | /* |
1910 | * Startup quirk: | ||
1911 | * | ||
1921 | * Starting up a edge-triggered IO-APIC interrupt is | 1912 | * Starting up a edge-triggered IO-APIC interrupt is |
1922 | * nasty - we need to make sure that we get the edge. | 1913 | * nasty - we need to make sure that we get the edge. |
1923 | * If it is already asserted for some reason, we need | 1914 | * If it is already asserted for some reason, we need |
@@ -1925,8 +1916,10 @@ static int __init timer_irq_works(void) | |||
1925 | * | 1916 | * |
1926 | * This is not complete - we should be able to fake | 1917 | * This is not complete - we should be able to fake |
1927 | * an edge even if it isn't on the 8259A... | 1918 | * an edge even if it isn't on the 8259A... |
1919 | * | ||
1920 | * (We do this for level-triggered IRQs too - it cannot hurt.) | ||
1928 | */ | 1921 | */ |
1929 | static unsigned int startup_edge_ioapic_irq(unsigned int irq) | 1922 | static unsigned int startup_ioapic_irq(unsigned int irq) |
1930 | { | 1923 | { |
1931 | int was_pending = 0; | 1924 | int was_pending = 0; |
1932 | unsigned long flags; | 1925 | unsigned long flags; |
@@ -1943,47 +1936,18 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) | |||
1943 | return was_pending; | 1936 | return was_pending; |
1944 | } | 1937 | } |
1945 | 1938 | ||
1946 | /* | 1939 | static void ack_ioapic_irq(unsigned int irq) |
1947 | * Once we have recorded IRQ_PENDING already, we can mask the | ||
1948 | * interrupt for real. This prevents IRQ storms from unhandled | ||
1949 | * devices. | ||
1950 | */ | ||
1951 | static void ack_edge_ioapic_irq(unsigned int irq) | ||
1952 | { | 1940 | { |
1953 | move_irq(irq); | 1941 | move_native_irq(irq); |
1954 | if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) | ||
1955 | == (IRQ_PENDING | IRQ_DISABLED)) | ||
1956 | mask_IO_APIC_irq(irq); | ||
1957 | ack_APIC_irq(); | 1942 | ack_APIC_irq(); |
1958 | } | 1943 | } |
1959 | 1944 | ||
1960 | /* | 1945 | static void ack_ioapic_quirk_irq(unsigned int irq) |
1961 | * Level triggered interrupts can just be masked, | ||
1962 | * and shutting down and starting up the interrupt | ||
1963 | * is the same as enabling and disabling them -- except | ||
1964 | * with a startup need to return a "was pending" value. | ||
1965 | * | ||
1966 | * Level triggered interrupts are special because we | ||
1967 | * do not touch any IO-APIC register while handling | ||
1968 | * them. We ack the APIC in the end-IRQ handler, not | ||
1969 | * in the start-IRQ-handler. Protection against reentrance | ||
1970 | * from the same interrupt is still provided, both by the | ||
1971 | * generic IRQ layer and by the fact that an unacked local | ||
1972 | * APIC does not accept IRQs. | ||
1973 | */ | ||
1974 | static unsigned int startup_level_ioapic_irq (unsigned int irq) | ||
1975 | { | ||
1976 | unmask_IO_APIC_irq(irq); | ||
1977 | |||
1978 | return 0; /* don't check for pending */ | ||
1979 | } | ||
1980 | |||
1981 | static void end_level_ioapic_irq (unsigned int irq) | ||
1982 | { | 1946 | { |
1983 | unsigned long v; | 1947 | unsigned long v; |
1984 | int i; | 1948 | int i; |
1985 | 1949 | ||
1986 | move_irq(irq); | 1950 | move_native_irq(irq); |
1987 | /* | 1951 | /* |
1988 | * It appears there is an erratum which affects at least version 0x11 | 1952 | * It appears there is an erratum which affects at least version 0x11 |
1989 | * of I/O APIC (that's the 82093AA and cores integrated into various | 1953 | * of I/O APIC (that's the 82093AA and cores integrated into various |
@@ -2018,105 +1982,26 @@ static void end_level_ioapic_irq (unsigned int irq) | |||
2018 | } | 1982 | } |
2019 | } | 1983 | } |
2020 | 1984 | ||
2021 | #ifdef CONFIG_PCI_MSI | 1985 | static int ioapic_retrigger_irq(unsigned int irq) |
2022 | static unsigned int startup_edge_ioapic_vector(unsigned int vector) | ||
2023 | { | ||
2024 | int irq = vector_to_irq(vector); | ||
2025 | |||
2026 | return startup_edge_ioapic_irq(irq); | ||
2027 | } | ||
2028 | |||
2029 | static void ack_edge_ioapic_vector(unsigned int vector) | ||
2030 | { | ||
2031 | int irq = vector_to_irq(vector); | ||
2032 | |||
2033 | move_native_irq(vector); | ||
2034 | ack_edge_ioapic_irq(irq); | ||
2035 | } | ||
2036 | |||
2037 | static unsigned int startup_level_ioapic_vector (unsigned int vector) | ||
2038 | { | ||
2039 | int irq = vector_to_irq(vector); | ||
2040 | |||
2041 | return startup_level_ioapic_irq (irq); | ||
2042 | } | ||
2043 | |||
2044 | static void end_level_ioapic_vector (unsigned int vector) | ||
2045 | { | ||
2046 | int irq = vector_to_irq(vector); | ||
2047 | |||
2048 | move_native_irq(vector); | ||
2049 | end_level_ioapic_irq(irq); | ||
2050 | } | ||
2051 | |||
2052 | static void mask_IO_APIC_vector (unsigned int vector) | ||
2053 | { | ||
2054 | int irq = vector_to_irq(vector); | ||
2055 | |||
2056 | mask_IO_APIC_irq(irq); | ||
2057 | } | ||
2058 | |||
2059 | static void unmask_IO_APIC_vector (unsigned int vector) | ||
2060 | { | ||
2061 | int irq = vector_to_irq(vector); | ||
2062 | |||
2063 | unmask_IO_APIC_irq(irq); | ||
2064 | } | ||
2065 | |||
2066 | #ifdef CONFIG_SMP | ||
2067 | static void set_ioapic_affinity_vector (unsigned int vector, | ||
2068 | cpumask_t cpu_mask) | ||
2069 | { | ||
2070 | int irq = vector_to_irq(vector); | ||
2071 | |||
2072 | set_native_irq_info(vector, cpu_mask); | ||
2073 | set_ioapic_affinity_irq(irq, cpu_mask); | ||
2074 | } | ||
2075 | #endif | ||
2076 | #endif | ||
2077 | |||
2078 | static int ioapic_retrigger(unsigned int irq) | ||
2079 | { | 1986 | { |
2080 | send_IPI_self(IO_APIC_VECTOR(irq)); | 1987 | send_IPI_self(IO_APIC_VECTOR(irq)); |
2081 | 1988 | ||
2082 | return 1; | 1989 | return 1; |
2083 | } | 1990 | } |
2084 | 1991 | ||
2085 | /* | 1992 | static struct irq_chip ioapic_chip __read_mostly = { |
2086 | * Level and edge triggered IO-APIC interrupts need different handling, | 1993 | .name = "IO-APIC", |
2087 | * so we use two separate IRQ descriptors. Edge triggered IRQs can be | 1994 | .startup = startup_ioapic_irq, |
2088 | * handled with the level-triggered descriptor, but that one has slightly | 1995 | .mask = mask_IO_APIC_irq, |
2089 | * more overhead. Level-triggered interrupts cannot be handled with the | 1996 | .unmask = unmask_IO_APIC_irq, |
2090 | * edge-triggered handler, without risking IRQ storms and other ugly | 1997 | .ack = ack_ioapic_irq, |
2091 | * races. | 1998 | .eoi = ack_ioapic_quirk_irq, |
2092 | */ | ||
2093 | static struct hw_interrupt_type ioapic_edge_type __read_mostly = { | ||
2094 | .typename = "IO-APIC-edge", | ||
2095 | .startup = startup_edge_ioapic, | ||
2096 | .shutdown = shutdown_edge_ioapic, | ||
2097 | .enable = enable_edge_ioapic, | ||
2098 | .disable = disable_edge_ioapic, | ||
2099 | .ack = ack_edge_ioapic, | ||
2100 | .end = end_edge_ioapic, | ||
2101 | #ifdef CONFIG_SMP | 1999 | #ifdef CONFIG_SMP |
2102 | .set_affinity = set_ioapic_affinity, | 2000 | .set_affinity = set_ioapic_affinity_irq, |
2103 | #endif | 2001 | #endif |
2104 | .retrigger = ioapic_retrigger, | 2002 | .retrigger = ioapic_retrigger_irq, |
2105 | }; | 2003 | }; |
2106 | 2004 | ||
2107 | static struct hw_interrupt_type ioapic_level_type __read_mostly = { | ||
2108 | .typename = "IO-APIC-level", | ||
2109 | .startup = startup_level_ioapic, | ||
2110 | .shutdown = shutdown_level_ioapic, | ||
2111 | .enable = enable_level_ioapic, | ||
2112 | .disable = disable_level_ioapic, | ||
2113 | .ack = mask_and_ack_level_ioapic, | ||
2114 | .end = end_level_ioapic, | ||
2115 | #ifdef CONFIG_SMP | ||
2116 | .set_affinity = set_ioapic_affinity, | ||
2117 | #endif | ||
2118 | .retrigger = ioapic_retrigger, | ||
2119 | }; | ||
2120 | 2005 | ||
2121 | static inline void init_IO_APIC_traps(void) | 2006 | static inline void init_IO_APIC_traps(void) |
2122 | { | 2007 | { |
@@ -2135,11 +2020,6 @@ static inline void init_IO_APIC_traps(void) | |||
2135 | */ | 2020 | */ |
2136 | for (irq = 0; irq < NR_IRQS ; irq++) { | 2021 | for (irq = 0; irq < NR_IRQS ; irq++) { |
2137 | int tmp = irq; | 2022 | int tmp = irq; |
2138 | if (use_pci_vector()) { | ||
2139 | if (!platform_legacy_irq(tmp)) | ||
2140 | if ((tmp = vector_to_irq(tmp)) == -1) | ||
2141 | continue; | ||
2142 | } | ||
2143 | if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { | 2023 | if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { |
2144 | /* | 2024 | /* |
2145 | * Hmm.. We don't have an entry for this, | 2025 | * Hmm.. We don't have an entry for this, |
@@ -2150,20 +2030,21 @@ static inline void init_IO_APIC_traps(void) | |||
2150 | make_8259A_irq(irq); | 2030 | make_8259A_irq(irq); |
2151 | else | 2031 | else |
2152 | /* Strange. Oh, well.. */ | 2032 | /* Strange. Oh, well.. */ |
2153 | irq_desc[irq].chip = &no_irq_type; | 2033 | irq_desc[irq].chip = &no_irq_chip; |
2154 | } | 2034 | } |
2155 | } | 2035 | } |
2156 | } | 2036 | } |
2157 | 2037 | ||
2158 | static void enable_lapic_irq (unsigned int irq) | 2038 | /* |
2159 | { | 2039 | * The local APIC irq-chip implementation: |
2160 | unsigned long v; | 2040 | */ |
2161 | 2041 | ||
2162 | v = apic_read(APIC_LVT0); | 2042 | static void ack_apic(unsigned int irq) |
2163 | apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED); | 2043 | { |
2044 | ack_APIC_irq(); | ||
2164 | } | 2045 | } |
2165 | 2046 | ||
2166 | static void disable_lapic_irq (unsigned int irq) | 2047 | static void mask_lapic_irq (unsigned int irq) |
2167 | { | 2048 | { |
2168 | unsigned long v; | 2049 | unsigned long v; |
2169 | 2050 | ||
@@ -2171,21 +2052,19 @@ static void disable_lapic_irq (unsigned int irq) | |||
2171 | apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); | 2052 | apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED); |
2172 | } | 2053 | } |
2173 | 2054 | ||
2174 | static void ack_lapic_irq (unsigned int irq) | 2055 | static void unmask_lapic_irq (unsigned int irq) |
2175 | { | 2056 | { |
2176 | ack_APIC_irq(); | 2057 | unsigned long v; |
2177 | } | ||
2178 | 2058 | ||
2179 | static void end_lapic_irq (unsigned int i) { /* nothing */ } | 2059 | v = apic_read(APIC_LVT0); |
2060 | apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED); | ||
2061 | } | ||
2180 | 2062 | ||
2181 | static struct hw_interrupt_type lapic_irq_type __read_mostly = { | 2063 | static struct irq_chip lapic_chip __read_mostly = { |
2182 | .typename = "local-APIC-edge", | 2064 | .name = "local-APIC-edge", |
2183 | .startup = NULL, /* startup_irq() not used for IRQ0 */ | 2065 | .mask = mask_lapic_irq, |
2184 | .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */ | 2066 | .unmask = unmask_lapic_irq, |
2185 | .enable = enable_lapic_irq, | 2067 | .eoi = ack_apic, |
2186 | .disable = disable_lapic_irq, | ||
2187 | .ack = ack_lapic_irq, | ||
2188 | .end = end_lapic_irq | ||
2189 | }; | 2068 | }; |
2190 | 2069 | ||
2191 | static void setup_nmi (void) | 2070 | static void setup_nmi (void) |
@@ -2356,7 +2235,7 @@ static inline void check_timer(void) | |||
2356 | printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); | 2235 | printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); |
2357 | 2236 | ||
2358 | disable_8259A_irq(0); | 2237 | disable_8259A_irq(0); |
2359 | irq_desc[0].chip = &lapic_irq_type; | 2238 | set_irq_chip_and_handler(0, &lapic_chip, handle_fasteoi_irq); |
2360 | apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ | 2239 | apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */ |
2361 | enable_8259A_irq(0); | 2240 | enable_8259A_irq(0); |
2362 | 2241 | ||
@@ -2531,6 +2410,238 @@ static int __init ioapic_init_sysfs(void) | |||
2531 | 2410 | ||
2532 | device_initcall(ioapic_init_sysfs); | 2411 | device_initcall(ioapic_init_sysfs); |
2533 | 2412 | ||
2413 | /* | ||
2414 | * Dynamic irq allocate and deallocation | ||
2415 | */ | ||
2416 | int create_irq(void) | ||
2417 | { | ||
2418 | /* Allocate an unused irq */ | ||
2419 | int irq, new, vector; | ||
2420 | unsigned long flags; | ||
2421 | |||
2422 | irq = -ENOSPC; | ||
2423 | spin_lock_irqsave(&vector_lock, flags); | ||
2424 | for (new = (NR_IRQS - 1); new >= 0; new--) { | ||
2425 | if (platform_legacy_irq(new)) | ||
2426 | continue; | ||
2427 | if (irq_vector[new] != 0) | ||
2428 | continue; | ||
2429 | vector = __assign_irq_vector(new); | ||
2430 | if (likely(vector > 0)) | ||
2431 | irq = new; | ||
2432 | break; | ||
2433 | } | ||
2434 | spin_unlock_irqrestore(&vector_lock, flags); | ||
2435 | |||
2436 | if (irq >= 0) { | ||
2437 | set_intr_gate(vector, interrupt[irq]); | ||
2438 | dynamic_irq_init(irq); | ||
2439 | } | ||
2440 | return irq; | ||
2441 | } | ||
2442 | |||
2443 | void destroy_irq(unsigned int irq) | ||
2444 | { | ||
2445 | unsigned long flags; | ||
2446 | |||
2447 | dynamic_irq_cleanup(irq); | ||
2448 | |||
2449 | spin_lock_irqsave(&vector_lock, flags); | ||
2450 | irq_vector[irq] = 0; | ||
2451 | spin_unlock_irqrestore(&vector_lock, flags); | ||
2452 | } | ||
2453 | |||
2454 | /* | ||
2455 | * MSI mesage composition | ||
2456 | */ | ||
2457 | #ifdef CONFIG_PCI_MSI | ||
2458 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | ||
2459 | { | ||
2460 | int vector; | ||
2461 | unsigned dest; | ||
2462 | |||
2463 | vector = assign_irq_vector(irq); | ||
2464 | if (vector >= 0) { | ||
2465 | dest = cpu_mask_to_apicid(TARGET_CPUS); | ||
2466 | |||
2467 | msg->address_hi = MSI_ADDR_BASE_HI; | ||
2468 | msg->address_lo = | ||
2469 | MSI_ADDR_BASE_LO | | ||
2470 | ((INT_DEST_MODE == 0) ? | ||
2471 | MSI_ADDR_DEST_MODE_PHYSICAL: | ||
2472 | MSI_ADDR_DEST_MODE_LOGICAL) | | ||
2473 | ((INT_DELIVERY_MODE != dest_LowestPrio) ? | ||
2474 | MSI_ADDR_REDIRECTION_CPU: | ||
2475 | MSI_ADDR_REDIRECTION_LOWPRI) | | ||
2476 | MSI_ADDR_DEST_ID(dest); | ||
2477 | |||
2478 | msg->data = | ||
2479 | MSI_DATA_TRIGGER_EDGE | | ||
2480 | MSI_DATA_LEVEL_ASSERT | | ||
2481 | ((INT_DELIVERY_MODE != dest_LowestPrio) ? | ||
2482 | MSI_DATA_DELIVERY_FIXED: | ||
2483 | MSI_DATA_DELIVERY_LOWPRI) | | ||
2484 | MSI_DATA_VECTOR(vector); | ||
2485 | } | ||
2486 | return vector; | ||
2487 | } | ||
2488 | |||
2489 | #ifdef CONFIG_SMP | ||
2490 | static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) | ||
2491 | { | ||
2492 | struct msi_msg msg; | ||
2493 | unsigned int dest; | ||
2494 | cpumask_t tmp; | ||
2495 | int vector; | ||
2496 | |||
2497 | cpus_and(tmp, mask, cpu_online_map); | ||
2498 | if (cpus_empty(tmp)) | ||
2499 | tmp = TARGET_CPUS; | ||
2500 | |||
2501 | vector = assign_irq_vector(irq); | ||
2502 | if (vector < 0) | ||
2503 | return; | ||
2504 | |||
2505 | dest = cpu_mask_to_apicid(mask); | ||
2506 | |||
2507 | read_msi_msg(irq, &msg); | ||
2508 | |||
2509 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
2510 | msg.data |= MSI_DATA_VECTOR(vector); | ||
2511 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
2512 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
2513 | |||
2514 | write_msi_msg(irq, &msg); | ||
2515 | set_native_irq_info(irq, mask); | ||
2516 | } | ||
2517 | #endif /* CONFIG_SMP */ | ||
2518 | |||
2519 | /* | ||
2520 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, | ||
2521 | * which implement the MSI or MSI-X Capability Structure. | ||
2522 | */ | ||
2523 | static struct irq_chip msi_chip = { | ||
2524 | .name = "PCI-MSI", | ||
2525 | .unmask = unmask_msi_irq, | ||
2526 | .mask = mask_msi_irq, | ||
2527 | .ack = ack_ioapic_irq, | ||
2528 | #ifdef CONFIG_SMP | ||
2529 | .set_affinity = set_msi_irq_affinity, | ||
2530 | #endif | ||
2531 | .retrigger = ioapic_retrigger_irq, | ||
2532 | }; | ||
2533 | |||
2534 | int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) | ||
2535 | { | ||
2536 | struct msi_msg msg; | ||
2537 | int ret; | ||
2538 | ret = msi_compose_msg(dev, irq, &msg); | ||
2539 | if (ret < 0) | ||
2540 | return ret; | ||
2541 | |||
2542 | write_msi_msg(irq, &msg); | ||
2543 | |||
2544 | set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq); | ||
2545 | |||
2546 | return 0; | ||
2547 | } | ||
2548 | |||
2549 | void arch_teardown_msi_irq(unsigned int irq) | ||
2550 | { | ||
2551 | return; | ||
2552 | } | ||
2553 | |||
2554 | #endif /* CONFIG_PCI_MSI */ | ||
2555 | |||
2556 | /* | ||
2557 | * Hypertransport interrupt support | ||
2558 | */ | ||
2559 | #ifdef CONFIG_HT_IRQ | ||
2560 | |||
2561 | #ifdef CONFIG_SMP | ||
2562 | |||
2563 | static void target_ht_irq(unsigned int irq, unsigned int dest) | ||
2564 | { | ||
2565 | u32 low, high; | ||
2566 | low = read_ht_irq_low(irq); | ||
2567 | high = read_ht_irq_high(irq); | ||
2568 | |||
2569 | low &= ~(HT_IRQ_LOW_DEST_ID_MASK); | ||
2570 | high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); | ||
2571 | |||
2572 | low |= HT_IRQ_LOW_DEST_ID(dest); | ||
2573 | high |= HT_IRQ_HIGH_DEST_ID(dest); | ||
2574 | |||
2575 | write_ht_irq_low(irq, low); | ||
2576 | write_ht_irq_high(irq, high); | ||
2577 | } | ||
2578 | |||
2579 | static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) | ||
2580 | { | ||
2581 | unsigned int dest; | ||
2582 | cpumask_t tmp; | ||
2583 | |||
2584 | cpus_and(tmp, mask, cpu_online_map); | ||
2585 | if (cpus_empty(tmp)) | ||
2586 | tmp = TARGET_CPUS; | ||
2587 | |||
2588 | cpus_and(mask, tmp, CPU_MASK_ALL); | ||
2589 | |||
2590 | dest = cpu_mask_to_apicid(mask); | ||
2591 | |||
2592 | target_ht_irq(irq, dest); | ||
2593 | set_native_irq_info(irq, mask); | ||
2594 | } | ||
2595 | #endif | ||
2596 | |||
2597 | static struct hw_interrupt_type ht_irq_chip = { | ||
2598 | .name = "PCI-HT", | ||
2599 | .mask = mask_ht_irq, | ||
2600 | .unmask = unmask_ht_irq, | ||
2601 | .ack = ack_ioapic_irq, | ||
2602 | #ifdef CONFIG_SMP | ||
2603 | .set_affinity = set_ht_irq_affinity, | ||
2604 | #endif | ||
2605 | .retrigger = ioapic_retrigger_irq, | ||
2606 | }; | ||
2607 | |||
2608 | int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) | ||
2609 | { | ||
2610 | int vector; | ||
2611 | |||
2612 | vector = assign_irq_vector(irq); | ||
2613 | if (vector >= 0) { | ||
2614 | u32 low, high; | ||
2615 | unsigned dest; | ||
2616 | cpumask_t tmp; | ||
2617 | |||
2618 | cpus_clear(tmp); | ||
2619 | cpu_set(vector >> 8, tmp); | ||
2620 | dest = cpu_mask_to_apicid(tmp); | ||
2621 | |||
2622 | high = HT_IRQ_HIGH_DEST_ID(dest); | ||
2623 | |||
2624 | low = HT_IRQ_LOW_BASE | | ||
2625 | HT_IRQ_LOW_DEST_ID(dest) | | ||
2626 | HT_IRQ_LOW_VECTOR(vector) | | ||
2627 | ((INT_DEST_MODE == 0) ? | ||
2628 | HT_IRQ_LOW_DM_PHYSICAL : | ||
2629 | HT_IRQ_LOW_DM_LOGICAL) | | ||
2630 | HT_IRQ_LOW_RQEOI_EDGE | | ||
2631 | ((INT_DELIVERY_MODE != dest_LowestPrio) ? | ||
2632 | HT_IRQ_LOW_MT_FIXED : | ||
2633 | HT_IRQ_LOW_MT_ARBITRATED) | | ||
2634 | HT_IRQ_LOW_IRQ_MASKED; | ||
2635 | |||
2636 | write_ht_irq_low(irq, low); | ||
2637 | write_ht_irq_high(irq, high); | ||
2638 | |||
2639 | set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq); | ||
2640 | } | ||
2641 | return vector; | ||
2642 | } | ||
2643 | #endif /* CONFIG_HT_IRQ */ | ||
2644 | |||
2534 | /* -------------------------------------------------------------------------- | 2645 | /* -------------------------------------------------------------------------- |
2535 | ACPI-based IOAPIC Configuration | 2646 | ACPI-based IOAPIC Configuration |
2536 | -------------------------------------------------------------------------- */ | 2647 | -------------------------------------------------------------------------- */ |
@@ -2684,7 +2795,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a | |||
2684 | 2795 | ||
2685 | ioapic_write_entry(ioapic, pin, entry); | 2796 | ioapic_write_entry(ioapic, pin, entry); |
2686 | spin_lock_irqsave(&ioapic_lock, flags); | 2797 | spin_lock_irqsave(&ioapic_lock, flags); |
2687 | set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); | 2798 | set_native_irq_info(irq, TARGET_CPUS); |
2688 | spin_unlock_irqrestore(&ioapic_lock, flags); | 2799 | spin_unlock_irqrestore(&ioapic_lock, flags); |
2689 | 2800 | ||
2690 | return 0; | 2801 | return 0; |
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 5fe547cd8f9f..3dd2e180151b 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c | |||
@@ -55,6 +55,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) | |||
55 | { | 55 | { |
56 | /* high bit used in ret_from_ code */ | 56 | /* high bit used in ret_from_ code */ |
57 | int irq = ~regs->orig_eax; | 57 | int irq = ~regs->orig_eax; |
58 | struct irq_desc *desc = irq_desc + irq; | ||
58 | #ifdef CONFIG_4KSTACKS | 59 | #ifdef CONFIG_4KSTACKS |
59 | union irq_ctx *curctx, *irqctx; | 60 | union irq_ctx *curctx, *irqctx; |
60 | u32 *isp; | 61 | u32 *isp; |
@@ -94,7 +95,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) | |||
94 | * current stack (which is the irq stack already after all) | 95 | * current stack (which is the irq stack already after all) |
95 | */ | 96 | */ |
96 | if (curctx != irqctx) { | 97 | if (curctx != irqctx) { |
97 | int arg1, arg2, ebx; | 98 | int arg1, arg2, arg3, ebx; |
98 | 99 | ||
99 | /* build the stack frame on the IRQ stack */ | 100 | /* build the stack frame on the IRQ stack */ |
100 | isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); | 101 | isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); |
@@ -110,16 +111,17 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs) | |||
110 | (curctx->tinfo.preempt_count & SOFTIRQ_MASK); | 111 | (curctx->tinfo.preempt_count & SOFTIRQ_MASK); |
111 | 112 | ||
112 | asm volatile( | 113 | asm volatile( |
113 | " xchgl %%ebx,%%esp \n" | 114 | " xchgl %%ebx,%%esp \n" |
114 | " call __do_IRQ \n" | 115 | " call *%%edi \n" |
115 | " movl %%ebx,%%esp \n" | 116 | " movl %%ebx,%%esp \n" |
116 | : "=a" (arg1), "=d" (arg2), "=b" (ebx) | 117 | : "=a" (arg1), "=d" (arg2), "=c" (arg3), "=b" (ebx) |
117 | : "0" (irq), "1" (regs), "2" (isp) | 118 | : "0" (irq), "1" (desc), "2" (regs), "3" (isp), |
118 | : "memory", "cc", "ecx" | 119 | "D" (desc->handle_irq) |
120 | : "memory", "cc" | ||
119 | ); | 121 | ); |
120 | } else | 122 | } else |
121 | #endif | 123 | #endif |
122 | __do_IRQ(irq, regs); | 124 | desc->handle_irq(irq, desc, regs); |
123 | 125 | ||
124 | irq_exit(); | 126 | irq_exit(); |
125 | 127 | ||
@@ -253,7 +255,8 @@ int show_interrupts(struct seq_file *p, void *v) | |||
253 | for_each_online_cpu(j) | 255 | for_each_online_cpu(j) |
254 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | 256 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); |
255 | #endif | 257 | #endif |
256 | seq_printf(p, " %14s", irq_desc[i].chip->typename); | 258 | seq_printf(p, " %8s", irq_desc[i].chip->name); |
259 | seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); | ||
257 | seq_printf(p, " %s", action->name); | 260 | seq_printf(p, " %s", action->name); |
258 | 261 | ||
259 | for (action=action->next; action; action = action->next) | 262 | for (action=action->next; action; action = action->next) |
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c index 4a8995c9c762..47f02af74be3 100644 --- a/arch/i386/pci/irq.c +++ b/arch/i386/pci/irq.c | |||
@@ -981,10 +981,6 @@ static void __init pcibios_fixup_irqs(void) | |||
981 | pci_name(bridge), 'A' + pin, irq); | 981 | pci_name(bridge), 'A' + pin, irq); |
982 | } | 982 | } |
983 | if (irq >= 0) { | 983 | if (irq >= 0) { |
984 | if (use_pci_vector() && | ||
985 | !platform_legacy_irq(irq)) | ||
986 | irq = IO_APIC_VECTOR(irq); | ||
987 | |||
988 | printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", | 984 | printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n", |
989 | pci_name(dev), 'A' + pin, irq); | 985 | pci_name(dev), 'A' + pin, irq); |
990 | dev->irq = irq; | 986 | dev->irq = irq; |
@@ -1169,33 +1165,3 @@ static int pirq_enable_irq(struct pci_dev *dev) | |||
1169 | } | 1165 | } |
1170 | return 0; | 1166 | return 0; |
1171 | } | 1167 | } |
1172 | |||
1173 | int pci_vector_resources(int last, int nr_released) | ||
1174 | { | ||
1175 | int count = nr_released; | ||
1176 | |||
1177 | int next = last; | ||
1178 | int offset = (last % 8); | ||
1179 | |||
1180 | while (next < FIRST_SYSTEM_VECTOR) { | ||
1181 | next += 8; | ||
1182 | #ifdef CONFIG_X86_64 | ||
1183 | if (next == IA32_SYSCALL_VECTOR) | ||
1184 | continue; | ||
1185 | #else | ||
1186 | if (next == SYSCALL_VECTOR) | ||
1187 | continue; | ||
1188 | #endif | ||
1189 | count++; | ||
1190 | if (next >= FIRST_SYSTEM_VECTOR) { | ||
1191 | if (offset%8) { | ||
1192 | next = FIRST_DEVICE_VECTOR + offset; | ||
1193 | offset++; | ||
1194 | continue; | ||
1195 | } | ||
1196 | count--; | ||
1197 | } | ||
1198 | } | ||
1199 | |||
1200 | return count; | ||
1201 | } | ||
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 31497496eb4b..cfa099b04cda 100644 --- a/arch/ia64/kernel/Makefile +++ b/arch/ia64/kernel/Makefile | |||
@@ -30,6 +30,7 @@ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o | |||
30 | obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o | 30 | obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o |
31 | obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o | 31 | obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o |
32 | obj-$(CONFIG_AUDIT) += audit.o | 32 | obj-$(CONFIG_AUDIT) += audit.o |
33 | obj-$(CONFIG_PCI_MSI) += msi_ia64.o | ||
33 | mca_recovery-y += mca_drv.o mca_drv_asm.o | 34 | mca_recovery-y += mca_drv.o mca_drv_asm.o |
34 | 35 | ||
35 | obj-$(CONFIG_IA64_ESI) += esi.o | 36 | obj-$(CONFIG_IA64_ESI) += esi.o |
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index aafca18ab33b..ab2d19c3661f 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
31 | #include <linux/threads.h> | 31 | #include <linux/threads.h> |
32 | #include <linux/bitops.h> | 32 | #include <linux/bitops.h> |
33 | #include <linux/irq.h> | ||
33 | 34 | ||
34 | #include <asm/delay.h> | 35 | #include <asm/delay.h> |
35 | #include <asm/intrinsics.h> | 36 | #include <asm/intrinsics.h> |
@@ -105,6 +106,25 @@ reserve_irq_vector (int vector) | |||
105 | return test_and_set_bit(pos, ia64_vector_mask); | 106 | return test_and_set_bit(pos, ia64_vector_mask); |
106 | } | 107 | } |
107 | 108 | ||
109 | /* | ||
110 | * Dynamic irq allocate and deallocation for MSI | ||
111 | */ | ||
112 | int create_irq(void) | ||
113 | { | ||
114 | int vector = assign_irq_vector(AUTO_ASSIGN); | ||
115 | |||
116 | if (vector >= 0) | ||
117 | dynamic_irq_init(vector); | ||
118 | |||
119 | return vector; | ||
120 | } | ||
121 | |||
122 | void destroy_irq(unsigned int irq) | ||
123 | { | ||
124 | dynamic_irq_cleanup(irq); | ||
125 | free_irq_vector(irq); | ||
126 | } | ||
127 | |||
108 | #ifdef CONFIG_SMP | 128 | #ifdef CONFIG_SMP |
109 | # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE) | 129 | # define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE) |
110 | #else | 130 | #else |
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c new file mode 100644 index 000000000000..822e59a1b822 --- /dev/null +++ b/arch/ia64/kernel/msi_ia64.c | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * MSI hooks for standard x86 apic | ||
3 | */ | ||
4 | |||
5 | #include <linux/pci.h> | ||
6 | #include <linux/irq.h> | ||
7 | #include <linux/msi.h> | ||
8 | #include <asm/smp.h> | ||
9 | |||
10 | /* | ||
11 | * Shifts for APIC-based data | ||
12 | */ | ||
13 | |||
14 | #define MSI_DATA_VECTOR_SHIFT 0 | ||
15 | #define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT) | ||
16 | |||
17 | #define MSI_DATA_DELIVERY_SHIFT 8 | ||
18 | #define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT) | ||
19 | #define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT) | ||
20 | |||
21 | #define MSI_DATA_LEVEL_SHIFT 14 | ||
22 | #define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT) | ||
23 | #define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT) | ||
24 | |||
25 | #define MSI_DATA_TRIGGER_SHIFT 15 | ||
26 | #define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT) | ||
27 | #define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT) | ||
28 | |||
29 | /* | ||
30 | * Shift/mask fields for APIC-based bus address | ||
31 | */ | ||
32 | |||
33 | #define MSI_TARGET_CPU_SHIFT 4 | ||
34 | #define MSI_ADDR_HEADER 0xfee00000 | ||
35 | |||
36 | #define MSI_ADDR_DESTID_MASK 0xfff0000f | ||
37 | #define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT) | ||
38 | |||
39 | #define MSI_ADDR_DESTMODE_SHIFT 2 | ||
40 | #define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT) | ||
41 | #define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT) | ||
42 | |||
43 | #define MSI_ADDR_REDIRECTION_SHIFT 3 | ||
44 | #define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) | ||
45 | #define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) | ||
46 | |||
47 | static struct irq_chip ia64_msi_chip; | ||
48 | |||
49 | #ifdef CONFIG_SMP | ||
50 | static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask) | ||
51 | { | ||
52 | struct msi_msg msg; | ||
53 | u32 addr; | ||
54 | |||
55 | read_msi_msg(irq, &msg); | ||
56 | |||
57 | addr = msg.address_lo; | ||
58 | addr &= MSI_ADDR_DESTID_MASK; | ||
59 | addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask))); | ||
60 | msg.address_lo = addr; | ||
61 | |||
62 | write_msi_msg(irq, &msg); | ||
63 | set_native_irq_info(irq, cpu_mask); | ||
64 | } | ||
65 | #endif /* CONFIG_SMP */ | ||
66 | |||
67 | int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) | ||
68 | { | ||
69 | struct msi_msg msg; | ||
70 | unsigned long dest_phys_id; | ||
71 | unsigned int vector; | ||
72 | |||
73 | dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map)); | ||
74 | vector = irq; | ||
75 | |||
76 | msg.address_hi = 0; | ||
77 | msg.address_lo = | ||
78 | MSI_ADDR_HEADER | | ||
79 | MSI_ADDR_DESTMODE_PHYS | | ||
80 | MSI_ADDR_REDIRECTION_CPU | | ||
81 | MSI_ADDR_DESTID_CPU(dest_phys_id); | ||
82 | |||
83 | msg.data = | ||
84 | MSI_DATA_TRIGGER_EDGE | | ||
85 | MSI_DATA_LEVEL_ASSERT | | ||
86 | MSI_DATA_DELIVERY_FIXED | | ||
87 | MSI_DATA_VECTOR(vector); | ||
88 | |||
89 | write_msi_msg(irq, &msg); | ||
90 | set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq); | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | void ia64_teardown_msi_irq(unsigned int irq) | ||
96 | { | ||
97 | return; /* no-op */ | ||
98 | } | ||
99 | |||
100 | static void ia64_ack_msi_irq(unsigned int irq) | ||
101 | { | ||
102 | move_native_irq(irq); | ||
103 | ia64_eoi(); | ||
104 | } | ||
105 | |||
106 | static int ia64_msi_retrigger_irq(unsigned int irq) | ||
107 | { | ||
108 | unsigned int vector = irq; | ||
109 | ia64_resend_irq(vector); | ||
110 | |||
111 | return 1; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Generic ops used on most IA64 platforms. | ||
116 | */ | ||
117 | static struct irq_chip ia64_msi_chip = { | ||
118 | .name = "PCI-MSI", | ||
119 | .mask = mask_msi_irq, | ||
120 | .unmask = unmask_msi_irq, | ||
121 | .ack = ia64_ack_msi_irq, | ||
122 | #ifdef CONFIG_SMP | ||
123 | .set_affinity = ia64_set_msi_irq_affinity, | ||
124 | #endif | ||
125 | .retrigger = ia64_msi_retrigger_irq, | ||
126 | }; | ||
127 | |||
128 | |||
129 | int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) | ||
130 | { | ||
131 | if (platform_setup_msi_irq) | ||
132 | return platform_setup_msi_irq(irq, pdev); | ||
133 | |||
134 | return ia64_setup_msi_irq(irq, pdev); | ||
135 | } | ||
136 | |||
137 | void arch_teardown_msi_irq(unsigned int irq) | ||
138 | { | ||
139 | if (platform_teardown_msi_irq) | ||
140 | return platform_teardown_msi_irq(irq); | ||
141 | |||
142 | return ia64_teardown_msi_irq(irq); | ||
143 | } | ||
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 15c7c670da39..b30be7c48ba8 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
@@ -810,12 +810,3 @@ pcibios_prep_mwi (struct pci_dev *dev) | |||
810 | } | 810 | } |
811 | return rc; | 811 | return rc; |
812 | } | 812 | } |
813 | |||
814 | int pci_vector_resources(int last, int nr_released) | ||
815 | { | ||
816 | int count = nr_released; | ||
817 | |||
818 | count += (IA64_LAST_DEVICE_VECTOR - last); | ||
819 | |||
820 | return count; | ||
821 | } | ||
diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile index ab9c48c88012..2d78f34dd763 100644 --- a/arch/ia64/sn/kernel/Makefile +++ b/arch/ia64/sn/kernel/Makefile | |||
@@ -19,3 +19,4 @@ xp-y := xp_main.o xp_nofault.o | |||
19 | obj-$(CONFIG_IA64_SGI_SN_XP) += xpc.o | 19 | obj-$(CONFIG_IA64_SGI_SN_XP) += xpc.o |
20 | xpc-y := xpc_main.o xpc_channel.o xpc_partition.o | 20 | xpc-y := xpc_main.o xpc_channel.o xpc_partition.o |
21 | obj-$(CONFIG_IA64_SGI_SN_XP) += xpnet.o | 21 | obj-$(CONFIG_IA64_SGI_SN_XP) += xpnet.o |
22 | obj-$(CONFIG_PCI_MSI) += msi_sn.o | ||
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c new file mode 100644 index 000000000000..6ffd1f850d41 --- /dev/null +++ b/arch/ia64/sn/kernel/msi_sn.c | |||
@@ -0,0 +1,230 @@ | |||
1 | /* | ||
2 | * This file is subject to the terms and conditions of the GNU General Public | ||
3 | * License. See the file "COPYING" in the main directory of this archive | ||
4 | * for more details. | ||
5 | * | ||
6 | * Copyright (C) 2006 Silicon Graphics, Inc. All Rights Reserved. | ||
7 | */ | ||
8 | |||
9 | #include <linux/types.h> | ||
10 | #include <linux/irq.h> | ||
11 | #include <linux/pci.h> | ||
12 | #include <linux/cpumask.h> | ||
13 | #include <linux/msi.h> | ||
14 | |||
15 | #include <asm/sn/addrs.h> | ||
16 | #include <asm/sn/intr.h> | ||
17 | #include <asm/sn/pcibus_provider_defs.h> | ||
18 | #include <asm/sn/pcidev.h> | ||
19 | #include <asm/sn/nodepda.h> | ||
20 | |||
21 | struct sn_msi_info { | ||
22 | u64 pci_addr; | ||
23 | struct sn_irq_info *sn_irq_info; | ||
24 | }; | ||
25 | |||
26 | static struct sn_msi_info sn_msi_info[NR_IRQS]; | ||
27 | |||
28 | static struct irq_chip sn_msi_chip; | ||
29 | |||
30 | void sn_teardown_msi_irq(unsigned int irq) | ||
31 | { | ||
32 | nasid_t nasid; | ||
33 | int widget; | ||
34 | struct pci_dev *pdev; | ||
35 | struct pcidev_info *sn_pdev; | ||
36 | struct sn_irq_info *sn_irq_info; | ||
37 | struct pcibus_bussoft *bussoft; | ||
38 | struct sn_pcibus_provider *provider; | ||
39 | |||
40 | sn_irq_info = sn_msi_info[irq].sn_irq_info; | ||
41 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
42 | return; | ||
43 | |||
44 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
45 | pdev = sn_pdev->pdi_linux_pcidev; | ||
46 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
47 | |||
48 | (*provider->dma_unmap)(pdev, | ||
49 | sn_msi_info[irq].pci_addr, | ||
50 | PCI_DMA_FROMDEVICE); | ||
51 | sn_msi_info[irq].pci_addr = 0; | ||
52 | |||
53 | bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
54 | nasid = NASID_GET(bussoft->bs_base); | ||
55 | widget = (nasid & 1) ? | ||
56 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
57 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
58 | |||
59 | sn_intr_free(nasid, widget, sn_irq_info); | ||
60 | sn_msi_info[irq].sn_irq_info = NULL; | ||
61 | |||
62 | return; | ||
63 | } | ||
64 | |||
65 | int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev) | ||
66 | { | ||
67 | struct msi_msg msg; | ||
68 | struct msi_desc *entry; | ||
69 | int widget; | ||
70 | int status; | ||
71 | nasid_t nasid; | ||
72 | u64 bus_addr; | ||
73 | struct sn_irq_info *sn_irq_info; | ||
74 | struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev); | ||
75 | struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
76 | |||
77 | entry = get_irq_data(irq); | ||
78 | if (!entry->msi_attrib.is_64) | ||
79 | return -EINVAL; | ||
80 | |||
81 | if (bussoft == NULL) | ||
82 | return -EINVAL; | ||
83 | |||
84 | if (provider == NULL || provider->dma_map_consistent == NULL) | ||
85 | return -EINVAL; | ||
86 | |||
87 | /* | ||
88 | * Set up the vector plumbing. Let the prom (via sn_intr_alloc) | ||
89 | * decide which cpu to direct this msi at by default. | ||
90 | */ | ||
91 | |||
92 | nasid = NASID_GET(bussoft->bs_base); | ||
93 | widget = (nasid & 1) ? | ||
94 | TIO_SWIN_WIDGETNUM(bussoft->bs_base) : | ||
95 | SWIN_WIDGETNUM(bussoft->bs_base); | ||
96 | |||
97 | sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL); | ||
98 | if (! sn_irq_info) | ||
99 | return -ENOMEM; | ||
100 | |||
101 | status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1); | ||
102 | if (status) { | ||
103 | kfree(sn_irq_info); | ||
104 | return -ENOMEM; | ||
105 | } | ||
106 | |||
107 | sn_irq_info->irq_int_bit = -1; /* mark this as an MSI irq */ | ||
108 | sn_irq_fixup(pdev, sn_irq_info); | ||
109 | |||
110 | /* Prom probably should fill these in, but doesn't ... */ | ||
111 | sn_irq_info->irq_bridge_type = bussoft->bs_asic_type; | ||
112 | sn_irq_info->irq_bridge = (void *)bussoft->bs_base; | ||
113 | |||
114 | /* | ||
115 | * Map the xio address into bus space | ||
116 | */ | ||
117 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
118 | sn_irq_info->irq_xtalkaddr, | ||
119 | sizeof(sn_irq_info->irq_xtalkaddr), | ||
120 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
121 | if (! bus_addr) { | ||
122 | sn_intr_free(nasid, widget, sn_irq_info); | ||
123 | kfree(sn_irq_info); | ||
124 | return -ENOMEM; | ||
125 | } | ||
126 | |||
127 | sn_msi_info[irq].sn_irq_info = sn_irq_info; | ||
128 | sn_msi_info[irq].pci_addr = bus_addr; | ||
129 | |||
130 | msg.address_hi = (u32)(bus_addr >> 32); | ||
131 | msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
132 | |||
133 | /* | ||
134 | * In the SN platform, bit 16 is a "send vector" bit which | ||
135 | * must be present in order to move the vector through the system. | ||
136 | */ | ||
137 | msg.data = 0x100 + irq; | ||
138 | |||
139 | #ifdef CONFIG_SMP | ||
140 | set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0); | ||
141 | #endif | ||
142 | |||
143 | write_msi_msg(irq, &msg); | ||
144 | set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | #ifdef CONFIG_SMP | ||
150 | static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask) | ||
151 | { | ||
152 | struct msi_msg msg; | ||
153 | int slice; | ||
154 | nasid_t nasid; | ||
155 | u64 bus_addr; | ||
156 | struct pci_dev *pdev; | ||
157 | struct pcidev_info *sn_pdev; | ||
158 | struct sn_irq_info *sn_irq_info; | ||
159 | struct sn_irq_info *new_irq_info; | ||
160 | struct sn_pcibus_provider *provider; | ||
161 | unsigned int cpu; | ||
162 | |||
163 | cpu = first_cpu(cpu_mask); | ||
164 | sn_irq_info = sn_msi_info[irq].sn_irq_info; | ||
165 | if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0) | ||
166 | return; | ||
167 | |||
168 | /* | ||
169 | * Release XIO resources for the old MSI PCI address | ||
170 | */ | ||
171 | |||
172 | read_msi_msg(irq, &msg); | ||
173 | sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo; | ||
174 | pdev = sn_pdev->pdi_linux_pcidev; | ||
175 | provider = SN_PCIDEV_BUSPROVIDER(pdev); | ||
176 | |||
177 | bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo); | ||
178 | (*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE); | ||
179 | sn_msi_info[irq].pci_addr = 0; | ||
180 | |||
181 | nasid = cpuid_to_nasid(cpu); | ||
182 | slice = cpuid_to_slice(cpu); | ||
183 | |||
184 | new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice); | ||
185 | sn_msi_info[irq].sn_irq_info = new_irq_info; | ||
186 | if (new_irq_info == NULL) | ||
187 | return; | ||
188 | |||
189 | /* | ||
190 | * Map the xio address into bus space | ||
191 | */ | ||
192 | |||
193 | bus_addr = (*provider->dma_map_consistent)(pdev, | ||
194 | new_irq_info->irq_xtalkaddr, | ||
195 | sizeof(new_irq_info->irq_xtalkaddr), | ||
196 | SN_DMA_MSI|SN_DMA_ADDR_XIO); | ||
197 | |||
198 | sn_msi_info[irq].pci_addr = bus_addr; | ||
199 | msg.address_hi = (u32)(bus_addr >> 32); | ||
200 | msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff); | ||
201 | |||
202 | write_msi_msg(irq, &msg); | ||
203 | set_native_irq_info(irq, cpu_mask); | ||
204 | } | ||
205 | #endif /* CONFIG_SMP */ | ||
206 | |||
207 | static void sn_ack_msi_irq(unsigned int irq) | ||
208 | { | ||
209 | move_native_irq(irq); | ||
210 | ia64_eoi(); | ||
211 | } | ||
212 | |||
213 | static int sn_msi_retrigger_irq(unsigned int irq) | ||
214 | { | ||
215 | unsigned int vector = irq; | ||
216 | ia64_resend_irq(vector); | ||
217 | |||
218 | return 1; | ||
219 | } | ||
220 | |||
221 | static struct irq_chip sn_msi_chip = { | ||
222 | .name = "PCI-MSI", | ||
223 | .mask = mask_msi_irq, | ||
224 | .unmask = unmask_msi_irq, | ||
225 | .ack = sn_ack_msi_irq, | ||
226 | #ifdef CONFIG_SMP | ||
227 | .set_affinity = sn_set_msi_irq_affinity, | ||
228 | #endif | ||
229 | .retrigger = sn_msi_retrigger_irq, | ||
230 | }; | ||
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 6dd0ea8f88e0..d2101237442e 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -127,7 +127,7 @@ config PA11 | |||
127 | 127 | ||
128 | config PREFETCH | 128 | config PREFETCH |
129 | def_bool y | 129 | def_bool y |
130 | depends on PA8X00 | 130 | depends on PA8X00 || PA7200 |
131 | 131 | ||
132 | config 64BIT | 132 | config 64BIT |
133 | bool "64-bit kernel" | 133 | bool "64-bit kernel" |
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c index 6e79dbf3f6bd..2d58b92b57e3 100644 --- a/arch/parisc/hpux/fs.c +++ b/arch/parisc/hpux/fs.c | |||
@@ -96,7 +96,7 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset, | |||
96 | put_user(namlen, &dirent->d_namlen); | 96 | put_user(namlen, &dirent->d_namlen); |
97 | copy_to_user(dirent->d_name, name, namlen); | 97 | copy_to_user(dirent->d_name, name, namlen); |
98 | put_user(0, dirent->d_name + namlen); | 98 | put_user(0, dirent->d_name + namlen); |
99 | ((char *) dirent) += reclen; | 99 | dirent = (void __user *)dirent + reclen; |
100 | buf->current_dir = dirent; | 100 | buf->current_dir = dirent; |
101 | buf->count -= reclen; | 101 | buf->count -= reclen; |
102 | return 0; | 102 | return 0; |
diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c index d1833f164bbe..1e64e7b88110 100644 --- a/arch/parisc/kernel/binfmt_elf32.c +++ b/arch/parisc/kernel/binfmt_elf32.c | |||
@@ -87,7 +87,7 @@ struct elf_prpsinfo32 | |||
87 | */ | 87 | */ |
88 | 88 | ||
89 | #define SET_PERSONALITY(ex, ibcs2) \ | 89 | #define SET_PERSONALITY(ex, ibcs2) \ |
90 | current->personality = PER_LINUX32; \ | 90 | set_thread_flag(TIF_32BIT); \ |
91 | current->thread.map_base = DEFAULT_MAP_BASE32; \ | 91 | current->thread.map_base = DEFAULT_MAP_BASE32; \ |
92 | current->thread.task_size = DEFAULT_TASK_SIZE32 \ | 92 | current->thread.task_size = DEFAULT_TASK_SIZE32 \ |
93 | 93 | ||
@@ -102,25 +102,3 @@ cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) | |||
102 | } | 102 | } |
103 | 103 | ||
104 | #include "../../../fs/binfmt_elf.c" | 104 | #include "../../../fs/binfmt_elf.c" |
105 | |||
106 | /* Set up a separate execution domain for ELF32 binaries running | ||
107 | * on an ELF64 kernel */ | ||
108 | |||
109 | static struct exec_domain parisc32_exec_domain = { | ||
110 | .name = "Linux/ELF32", | ||
111 | .pers_low = PER_LINUX32, | ||
112 | .pers_high = PER_LINUX32, | ||
113 | }; | ||
114 | |||
115 | static int __init parisc32_exec_init(void) | ||
116 | { | ||
117 | /* steal the identity signal mappings from the default domain */ | ||
118 | parisc32_exec_domain.signal_map = default_exec_domain.signal_map; | ||
119 | parisc32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; | ||
120 | |||
121 | register_exec_domain(&parisc32_exec_domain); | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | __initcall(parisc32_exec_init); | ||
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index bc7c4a4e26a1..0be51e92a2fc 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c | |||
@@ -35,15 +35,12 @@ int icache_stride __read_mostly; | |||
35 | EXPORT_SYMBOL(dcache_stride); | 35 | EXPORT_SYMBOL(dcache_stride); |
36 | 36 | ||
37 | 37 | ||
38 | #if defined(CONFIG_SMP) | ||
39 | /* On some machines (e.g. ones with the Merced bus), there can be | 38 | /* On some machines (e.g. ones with the Merced bus), there can be |
40 | * only a single PxTLB broadcast at a time; this must be guaranteed | 39 | * only a single PxTLB broadcast at a time; this must be guaranteed |
41 | * by software. We put a spinlock around all TLB flushes to | 40 | * by software. We put a spinlock around all TLB flushes to |
42 | * ensure this. | 41 | * ensure this. |
43 | */ | 42 | */ |
44 | DEFINE_SPINLOCK(pa_tlb_lock); | 43 | DEFINE_SPINLOCK(pa_tlb_lock); |
45 | EXPORT_SYMBOL(pa_tlb_lock); | ||
46 | #endif | ||
47 | 44 | ||
48 | struct pdc_cache_info cache_info __read_mostly; | 45 | struct pdc_cache_info cache_info __read_mostly; |
49 | #ifndef CONFIG_PA20 | 46 | #ifndef CONFIG_PA20 |
@@ -91,7 +88,8 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) | |||
91 | 88 | ||
92 | flush_kernel_dcache_page(page); | 89 | flush_kernel_dcache_page(page); |
93 | clear_bit(PG_dcache_dirty, &page->flags); | 90 | clear_bit(PG_dcache_dirty, &page->flags); |
94 | } | 91 | } else if (parisc_requires_coherency()) |
92 | flush_kernel_dcache_page(page); | ||
95 | } | 93 | } |
96 | 94 | ||
97 | void | 95 | void |
@@ -370,3 +368,45 @@ void parisc_setup_cache_timing(void) | |||
370 | 368 | ||
371 | printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); | 369 | printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); |
372 | } | 370 | } |
371 | |||
372 | extern void purge_kernel_dcache_page(unsigned long); | ||
373 | extern void clear_user_page_asm(void *page, unsigned long vaddr); | ||
374 | |||
375 | void clear_user_page(void *page, unsigned long vaddr, struct page *pg) | ||
376 | { | ||
377 | purge_kernel_dcache_page((unsigned long)page); | ||
378 | purge_tlb_start(); | ||
379 | pdtlb_kernel(page); | ||
380 | purge_tlb_end(); | ||
381 | clear_user_page_asm(page, vaddr); | ||
382 | } | ||
383 | EXPORT_SYMBOL(clear_user_page); | ||
384 | |||
385 | void flush_kernel_dcache_page_addr(void *addr) | ||
386 | { | ||
387 | flush_kernel_dcache_page_asm(addr); | ||
388 | purge_tlb_start(); | ||
389 | pdtlb_kernel(addr); | ||
390 | purge_tlb_end(); | ||
391 | } | ||
392 | EXPORT_SYMBOL(flush_kernel_dcache_page_addr); | ||
393 | |||
394 | void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, | ||
395 | struct page *pg) | ||
396 | { | ||
397 | /* no coherency needed (all in kmap/kunmap) */ | ||
398 | copy_user_page_asm(vto, vfrom); | ||
399 | if (!parisc_requires_coherency()) | ||
400 | flush_kernel_dcache_page_asm(vto); | ||
401 | } | ||
402 | EXPORT_SYMBOL(copy_user_page); | ||
403 | |||
404 | #ifdef CONFIG_PA8X00 | ||
405 | |||
406 | void kunmap_parisc(void *addr) | ||
407 | { | ||
408 | if (parisc_requires_coherency()) | ||
409 | flush_kernel_dcache_page_addr(addr); | ||
410 | } | ||
411 | EXPORT_SYMBOL(kunmap_parisc); | ||
412 | #endif | ||
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 192357a3b9fe..340b5e8d67ba 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | 31 | ||
32 | #include <asm/psw.h> | 32 | #include <asm/psw.h> |
33 | #include <asm/cache.h> /* for L1_CACHE_SHIFT */ | ||
33 | #include <asm/assembly.h> /* for LDREG/STREG defines */ | 34 | #include <asm/assembly.h> /* for LDREG/STREG defines */ |
34 | #include <asm/pgtable.h> | 35 | #include <asm/pgtable.h> |
35 | #include <asm/signal.h> | 36 | #include <asm/signal.h> |
@@ -478,11 +479,7 @@ | |||
478 | bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault | 479 | bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault |
479 | DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */ | 480 | DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */ |
480 | copy \pmd,%r9 | 481 | copy \pmd,%r9 |
481 | #ifdef CONFIG_64BIT | 482 | SHLREG %r9,PxD_VALUE_SHIFT,\pmd |
482 | shld %r9,PxD_VALUE_SHIFT,\pmd | ||
483 | #else | ||
484 | shlw %r9,PxD_VALUE_SHIFT,\pmd | ||
485 | #endif | ||
486 | EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index | 483 | EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index |
487 | DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */ | 484 | DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */ |
488 | shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd | 485 | shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd |
@@ -970,11 +967,7 @@ intr_return: | |||
970 | /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount | 967 | /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount |
971 | ** irq_stat[] is defined using ____cacheline_aligned. | 968 | ** irq_stat[] is defined using ____cacheline_aligned. |
972 | */ | 969 | */ |
973 | #ifdef CONFIG_64BIT | 970 | SHLREG %r1,L1_CACHE_SHIFT,%r20 |
974 | shld %r1, 6, %r20 | ||
975 | #else | ||
976 | shlw %r1, 5, %r20 | ||
977 | #endif | ||
978 | add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ | 971 | add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ |
979 | #endif /* CONFIG_SMP */ | 972 | #endif /* CONFIG_SMP */ |
980 | 973 | ||
@@ -1076,7 +1069,7 @@ intr_do_preempt: | |||
1076 | BL preempt_schedule_irq, %r2 | 1069 | BL preempt_schedule_irq, %r2 |
1077 | nop | 1070 | nop |
1078 | 1071 | ||
1079 | b intr_restore /* ssm PSW_SM_I done by intr_restore */ | 1072 | b,n intr_restore /* ssm PSW_SM_I done by intr_restore */ |
1080 | #endif /* CONFIG_PREEMPT */ | 1073 | #endif /* CONFIG_PREEMPT */ |
1081 | 1074 | ||
1082 | .import do_signal,code | 1075 | .import do_signal,code |
@@ -2115,11 +2108,7 @@ syscall_check_bh: | |||
2115 | ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */ | 2108 | ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */ |
2116 | 2109 | ||
2117 | /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */ | 2110 | /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */ |
2118 | #ifdef CONFIG_64BIT | 2111 | SHLREG %r26,L1_CACHE_SHIFT,%r20 |
2119 | shld %r26, 6, %r20 | ||
2120 | #else | ||
2121 | shlw %r26, 5, %r20 | ||
2122 | #endif | ||
2123 | add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ | 2112 | add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ |
2124 | #endif /* CONFIG_SMP */ | 2113 | #endif /* CONFIG_SMP */ |
2125 | 2114 | ||
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c index 3058bffd8a2c..18ba4cb9159b 100644 --- a/arch/parisc/kernel/hardware.c +++ b/arch/parisc/kernel/hardware.c | |||
@@ -231,6 +231,7 @@ static struct hp_hardware hp_hardware_list[] __initdata = { | |||
231 | {HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"}, | 231 | {HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"}, |
232 | {HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"}, | 232 | {HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"}, |
233 | {HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"}, | 233 | {HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"}, |
234 | {HPHW_NPROC,0x5EB,0x4,0x91,"Perf/Leone 875 W2+"}, | ||
234 | {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"}, | 235 | {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"}, |
235 | {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"}, | 236 | {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"}, |
236 | {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"}, | 237 | {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"}, |
@@ -584,8 +585,10 @@ static struct hp_hardware hp_hardware_list[] __initdata = { | |||
584 | {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, | 585 | {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, |
585 | {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, | 586 | {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, |
586 | {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, | 587 | {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, |
588 | {HPHW_FABRIC, 0x005, 0x000AA, 0x80, "Keystone DNA Central Agent"}, | ||
587 | {HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"}, | 589 | {HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"}, |
588 | {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, | 590 | {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, |
591 | {HPHW_FABRIC, 0x005, 0x000AB, 0x00, "Keystone TOGO Fabric Crossbar"}, | ||
589 | {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, | 592 | {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, |
590 | {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, | 593 | {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, |
591 | {HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"}, | 594 | {HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"}, |
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 5b8803cc3d69..9bdd0197ceb7 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c | |||
@@ -45,6 +45,17 @@ extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *); | |||
45 | */ | 45 | */ |
46 | static volatile unsigned long cpu_eiem = 0; | 46 | static volatile unsigned long cpu_eiem = 0; |
47 | 47 | ||
48 | /* | ||
49 | ** ack bitmap ... habitually set to 1, but reset to zero | ||
50 | ** between ->ack() and ->end() of the interrupt to prevent | ||
51 | ** re-interruption of a processing interrupt. | ||
52 | */ | ||
53 | static volatile unsigned long global_ack_eiem = ~0UL; | ||
54 | /* | ||
55 | ** Local bitmap, same as above but for per-cpu interrupts | ||
56 | */ | ||
57 | static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL; | ||
58 | |||
48 | static void cpu_disable_irq(unsigned int irq) | 59 | static void cpu_disable_irq(unsigned int irq) |
49 | { | 60 | { |
50 | unsigned long eirr_bit = EIEM_MASK(irq); | 61 | unsigned long eirr_bit = EIEM_MASK(irq); |
@@ -62,13 +73,6 @@ static void cpu_enable_irq(unsigned int irq) | |||
62 | 73 | ||
63 | cpu_eiem |= eirr_bit; | 74 | cpu_eiem |= eirr_bit; |
64 | 75 | ||
65 | /* FIXME: while our interrupts aren't nested, we cannot reset | ||
66 | * the eiem mask if we're already in an interrupt. Once we | ||
67 | * implement nested interrupts, this can go away | ||
68 | */ | ||
69 | if (!in_interrupt()) | ||
70 | set_eiem(cpu_eiem); | ||
71 | |||
72 | /* This is just a simple NOP IPI. But what it does is cause | 76 | /* This is just a simple NOP IPI. But what it does is cause |
73 | * all the other CPUs to do a set_eiem(cpu_eiem) at the end | 77 | * all the other CPUs to do a set_eiem(cpu_eiem) at the end |
74 | * of the interrupt handler */ | 78 | * of the interrupt handler */ |
@@ -84,13 +88,45 @@ static unsigned int cpu_startup_irq(unsigned int irq) | |||
84 | void no_ack_irq(unsigned int irq) { } | 88 | void no_ack_irq(unsigned int irq) { } |
85 | void no_end_irq(unsigned int irq) { } | 89 | void no_end_irq(unsigned int irq) { } |
86 | 90 | ||
91 | void cpu_ack_irq(unsigned int irq) | ||
92 | { | ||
93 | unsigned long mask = EIEM_MASK(irq); | ||
94 | int cpu = smp_processor_id(); | ||
95 | |||
96 | /* Clear in EIEM so we can no longer process */ | ||
97 | if (CHECK_IRQ_PER_CPU(irq_desc[irq].status)) | ||
98 | per_cpu(local_ack_eiem, cpu) &= ~mask; | ||
99 | else | ||
100 | global_ack_eiem &= ~mask; | ||
101 | |||
102 | /* disable the interrupt */ | ||
103 | set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu)); | ||
104 | /* and now ack it */ | ||
105 | mtctl(mask, 23); | ||
106 | } | ||
107 | |||
108 | void cpu_end_irq(unsigned int irq) | ||
109 | { | ||
110 | unsigned long mask = EIEM_MASK(irq); | ||
111 | int cpu = smp_processor_id(); | ||
112 | |||
113 | /* set it in the eiems---it's no longer in process */ | ||
114 | if (CHECK_IRQ_PER_CPU(irq_desc[irq].status)) | ||
115 | per_cpu(local_ack_eiem, cpu) |= mask; | ||
116 | else | ||
117 | global_ack_eiem |= mask; | ||
118 | |||
119 | /* enable the interrupt */ | ||
120 | set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu)); | ||
121 | } | ||
122 | |||
87 | #ifdef CONFIG_SMP | 123 | #ifdef CONFIG_SMP |
88 | int cpu_check_affinity(unsigned int irq, cpumask_t *dest) | 124 | int cpu_check_affinity(unsigned int irq, cpumask_t *dest) |
89 | { | 125 | { |
90 | int cpu_dest; | 126 | int cpu_dest; |
91 | 127 | ||
92 | /* timer and ipi have to always be received on all CPUs */ | 128 | /* timer and ipi have to always be received on all CPUs */ |
93 | if (irq == TIMER_IRQ || irq == IPI_IRQ) { | 129 | if (CHECK_IRQ_PER_CPU(irq)) { |
94 | /* Bad linux design decision. The mask has already | 130 | /* Bad linux design decision. The mask has already |
95 | * been set; we must reset it */ | 131 | * been set; we must reset it */ |
96 | irq_desc[irq].affinity = CPU_MASK_ALL; | 132 | irq_desc[irq].affinity = CPU_MASK_ALL; |
@@ -119,8 +155,8 @@ static struct hw_interrupt_type cpu_interrupt_type = { | |||
119 | .shutdown = cpu_disable_irq, | 155 | .shutdown = cpu_disable_irq, |
120 | .enable = cpu_enable_irq, | 156 | .enable = cpu_enable_irq, |
121 | .disable = cpu_disable_irq, | 157 | .disable = cpu_disable_irq, |
122 | .ack = no_ack_irq, | 158 | .ack = cpu_ack_irq, |
123 | .end = no_end_irq, | 159 | .end = cpu_end_irq, |
124 | #ifdef CONFIG_SMP | 160 | #ifdef CONFIG_SMP |
125 | .set_affinity = cpu_set_affinity_irq, | 161 | .set_affinity = cpu_set_affinity_irq, |
126 | #endif | 162 | #endif |
@@ -209,7 +245,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
209 | ** Then use that to get the Transaction address and data. | 245 | ** Then use that to get the Transaction address and data. |
210 | */ | 246 | */ |
211 | 247 | ||
212 | int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data) | 248 | int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data) |
213 | { | 249 | { |
214 | if (irq_desc[irq].action) | 250 | if (irq_desc[irq].action) |
215 | return -EBUSY; | 251 | return -EBUSY; |
@@ -298,82 +334,69 @@ unsigned int txn_alloc_data(unsigned int virt_irq) | |||
298 | return virt_irq - CPU_IRQ_BASE; | 334 | return virt_irq - CPU_IRQ_BASE; |
299 | } | 335 | } |
300 | 336 | ||
337 | static inline int eirr_to_irq(unsigned long eirr) | ||
338 | { | ||
339 | #ifdef CONFIG_64BIT | ||
340 | int bit = fls64(eirr); | ||
341 | #else | ||
342 | int bit = fls(eirr); | ||
343 | #endif | ||
344 | return (BITS_PER_LONG - bit) + TIMER_IRQ; | ||
345 | } | ||
346 | |||
301 | /* ONLY called from entry.S:intr_extint() */ | 347 | /* ONLY called from entry.S:intr_extint() */ |
302 | void do_cpu_irq_mask(struct pt_regs *regs) | 348 | void do_cpu_irq_mask(struct pt_regs *regs) |
303 | { | 349 | { |
304 | unsigned long eirr_val; | 350 | unsigned long eirr_val; |
305 | 351 | int irq, cpu = smp_processor_id(); | |
306 | irq_enter(); | ||
307 | |||
308 | /* | ||
309 | * Don't allow TIMER or IPI nested interrupts. | ||
310 | * Allowing any single interrupt to nest can lead to that CPU | ||
311 | * handling interrupts with all enabled interrupts unmasked. | ||
312 | */ | ||
313 | set_eiem(0UL); | ||
314 | |||
315 | /* 1) only process IRQs that are enabled/unmasked (cpu_eiem) | ||
316 | * 2) We loop here on EIRR contents in order to avoid | ||
317 | * nested interrupts or having to take another interrupt | ||
318 | * when we could have just handled it right away. | ||
319 | */ | ||
320 | for (;;) { | ||
321 | unsigned long bit = (1UL << (BITS_PER_LONG - 1)); | ||
322 | unsigned int irq; | ||
323 | eirr_val = mfctl(23) & cpu_eiem; | ||
324 | if (!eirr_val) | ||
325 | break; | ||
326 | |||
327 | mtctl(eirr_val, 23); /* reset bits we are going to process */ | ||
328 | |||
329 | /* Work our way from MSb to LSb...same order we alloc EIRs */ | ||
330 | for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) { | ||
331 | #ifdef CONFIG_SMP | 352 | #ifdef CONFIG_SMP |
332 | cpumask_t dest = irq_desc[irq].affinity; | 353 | cpumask_t dest; |
333 | #endif | 354 | #endif |
334 | if (!(bit & eirr_val)) | ||
335 | continue; | ||
336 | 355 | ||
337 | /* clear bit in mask - can exit loop sooner */ | 356 | local_irq_disable(); |
338 | eirr_val &= ~bit; | 357 | irq_enter(); |
339 | 358 | ||
340 | #ifdef CONFIG_SMP | 359 | eirr_val = mfctl(23) & cpu_eiem & global_ack_eiem & |
341 | /* FIXME: because generic set affinity mucks | 360 | per_cpu(local_ack_eiem, cpu); |
342 | * with the affinity before sending it to us | 361 | if (!eirr_val) |
343 | * we can get the situation where the affinity is | 362 | goto set_out; |
344 | * wrong for our CPU type interrupts */ | 363 | irq = eirr_to_irq(eirr_val); |
345 | if (irq != TIMER_IRQ && irq != IPI_IRQ && | ||
346 | !cpu_isset(smp_processor_id(), dest)) { | ||
347 | int cpu = first_cpu(dest); | ||
348 | |||
349 | printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n", | ||
350 | irq, smp_processor_id(), cpu); | ||
351 | gsc_writel(irq + CPU_IRQ_BASE, | ||
352 | cpu_data[cpu].hpa); | ||
353 | continue; | ||
354 | } | ||
355 | #endif | ||
356 | 364 | ||
357 | __do_IRQ(irq, regs); | 365 | #ifdef CONFIG_SMP |
358 | } | 366 | dest = irq_desc[irq].affinity; |
367 | if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) && | ||
368 | !cpu_isset(smp_processor_id(), dest)) { | ||
369 | int cpu = first_cpu(dest); | ||
370 | |||
371 | printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n", | ||
372 | irq, smp_processor_id(), cpu); | ||
373 | gsc_writel(irq + CPU_IRQ_BASE, | ||
374 | cpu_data[cpu].hpa); | ||
375 | goto set_out; | ||
359 | } | 376 | } |
377 | #endif | ||
378 | __do_IRQ(irq, regs); | ||
360 | 379 | ||
361 | set_eiem(cpu_eiem); /* restore original mask */ | 380 | out: |
362 | irq_exit(); | 381 | irq_exit(); |
363 | } | 382 | return; |
364 | 383 | ||
384 | set_out: | ||
385 | set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu)); | ||
386 | goto out; | ||
387 | } | ||
365 | 388 | ||
366 | static struct irqaction timer_action = { | 389 | static struct irqaction timer_action = { |
367 | .handler = timer_interrupt, | 390 | .handler = timer_interrupt, |
368 | .name = "timer", | 391 | .name = "timer", |
369 | .flags = IRQF_DISABLED, | 392 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU, |
370 | }; | 393 | }; |
371 | 394 | ||
372 | #ifdef CONFIG_SMP | 395 | #ifdef CONFIG_SMP |
373 | static struct irqaction ipi_action = { | 396 | static struct irqaction ipi_action = { |
374 | .handler = ipi_interrupt, | 397 | .handler = ipi_interrupt, |
375 | .name = "IPI", | 398 | .name = "IPI", |
376 | .flags = IRQF_DISABLED, | 399 | .flags = IRQF_DISABLED | IRQF_PERCPU, |
377 | }; | 400 | }; |
378 | #endif | 401 | #endif |
379 | 402 | ||
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index 99d7fca93104..fb81e5687e7c 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c | |||
@@ -143,8 +143,9 @@ static int __init processor_probe(struct parisc_device *dev) | |||
143 | p = &cpu_data[cpuid]; | 143 | p = &cpu_data[cpuid]; |
144 | boot_cpu_data.cpu_count++; | 144 | boot_cpu_data.cpu_count++; |
145 | 145 | ||
146 | /* initialize counters */ | 146 | /* initialize counters - CPU 0 gets it_value set in time_init() */ |
147 | memset(p, 0, sizeof(struct cpuinfo_parisc)); | 147 | if (cpuid) |
148 | memset(p, 0, sizeof(struct cpuinfo_parisc)); | ||
148 | 149 | ||
149 | p->loops_per_jiffy = loops_per_jiffy; | 150 | p->loops_per_jiffy = loops_per_jiffy; |
150 | p->dev = dev; /* Save IODC data in case we need it */ | 151 | p->dev = dev; /* Save IODC data in case we need it */ |
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index bb83880c5ee3..ee6653edeb7a 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/stddef.h> | 26 | #include <linux/stddef.h> |
27 | #include <linux/compat.h> | 27 | #include <linux/compat.h> |
28 | #include <linux/elf.h> | 28 | #include <linux/elf.h> |
29 | #include <linux/personality.h> | ||
30 | #include <asm/ucontext.h> | 29 | #include <asm/ucontext.h> |
31 | #include <asm/rt_sigframe.h> | 30 | #include <asm/rt_sigframe.h> |
32 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
@@ -433,13 +432,13 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
433 | if (in_syscall) { | 432 | if (in_syscall) { |
434 | regs->gr[31] = haddr; | 433 | regs->gr[31] = haddr; |
435 | #ifdef __LP64__ | 434 | #ifdef __LP64__ |
436 | if (personality(current->personality) == PER_LINUX) | 435 | if (!test_thread_flag(TIF_32BIT)) |
437 | sigframe_size |= 1; | 436 | sigframe_size |= 1; |
438 | #endif | 437 | #endif |
439 | } else { | 438 | } else { |
440 | unsigned long psw = USER_PSW; | 439 | unsigned long psw = USER_PSW; |
441 | #ifdef __LP64__ | 440 | #ifdef __LP64__ |
442 | if (personality(current->personality) == PER_LINUX) | 441 | if (!test_thread_flag(TIF_32BIT)) |
443 | psw |= PSW_W; | 442 | psw |= PSW_W; |
444 | #endif | 443 | #endif |
445 | 444 | ||
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index 98e40959a564..faad338f310e 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c | |||
@@ -262,6 +262,9 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
262 | this_cpu, which); | 262 | this_cpu, which); |
263 | return IRQ_NONE; | 263 | return IRQ_NONE; |
264 | } /* Switch */ | 264 | } /* Switch */ |
265 | /* let in any pending interrupts */ | ||
266 | local_irq_enable(); | ||
267 | local_irq_disable(); | ||
265 | } /* while (ops) */ | 268 | } /* while (ops) */ |
266 | } | 269 | } |
267 | return IRQ_HANDLED; | 270 | return IRQ_HANDLED; |
@@ -430,8 +433,9 @@ smp_do_timer(struct pt_regs *regs) | |||
430 | static void __init | 433 | static void __init |
431 | smp_cpu_init(int cpunum) | 434 | smp_cpu_init(int cpunum) |
432 | { | 435 | { |
433 | extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */ | 436 | extern int init_per_cpu(int); /* arch/parisc/kernel/processor.c */ |
434 | extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */ | 437 | extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */ |
438 | extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */ | ||
435 | 439 | ||
436 | /* Set modes and Enable floating point coprocessor */ | 440 | /* Set modes and Enable floating point coprocessor */ |
437 | (void) init_per_cpu(cpunum); | 441 | (void) init_per_cpu(cpunum); |
@@ -457,6 +461,7 @@ smp_cpu_init(int cpunum) | |||
457 | enter_lazy_tlb(&init_mm, current); | 461 | enter_lazy_tlb(&init_mm, current); |
458 | 462 | ||
459 | init_IRQ(); /* make sure no IRQ's are enabled or pending */ | 463 | init_IRQ(); /* make sure no IRQ's are enabled or pending */ |
464 | start_cpu_itimer(); | ||
460 | } | 465 | } |
461 | 466 | ||
462 | 467 | ||
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 8b5df98e2b31..1db5588ceacf 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <linux/shm.h> | 31 | #include <linux/shm.h> |
32 | #include <linux/smp_lock.h> | 32 | #include <linux/smp_lock.h> |
33 | #include <linux/syscalls.h> | 33 | #include <linux/syscalls.h> |
34 | #include <linux/utsname.h> | ||
35 | #include <linux/personality.h> | ||
34 | 36 | ||
35 | int sys_pipe(int __user *fildes) | 37 | int sys_pipe(int __user *fildes) |
36 | { | 38 | { |
@@ -248,3 +250,46 @@ asmlinkage int sys_free_hugepages(unsigned long addr) | |||
248 | { | 250 | { |
249 | return -EINVAL; | 251 | return -EINVAL; |
250 | } | 252 | } |
253 | |||
254 | long parisc_personality(unsigned long personality) | ||
255 | { | ||
256 | long err; | ||
257 | |||
258 | if (personality(current->personality) == PER_LINUX32 | ||
259 | && personality == PER_LINUX) | ||
260 | personality = PER_LINUX32; | ||
261 | |||
262 | err = sys_personality(personality); | ||
263 | if (err == PER_LINUX32) | ||
264 | err = PER_LINUX; | ||
265 | |||
266 | return err; | ||
267 | } | ||
268 | |||
269 | static inline int override_machine(char __user *mach) { | ||
270 | #ifdef CONFIG_COMPAT | ||
271 | if (personality(current->personality) == PER_LINUX32) { | ||
272 | if (__put_user(0, mach + 6) || | ||
273 | __put_user(0, mach + 7)) | ||
274 | return -EFAULT; | ||
275 | } | ||
276 | |||
277 | return 0; | ||
278 | #else /*!CONFIG_COMPAT*/ | ||
279 | return 0; | ||
280 | #endif /*CONFIG_COMPAT*/ | ||
281 | } | ||
282 | |||
283 | long parisc_newuname(struct new_utsname __user *utsname) | ||
284 | { | ||
285 | int err = 0; | ||
286 | |||
287 | down_read(&uts_sem); | ||
288 | if (copy_to_user(utsname, &system_utsname, sizeof(*utsname))) | ||
289 | err = -EFAULT; | ||
290 | up_read(&uts_sem); | ||
291 | |||
292 | err = override_machine(utsname->machine); | ||
293 | |||
294 | return (long)err; | ||
295 | } | ||
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S index e27b432f90a8..701d66a596e8 100644 --- a/arch/parisc/kernel/syscall_table.S +++ b/arch/parisc/kernel/syscall_table.S | |||
@@ -132,7 +132,7 @@ | |||
132 | ENTRY_SAME(socketpair) | 132 | ENTRY_SAME(socketpair) |
133 | ENTRY_SAME(setpgid) | 133 | ENTRY_SAME(setpgid) |
134 | ENTRY_SAME(send) | 134 | ENTRY_SAME(send) |
135 | ENTRY_SAME(newuname) | 135 | ENTRY_OURS(newuname) |
136 | ENTRY_SAME(umask) /* 60 */ | 136 | ENTRY_SAME(umask) /* 60 */ |
137 | ENTRY_SAME(chroot) | 137 | ENTRY_SAME(chroot) |
138 | ENTRY_SAME(ustat) | 138 | ENTRY_SAME(ustat) |
@@ -221,7 +221,7 @@ | |||
221 | ENTRY_SAME(fchdir) | 221 | ENTRY_SAME(fchdir) |
222 | ENTRY_SAME(bdflush) | 222 | ENTRY_SAME(bdflush) |
223 | ENTRY_SAME(sysfs) /* 135 */ | 223 | ENTRY_SAME(sysfs) /* 135 */ |
224 | ENTRY_SAME(personality) | 224 | ENTRY_OURS(personality) |
225 | ENTRY_SAME(ni_syscall) /* for afs_syscall */ | 225 | ENTRY_SAME(ni_syscall) /* for afs_syscall */ |
226 | ENTRY_SAME(setfsuid) | 226 | ENTRY_SAME(setfsuid) |
227 | ENTRY_SAME(setfsgid) | 227 | ENTRY_SAME(setfsgid) |
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index ab641d67f551..b3496b592a2d 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c | |||
@@ -32,8 +32,7 @@ | |||
32 | 32 | ||
33 | #include <linux/timex.h> | 33 | #include <linux/timex.h> |
34 | 34 | ||
35 | static long clocktick __read_mostly; /* timer cycles per tick */ | 35 | static unsigned long clocktick __read_mostly; /* timer cycles per tick */ |
36 | static long halftick __read_mostly; | ||
37 | 36 | ||
38 | #ifdef CONFIG_SMP | 37 | #ifdef CONFIG_SMP |
39 | extern void smp_do_timer(struct pt_regs *regs); | 38 | extern void smp_do_timer(struct pt_regs *regs); |
@@ -41,46 +40,106 @@ extern void smp_do_timer(struct pt_regs *regs); | |||
41 | 40 | ||
42 | irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 41 | irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
43 | { | 42 | { |
44 | long now; | 43 | unsigned long now; |
45 | long next_tick; | 44 | unsigned long next_tick; |
46 | int nticks; | 45 | unsigned long cycles_elapsed; |
47 | int cpu = smp_processor_id(); | 46 | unsigned long cycles_remainder; |
47 | unsigned int cpu = smp_processor_id(); | ||
48 | |||
49 | /* gcc can optimize for "read-only" case with a local clocktick */ | ||
50 | unsigned long cpt = clocktick; | ||
48 | 51 | ||
49 | profile_tick(CPU_PROFILING, regs); | 52 | profile_tick(CPU_PROFILING, regs); |
50 | 53 | ||
51 | now = mfctl(16); | 54 | /* Initialize next_tick to the expected tick time. */ |
52 | /* initialize next_tick to time at last clocktick */ | ||
53 | next_tick = cpu_data[cpu].it_value; | 55 | next_tick = cpu_data[cpu].it_value; |
54 | 56 | ||
55 | /* since time passes between the interrupt and the mfctl() | 57 | /* Get current interval timer. |
56 | * above, it is never true that last_tick + clocktick == now. If we | 58 | * CR16 reads as 64 bits in CPU wide mode. |
57 | * never miss a clocktick, we could set next_tick = last_tick + clocktick | 59 | * CR16 reads as 32 bits in CPU narrow mode. |
58 | * but maybe we'll miss ticks, hence the loop. | ||
59 | * | ||
60 | * Variables are *signed*. | ||
61 | */ | 60 | */ |
61 | now = mfctl(16); | ||
62 | |||
63 | cycles_elapsed = now - next_tick; | ||
62 | 64 | ||
63 | nticks = 0; | 65 | if ((cycles_elapsed >> 5) < cpt) { |
64 | while((next_tick - now) < halftick) { | 66 | /* use "cheap" math (add/subtract) instead |
65 | next_tick += clocktick; | 67 | * of the more expensive div/mul method |
66 | nticks++; | 68 | */ |
69 | cycles_remainder = cycles_elapsed; | ||
70 | while (cycles_remainder > cpt) { | ||
71 | cycles_remainder -= cpt; | ||
72 | } | ||
73 | } else { | ||
74 | cycles_remainder = cycles_elapsed % cpt; | ||
67 | } | 75 | } |
68 | mtctl(next_tick, 16); | 76 | |
77 | /* Can we differentiate between "early CR16" (aka Scenario 1) and | ||
78 | * "long delay" (aka Scenario 3)? I don't think so. | ||
79 | * | ||
80 | * We expected timer_interrupt to be delivered at least a few hundred | ||
81 | * cycles after the IT fires. But it's arbitrary how much time passes | ||
82 | * before we call it "late". I've picked one second. | ||
83 | */ | ||
84 | /* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ | ||
85 | #if HZ == 1000 | ||
86 | if (cycles_elapsed > (cpt << 10) ) | ||
87 | #elif HZ == 250 | ||
88 | if (cycles_elapsed > (cpt << 8) ) | ||
89 | #elif HZ == 100 | ||
90 | if (cycles_elapsed > (cpt << 7) ) | ||
91 | #else | ||
92 | #warn WTF is HZ set to anyway? | ||
93 | if (cycles_elapsed > (HZ * cpt) ) | ||
94 | #endif | ||
95 | { | ||
96 | /* Scenario 3: very long delay? bad in any case */ | ||
97 | printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" | ||
98 | " cycles %lX rem %lX " | ||
99 | " next/now %lX/%lX\n", | ||
100 | cpu, | ||
101 | cycles_elapsed, cycles_remainder, | ||
102 | next_tick, now ); | ||
103 | } | ||
104 | |||
105 | /* convert from "division remainder" to "remainder of clock tick" */ | ||
106 | cycles_remainder = cpt - cycles_remainder; | ||
107 | |||
108 | /* Determine when (in CR16 cycles) next IT interrupt will fire. | ||
109 | * We want IT to fire modulo clocktick even if we miss/skip some. | ||
110 | * But those interrupts don't in fact get delivered that regularly. | ||
111 | */ | ||
112 | next_tick = now + cycles_remainder; | ||
113 | |||
69 | cpu_data[cpu].it_value = next_tick; | 114 | cpu_data[cpu].it_value = next_tick; |
70 | 115 | ||
71 | while (nticks--) { | 116 | /* Skip one clocktick on purpose if we are likely to miss next_tick. |
117 | * We want to avoid the new next_tick being less than CR16. | ||
118 | * If that happened, itimer wouldn't fire until CR16 wrapped. | ||
119 | * We'll catch the tick we missed on the tick after that. | ||
120 | */ | ||
121 | if (!(cycles_remainder >> 13)) | ||
122 | next_tick += cpt; | ||
123 | |||
124 | /* Program the IT when to deliver the next interrupt. */ | ||
125 | /* Only bottom 32-bits of next_tick are written to cr16. */ | ||
126 | mtctl(next_tick, 16); | ||
127 | |||
128 | |||
129 | /* Done mucking with unreliable delivery of interrupts. | ||
130 | * Go do system house keeping. | ||
131 | */ | ||
72 | #ifdef CONFIG_SMP | 132 | #ifdef CONFIG_SMP |
73 | smp_do_timer(regs); | 133 | smp_do_timer(regs); |
74 | #else | 134 | #else |
75 | update_process_times(user_mode(regs)); | 135 | update_process_times(user_mode(regs)); |
76 | #endif | 136 | #endif |
77 | if (cpu == 0) { | 137 | if (cpu == 0) { |
78 | write_seqlock(&xtime_lock); | 138 | write_seqlock(&xtime_lock); |
79 | do_timer(1); | 139 | do_timer(regs); |
80 | write_sequnlock(&xtime_lock); | 140 | write_sequnlock(&xtime_lock); |
81 | } | ||
82 | } | 141 | } |
83 | 142 | ||
84 | /* check soft power switch status */ | 143 | /* check soft power switch status */ |
85 | if (cpu == 0 && !atomic_read(&power_tasklet.count)) | 144 | if (cpu == 0 && !atomic_read(&power_tasklet.count)) |
86 | tasklet_schedule(&power_tasklet); | 145 | tasklet_schedule(&power_tasklet); |
@@ -106,14 +165,12 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
106 | EXPORT_SYMBOL(profile_pc); | 165 | EXPORT_SYMBOL(profile_pc); |
107 | 166 | ||
108 | 167 | ||
109 | /*** converted from ia64 ***/ | ||
110 | /* | 168 | /* |
111 | * Return the number of micro-seconds that elapsed since the last | 169 | * Return the number of micro-seconds that elapsed since the last |
112 | * update to wall time (aka xtime). The xtime_lock | 170 | * update to wall time (aka xtime). The xtime_lock |
113 | * must be at least read-locked when calling this routine. | 171 | * must be at least read-locked when calling this routine. |
114 | */ | 172 | */ |
115 | static inline unsigned long | 173 | static inline unsigned long gettimeoffset (void) |
116 | gettimeoffset (void) | ||
117 | { | 174 | { |
118 | #ifndef CONFIG_SMP | 175 | #ifndef CONFIG_SMP |
119 | /* | 176 | /* |
@@ -121,21 +178,44 @@ gettimeoffset (void) | |||
121 | * Once parisc-linux learns the cr16 difference between processors, | 178 | * Once parisc-linux learns the cr16 difference between processors, |
122 | * this could be made to work. | 179 | * this could be made to work. |
123 | */ | 180 | */ |
124 | long last_tick; | 181 | unsigned long now; |
125 | long elapsed_cycles; | 182 | unsigned long prev_tick; |
126 | 183 | unsigned long next_tick; | |
127 | /* it_value is the intended time of the next tick */ | 184 | unsigned long elapsed_cycles; |
128 | last_tick = cpu_data[smp_processor_id()].it_value; | 185 | unsigned long usec; |
129 | 186 | unsigned long cpuid = smp_processor_id(); | |
130 | /* Subtract one tick and account for possible difference between | 187 | unsigned long cpt = clocktick; |
131 | * when we expected the tick and when it actually arrived. | 188 | |
132 | * (aka wall vs real) | 189 | next_tick = cpu_data[cpuid].it_value; |
133 | */ | 190 | now = mfctl(16); /* Read the hardware interval timer. */ |
134 | last_tick -= clocktick * (jiffies - wall_jiffies + 1); | 191 | |
135 | elapsed_cycles = mfctl(16) - last_tick; | 192 | prev_tick = next_tick - cpt; |
193 | |||
194 | /* Assume Scenario 1: "now" is later than prev_tick. */ | ||
195 | elapsed_cycles = now - prev_tick; | ||
196 | |||
197 | /* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ | ||
198 | #if HZ == 1000 | ||
199 | if (elapsed_cycles > (cpt << 10) ) | ||
200 | #elif HZ == 250 | ||
201 | if (elapsed_cycles > (cpt << 8) ) | ||
202 | #elif HZ == 100 | ||
203 | if (elapsed_cycles > (cpt << 7) ) | ||
204 | #else | ||
205 | #warn WTF is HZ set to anyway? | ||
206 | if (elapsed_cycles > (HZ * cpt) ) | ||
207 | #endif | ||
208 | { | ||
209 | /* Scenario 3: clock ticks are missing. */ | ||
210 | printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!" | ||
211 | " cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n", | ||
212 | cpuid, elapsed_cycles / cpt, | ||
213 | elapsed_cycles, prev_tick, now, next_tick, cpt); | ||
214 | } | ||
136 | 215 | ||
137 | /* the precision of this math could be improved */ | 216 | /* FIXME: Can we improve the precision? Not with PAGE0. */ |
138 | return elapsed_cycles / (PAGE0->mem_10msec / 10000); | 217 | usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec; |
218 | return usec; | ||
139 | #else | 219 | #else |
140 | return 0; | 220 | return 0; |
141 | #endif | 221 | #endif |
@@ -146,6 +226,7 @@ do_gettimeofday (struct timeval *tv) | |||
146 | { | 226 | { |
147 | unsigned long flags, seq, usec, sec; | 227 | unsigned long flags, seq, usec, sec; |
148 | 228 | ||
229 | /* Hold xtime_lock and adjust timeval. */ | ||
149 | do { | 230 | do { |
150 | seq = read_seqbegin_irqsave(&xtime_lock, flags); | 231 | seq = read_seqbegin_irqsave(&xtime_lock, flags); |
151 | usec = gettimeoffset(); | 232 | usec = gettimeoffset(); |
@@ -153,25 +234,13 @@ do_gettimeofday (struct timeval *tv) | |||
153 | usec += (xtime.tv_nsec / 1000); | 234 | usec += (xtime.tv_nsec / 1000); |
154 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); | 235 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); |
155 | 236 | ||
156 | if (unlikely(usec > LONG_MAX)) { | 237 | /* Move adjusted usec's into sec's. */ |
157 | /* This can happen if the gettimeoffset adjustment is | ||
158 | * negative and xtime.tv_nsec is smaller than the | ||
159 | * adjustment */ | ||
160 | printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec); | ||
161 | usec += USEC_PER_SEC; | ||
162 | --sec; | ||
163 | /* This should never happen, it means the negative | ||
164 | * time adjustment was more than a second, so there's | ||
165 | * something seriously wrong */ | ||
166 | BUG_ON(usec > LONG_MAX); | ||
167 | } | ||
168 | |||
169 | |||
170 | while (usec >= USEC_PER_SEC) { | 238 | while (usec >= USEC_PER_SEC) { |
171 | usec -= USEC_PER_SEC; | 239 | usec -= USEC_PER_SEC; |
172 | ++sec; | 240 | ++sec; |
173 | } | 241 | } |
174 | 242 | ||
243 | /* Return adjusted result. */ | ||
175 | tv->tv_sec = sec; | 244 | tv->tv_sec = sec; |
176 | tv->tv_usec = usec; | 245 | tv->tv_usec = usec; |
177 | } | 246 | } |
@@ -223,22 +292,23 @@ unsigned long long sched_clock(void) | |||
223 | } | 292 | } |
224 | 293 | ||
225 | 294 | ||
295 | void __init start_cpu_itimer(void) | ||
296 | { | ||
297 | unsigned int cpu = smp_processor_id(); | ||
298 | unsigned long next_tick = mfctl(16) + clocktick; | ||
299 | |||
300 | mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */ | ||
301 | |||
302 | cpu_data[cpu].it_value = next_tick; | ||
303 | } | ||
304 | |||
226 | void __init time_init(void) | 305 | void __init time_init(void) |
227 | { | 306 | { |
228 | unsigned long next_tick; | ||
229 | static struct pdc_tod tod_data; | 307 | static struct pdc_tod tod_data; |
230 | 308 | ||
231 | clocktick = (100 * PAGE0->mem_10msec) / HZ; | 309 | clocktick = (100 * PAGE0->mem_10msec) / HZ; |
232 | halftick = clocktick / 2; | ||
233 | 310 | ||
234 | /* Setup clock interrupt timing */ | 311 | start_cpu_itimer(); /* get CPU 0 started */ |
235 | |||
236 | next_tick = mfctl(16); | ||
237 | next_tick += clocktick; | ||
238 | cpu_data[smp_processor_id()].it_value = next_tick; | ||
239 | |||
240 | /* kick off Itimer (CR16) */ | ||
241 | mtctl(next_tick, 16); | ||
242 | 312 | ||
243 | if(pdc_tod_read(&tod_data) == 0) { | 313 | if(pdc_tod_read(&tod_data) == 0) { |
244 | write_seqlock_irq(&xtime_lock); | 314 | write_seqlock_irq(&xtime_lock); |
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 77b28cb8aca6..65cd6ca32fed 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
17 | #include <linux/ptrace.h> | 17 | #include <linux/ptrace.h> |
18 | #include <linux/timer.h> | 18 | #include <linux/timer.h> |
19 | #include <linux/delay.h> | ||
19 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
20 | #include <linux/module.h> | 21 | #include <linux/module.h> |
21 | #include <linux/smp.h> | 22 | #include <linux/smp.h> |
@@ -245,6 +246,15 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) | |||
245 | current->comm, current->pid, str, err); | 246 | current->comm, current->pid, str, err); |
246 | show_regs(regs); | 247 | show_regs(regs); |
247 | 248 | ||
249 | if (in_interrupt()) | ||
250 | panic("Fatal exception in interrupt"); | ||
251 | |||
252 | if (panic_on_oops) { | ||
253 | printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); | ||
254 | ssleep(5); | ||
255 | panic("Fatal exception"); | ||
256 | } | ||
257 | |||
248 | /* Wot's wrong wif bein' racy? */ | 258 | /* Wot's wrong wif bein' racy? */ |
249 | if (current->thread.flags & PARISC_KERNEL_DEATH) { | 259 | if (current->thread.flags & PARISC_KERNEL_DEATH) { |
250 | printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__); | 260 | printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__); |
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 25ad28d63e88..0667f2b4f977 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c | |||
@@ -31,10 +31,7 @@ | |||
31 | 31 | ||
32 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); | 32 | DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); |
33 | 33 | ||
34 | extern char _text; /* start of kernel code, defined by linker */ | ||
35 | extern int data_start; | 34 | extern int data_start; |
36 | extern char _end; /* end of BSS, defined by linker */ | ||
37 | extern char __init_begin, __init_end; | ||
38 | 35 | ||
39 | #ifdef CONFIG_DISCONTIGMEM | 36 | #ifdef CONFIG_DISCONTIGMEM |
40 | struct node_map_data node_data[MAX_NUMNODES] __read_mostly; | 37 | struct node_map_data node_data[MAX_NUMNODES] __read_mostly; |
@@ -319,8 +316,8 @@ static void __init setup_bootmem(void) | |||
319 | 316 | ||
320 | reserve_bootmem_node(NODE_DATA(0), 0UL, | 317 | reserve_bootmem_node(NODE_DATA(0), 0UL, |
321 | (unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE)); | 318 | (unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE)); |
322 | reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text), | 319 | reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text), |
323 | (unsigned long)(&_end - &_text)); | 320 | (unsigned long)(_end - _text)); |
324 | reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT), | 321 | reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT), |
325 | ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT)); | 322 | ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT)); |
326 | 323 | ||
@@ -355,8 +352,8 @@ static void __init setup_bootmem(void) | |||
355 | #endif | 352 | #endif |
356 | 353 | ||
357 | data_resource.start = virt_to_phys(&data_start); | 354 | data_resource.start = virt_to_phys(&data_start); |
358 | data_resource.end = virt_to_phys(&_end)-1; | 355 | data_resource.end = virt_to_phys(_end) - 1; |
359 | code_resource.start = virt_to_phys(&_text); | 356 | code_resource.start = virt_to_phys(_text); |
360 | code_resource.end = virt_to_phys(&data_start)-1; | 357 | code_resource.end = virt_to_phys(&data_start)-1; |
361 | 358 | ||
362 | /* We don't know which region the kernel will be in, so try | 359 | /* We don't know which region the kernel will be in, so try |
@@ -385,12 +382,12 @@ void free_initmem(void) | |||
385 | */ | 382 | */ |
386 | local_irq_disable(); | 383 | local_irq_disable(); |
387 | 384 | ||
388 | memset(&__init_begin, 0x00, | 385 | memset(__init_begin, 0x00, |
389 | (unsigned long)&__init_end - (unsigned long)&__init_begin); | 386 | (unsigned long)__init_end - (unsigned long)__init_begin); |
390 | 387 | ||
391 | flush_data_cache(); | 388 | flush_data_cache(); |
392 | asm volatile("sync" : : ); | 389 | asm volatile("sync" : : ); |
393 | flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end); | 390 | flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end); |
394 | asm volatile("sync" : : ); | 391 | asm volatile("sync" : : ); |
395 | 392 | ||
396 | local_irq_enable(); | 393 | local_irq_enable(); |
@@ -398,8 +395,8 @@ void free_initmem(void) | |||
398 | 395 | ||
399 | /* align __init_begin and __init_end to page size, | 396 | /* align __init_begin and __init_end to page size, |
400 | ignoring linker script where we might have tried to save RAM */ | 397 | ignoring linker script where we might have tried to save RAM */ |
401 | init_begin = PAGE_ALIGN((unsigned long)(&__init_begin)); | 398 | init_begin = PAGE_ALIGN((unsigned long)(__init_begin)); |
402 | init_end = PAGE_ALIGN((unsigned long)(&__init_end)); | 399 | init_end = PAGE_ALIGN((unsigned long)(__init_end)); |
403 | for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) { | 400 | for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) { |
404 | ClearPageReserved(virt_to_page(addr)); | 401 | ClearPageReserved(virt_to_page(addr)); |
405 | init_page_count(virt_to_page(addr)); | 402 | init_page_count(virt_to_page(addr)); |
@@ -578,7 +575,7 @@ static void __init map_pages(unsigned long start_vaddr, unsigned long start_padd | |||
578 | extern const unsigned long fault_vector_20; | 575 | extern const unsigned long fault_vector_20; |
579 | extern void * const linux_gateway_page; | 576 | extern void * const linux_gateway_page; |
580 | 577 | ||
581 | ro_start = __pa((unsigned long)&_text); | 578 | ro_start = __pa((unsigned long)_text); |
582 | ro_end = __pa((unsigned long)&data_start); | 579 | ro_end = __pa((unsigned long)&data_start); |
583 | fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK; | 580 | fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK; |
584 | gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK; | 581 | gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK; |
diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c index 27384567a1d0..47a1d2ac9419 100644 --- a/arch/parisc/mm/ioremap.c +++ b/arch/parisc/mm/ioremap.c | |||
@@ -188,7 +188,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l | |||
188 | } | 188 | } |
189 | EXPORT_SYMBOL(__ioremap); | 189 | EXPORT_SYMBOL(__ioremap); |
190 | 190 | ||
191 | void iounmap(void __iomem *addr) | 191 | void iounmap(const volatile void __iomem *addr) |
192 | { | 192 | { |
193 | if (addr > high_memory) | 193 | if (addr > high_memory) |
194 | return vfree((void *) (PAGE_MASK & (unsigned long __force) addr)); | 194 | return vfree((void *) (PAGE_MASK & (unsigned long __force) addr)); |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 96ef656e4669..8b6910465578 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -338,10 +338,6 @@ config PPC_MULTIPLATFORM | |||
338 | RS/6000 machine, an Apple machine, or a PReP, CHRP, | 338 | RS/6000 machine, an Apple machine, or a PReP, CHRP, |
339 | Maple or Cell-based machine. | 339 | Maple or Cell-based machine. |
340 | 340 | ||
341 | config PPC_ISERIES | ||
342 | bool "IBM Legacy iSeries" | ||
343 | depends on PPC64 | ||
344 | |||
345 | config EMBEDDED6xx | 341 | config EMBEDDED6xx |
346 | bool "Embedded 6xx/7xx/7xxx-based board" | 342 | bool "Embedded 6xx/7xx/7xxx-based board" |
347 | depends on PPC32 && (BROKEN||BROKEN_ON_SMP) | 343 | depends on PPC32 && (BROKEN||BROKEN_ON_SMP) |
@@ -355,6 +351,16 @@ config APUS | |||
355 | <http://linux-apus.sourceforge.net/>. | 351 | <http://linux-apus.sourceforge.net/>. |
356 | endchoice | 352 | endchoice |
357 | 353 | ||
354 | config QUICC_ENGINE | ||
355 | bool | ||
356 | depends on PPC_MPC836x || PPC_MPC832x | ||
357 | default y | ||
358 | help | ||
359 | The QUICC Engine (QE) is a new generation of communications | ||
360 | coprocessors on Freescale embedded CPUs (akin to CPM in older chips). | ||
361 | Selecting this option means that you wish to build a kernel | ||
362 | for a machine with a QE coprocessor. | ||
363 | |||
358 | config PPC_PSERIES | 364 | config PPC_PSERIES |
359 | depends on PPC_MULTIPLATFORM && PPC64 | 365 | depends on PPC_MULTIPLATFORM && PPC64 |
360 | bool "IBM pSeries & new (POWER5-based) iSeries" | 366 | bool "IBM pSeries & new (POWER5-based) iSeries" |
@@ -365,6 +371,10 @@ config PPC_PSERIES | |||
365 | select PPC_UDBG_16550 | 371 | select PPC_UDBG_16550 |
366 | default y | 372 | default y |
367 | 373 | ||
374 | config PPC_ISERIES | ||
375 | bool "IBM Legacy iSeries" | ||
376 | depends on PPC_MULTIPLATFORM && PPC64 | ||
377 | |||
368 | config PPC_CHRP | 378 | config PPC_CHRP |
369 | bool "Common Hardware Reference Platform (CHRP) based machines" | 379 | bool "Common Hardware Reference Platform (CHRP) based machines" |
370 | depends on PPC_MULTIPLATFORM && PPC32 | 380 | depends on PPC_MULTIPLATFORM && PPC32 |
@@ -594,6 +604,7 @@ endmenu | |||
594 | 604 | ||
595 | source arch/powerpc/platforms/embedded6xx/Kconfig | 605 | source arch/powerpc/platforms/embedded6xx/Kconfig |
596 | source arch/powerpc/platforms/4xx/Kconfig | 606 | source arch/powerpc/platforms/4xx/Kconfig |
607 | source arch/powerpc/platforms/82xx/Kconfig | ||
597 | source arch/powerpc/platforms/83xx/Kconfig | 608 | source arch/powerpc/platforms/83xx/Kconfig |
598 | source arch/powerpc/platforms/85xx/Kconfig | 609 | source arch/powerpc/platforms/85xx/Kconfig |
599 | source arch/powerpc/platforms/86xx/Kconfig | 610 | source arch/powerpc/platforms/86xx/Kconfig |
@@ -1058,6 +1069,8 @@ source "fs/Kconfig" | |||
1058 | 1069 | ||
1059 | # XXX source "arch/ppc/8260_io/Kconfig" | 1070 | # XXX source "arch/ppc/8260_io/Kconfig" |
1060 | 1071 | ||
1072 | source "arch/powerpc/sysdev/qe_lib/Kconfig" | ||
1073 | |||
1061 | source "arch/powerpc/platforms/iseries/Kconfig" | 1074 | source "arch/powerpc/platforms/iseries/Kconfig" |
1062 | 1075 | ||
1063 | source "lib/Kconfig" | 1076 | source "lib/Kconfig" |
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index c383d56bbe18..003520b56303 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile | |||
@@ -113,7 +113,7 @@ endif | |||
113 | endif | 113 | endif |
114 | 114 | ||
115 | quiet_cmd_wrap = WRAP $@ | 115 | quiet_cmd_wrap = WRAP $@ |
116 | cmd_wrap =$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux | 116 | cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux |
117 | quiet_cmd_wrap_initrd = WRAP $@ | 117 | quiet_cmd_wrap_initrd = WRAP $@ |
118 | cmd_wrap_initrd =$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \ | 118 | cmd_wrap_initrd =$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \ |
119 | -i $(obj)/ramdisk.image.gz vmlinux | 119 | -i $(obj)/ramdisk.image.gz vmlinux |
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts new file mode 100644 index 000000000000..34efdd028c4f --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8272ads.dts | |||
@@ -0,0 +1,223 @@ | |||
1 | /* | ||
2 | * MPC8272 ADS Device Tree Source | ||
3 | * | ||
4 | * Copyright 2005 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | / { | ||
13 | model = "MPC8272ADS"; | ||
14 | compatible = "MPC8260ADS"; | ||
15 | #address-cells = <1>; | ||
16 | #size-cells = <1>; | ||
17 | linux,phandle = <100>; | ||
18 | |||
19 | cpus { | ||
20 | #cpus = <1>; | ||
21 | #address-cells = <1>; | ||
22 | #size-cells = <0>; | ||
23 | linux,phandle = <200>; | ||
24 | |||
25 | PowerPC,8272@0 { | ||
26 | device_type = "cpu"; | ||
27 | reg = <0>; | ||
28 | d-cache-line-size = <20>; // 32 bytes | ||
29 | i-cache-line-size = <20>; // 32 bytes | ||
30 | d-cache-size = <4000>; // L1, 16K | ||
31 | i-cache-size = <4000>; // L1, 16K | ||
32 | timebase-frequency = <0>; | ||
33 | bus-frequency = <0>; | ||
34 | clock-frequency = <0>; | ||
35 | 32-bit; | ||
36 | linux,phandle = <201>; | ||
37 | linux,boot-cpu; | ||
38 | }; | ||
39 | }; | ||
40 | |||
41 | interrupt-controller@f8200000 { | ||
42 | linux,phandle = <f8200000>; | ||
43 | #address-cells = <0>; | ||
44 | #interrupt-cells = <2>; | ||
45 | interrupt-controller; | ||
46 | reg = <f8200000 f8200004>; | ||
47 | built-in; | ||
48 | device_type = "pci-pic"; | ||
49 | }; | ||
50 | memory { | ||
51 | device_type = "memory"; | ||
52 | linux,phandle = <300>; | ||
53 | reg = <00000000 4000000 f4500000 00000020>; | ||
54 | }; | ||
55 | |||
56 | soc8272@f0000000 { | ||
57 | #address-cells = <1>; | ||
58 | #size-cells = <1>; | ||
59 | #interrupt-cells = <2>; | ||
60 | device_type = "soc"; | ||
61 | ranges = < 0 0 2 00000000 f0000000 00053000>; | ||
62 | reg = <f0000000 0>; | ||
63 | |||
64 | mdio@0 { | ||
65 | device_type = "mdio"; | ||
66 | compatible = "fs_enet"; | ||
67 | reg = <0 0>; | ||
68 | linux,phandle = <24520>; | ||
69 | #address-cells = <1>; | ||
70 | #size-cells = <0>; | ||
71 | ethernet-phy@0 { | ||
72 | linux,phandle = <2452000>; | ||
73 | interrupt-parent = <10c00>; | ||
74 | interrupts = <19 1>; | ||
75 | reg = <0>; | ||
76 | bitbang = [ 12 12 13 02 02 01 ]; | ||
77 | device_type = "ethernet-phy"; | ||
78 | }; | ||
79 | ethernet-phy@1 { | ||
80 | linux,phandle = <2452001>; | ||
81 | interrupt-parent = <10c00>; | ||
82 | interrupts = <19 1>; | ||
83 | bitbang = [ 12 12 13 02 02 01 ]; | ||
84 | reg = <3>; | ||
85 | device_type = "ethernet-phy"; | ||
86 | }; | ||
87 | }; | ||
88 | |||
89 | ethernet@24000 { | ||
90 | #address-cells = <1>; | ||
91 | #size-cells = <0>; | ||
92 | device_type = "network"; | ||
93 | device-id = <2>; | ||
94 | compatible = "fs_enet"; | ||
95 | model = "FCC"; | ||
96 | reg = <11300 20 8400 100 11380 30>; | ||
97 | mac-address = [ 00 11 2F 99 43 54 ]; | ||
98 | interrupts = <20 2>; | ||
99 | interrupt-parent = <10c00>; | ||
100 | phy-handle = <2452000>; | ||
101 | rx-clock = <13>; | ||
102 | tx-clock = <12>; | ||
103 | }; | ||
104 | |||
105 | ethernet@25000 { | ||
106 | device_type = "network"; | ||
107 | device-id = <3>; | ||
108 | compatible = "fs_enet"; | ||
109 | model = "FCC"; | ||
110 | reg = <11320 20 8500 100 113b0 30>; | ||
111 | mac-address = [ 00 11 2F 99 44 54 ]; | ||
112 | interrupts = <21 2>; | ||
113 | interrupt-parent = <10c00>; | ||
114 | phy-handle = <2452001>; | ||
115 | rx-clock = <17>; | ||
116 | tx-clock = <18>; | ||
117 | }; | ||
118 | |||
119 | cpm@f0000000 { | ||
120 | linux,phandle = <f0000000>; | ||
121 | #address-cells = <1>; | ||
122 | #size-cells = <1>; | ||
123 | #interrupt-cells = <2>; | ||
124 | device_type = "cpm"; | ||
125 | model = "CPM2"; | ||
126 | ranges = <00000000 00000000 3ffff>; | ||
127 | reg = <10d80 3280>; | ||
128 | command-proc = <119c0>; | ||
129 | brg-frequency = <17D7840>; | ||
130 | cpm_clk = <BEBC200>; | ||
131 | |||
132 | scc@11a00 { | ||
133 | device_type = "serial"; | ||
134 | compatible = "cpm_uart"; | ||
135 | model = "SCC"; | ||
136 | device-id = <2>; | ||
137 | reg = <11a00 20 8000 100>; | ||
138 | current-speed = <1c200>; | ||
139 | interrupts = <28 2>; | ||
140 | interrupt-parent = <10c00>; | ||
141 | clock-setup = <0 00ffffff>; | ||
142 | rx-clock = <1>; | ||
143 | tx-clock = <1>; | ||
144 | }; | ||
145 | |||
146 | scc@11a60 { | ||
147 | device_type = "serial"; | ||
148 | compatible = "cpm_uart"; | ||
149 | model = "SCC"; | ||
150 | device-id = <5>; | ||
151 | reg = <11a60 20 8300 100>; | ||
152 | current-speed = <1c200>; | ||
153 | interrupts = <2b 2>; | ||
154 | interrupt-parent = <10c00>; | ||
155 | clock-setup = <1b ffffff00>; | ||
156 | rx-clock = <4>; | ||
157 | tx-clock = <4>; | ||
158 | }; | ||
159 | |||
160 | }; | ||
161 | interrupt-controller@10c00 { | ||
162 | linux,phandle = <10c00>; | ||
163 | #address-cells = <0>; | ||
164 | #interrupt-cells = <2>; | ||
165 | interrupt-controller; | ||
166 | reg = <10c00 80>; | ||
167 | built-in; | ||
168 | device_type = "cpm-pic"; | ||
169 | compatible = "CPM2"; | ||
170 | }; | ||
171 | pci@0500 { | ||
172 | linux,phandle = <0500>; | ||
173 | #interrupt-cells = <1>; | ||
174 | #size-cells = <2>; | ||
175 | #address-cells = <3>; | ||
176 | compatible = "8272"; | ||
177 | device_type = "pci"; | ||
178 | reg = <10430 4dc>; | ||
179 | clock-frequency = <3f940aa>; | ||
180 | interrupt-map-mask = <f800 0 0 7>; | ||
181 | interrupt-map = < | ||
182 | |||
183 | /* IDSEL 0x16 */ | ||
184 | b000 0 0 1 f8200000 40 0 | ||
185 | b000 0 0 2 f8200000 41 0 | ||
186 | b000 0 0 3 f8200000 42 0 | ||
187 | b000 0 0 4 f8200000 43 0 | ||
188 | |||
189 | /* IDSEL 0x17 */ | ||
190 | b800 0 0 1 f8200000 43 0 | ||
191 | b800 0 0 2 f8200000 40 0 | ||
192 | b800 0 0 3 f8200000 41 0 | ||
193 | b800 0 0 4 f8200000 42 0 | ||
194 | |||
195 | /* IDSEL 0x18 */ | ||
196 | c000 0 0 1 f8200000 42 0 | ||
197 | c000 0 0 2 f8200000 43 0 | ||
198 | c000 0 0 3 f8200000 40 0 | ||
199 | c000 0 0 4 f8200000 41 0>; | ||
200 | interrupt-parent = <10c00>; | ||
201 | interrupts = <14 3>; | ||
202 | bus-range = <0 0>; | ||
203 | ranges = <02000000 0 80000000 80000000 0 40000000 | ||
204 | 01000000 0 00000000 f6000000 0 02000000>; | ||
205 | }; | ||
206 | |||
207 | /* May need to remove if on a part without crypto engine */ | ||
208 | crypto@30000 { | ||
209 | device_type = "crypto"; | ||
210 | model = "SEC2"; | ||
211 | compatible = "talitos"; | ||
212 | reg = <30000 10000>; | ||
213 | interrupts = <b 0>; | ||
214 | interrupt-parent = <10c00>; | ||
215 | num-channels = <4>; | ||
216 | channel-fifo-len = <18>; | ||
217 | exec-units-mask = <0000007e>; | ||
218 | /* desc mask is for rev1.x, we need runtime fixup for >=2.x */ | ||
219 | descriptor-types-mask = <01010ebf>; | ||
220 | }; | ||
221 | |||
222 | }; | ||
223 | }; | ||
diff --git a/arch/powerpc/boot/dts/mpc8360emds.dts b/arch/powerpc/boot/dts/mpc8360emds.dts new file mode 100644 index 000000000000..9022192155b9 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8360emds.dts | |||
@@ -0,0 +1,375 @@ | |||
1 | /* | ||
2 | * MPC8360E EMDS Device Tree Source | ||
3 | * | ||
4 | * Copyright 2006 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | |||
13 | /* | ||
14 | /memreserve/ 00000000 1000000; | ||
15 | */ | ||
16 | |||
17 | / { | ||
18 | model = "MPC8360EPB"; | ||
19 | compatible = "MPC83xx"; | ||
20 | #address-cells = <1>; | ||
21 | #size-cells = <1>; | ||
22 | linux,phandle = <100>; | ||
23 | |||
24 | cpus { | ||
25 | #cpus = <1>; | ||
26 | #address-cells = <1>; | ||
27 | #size-cells = <0>; | ||
28 | linux,phandle = <200>; | ||
29 | |||
30 | PowerPC,8360@0 { | ||
31 | device_type = "cpu"; | ||
32 | reg = <0>; | ||
33 | d-cache-line-size = <20>; // 32 bytes | ||
34 | i-cache-line-size = <20>; // 32 bytes | ||
35 | d-cache-size = <8000>; // L1, 32K | ||
36 | i-cache-size = <8000>; // L1, 32K | ||
37 | timebase-frequency = <3EF1480>; | ||
38 | bus-frequency = <FBC5200>; | ||
39 | clock-frequency = <1F78A400>; | ||
40 | 32-bit; | ||
41 | linux,phandle = <201>; | ||
42 | linux,boot-cpu; | ||
43 | }; | ||
44 | }; | ||
45 | |||
46 | memory { | ||
47 | device_type = "memory"; | ||
48 | linux,phandle = <300>; | ||
49 | reg = <00000000 10000000>; | ||
50 | }; | ||
51 | |||
52 | bcsr@f8000000 { | ||
53 | device_type = "board-control"; | ||
54 | reg = <f8000000 8000>; | ||
55 | }; | ||
56 | |||
57 | soc8360@e0000000 { | ||
58 | #address-cells = <1>; | ||
59 | #size-cells = <1>; | ||
60 | #interrupt-cells = <2>; | ||
61 | device_type = "soc"; | ||
62 | ranges = <0 e0000000 00100000>; | ||
63 | reg = <e0000000 00000200>; | ||
64 | bus-frequency = <FBC5200>; | ||
65 | |||
66 | wdt@200 { | ||
67 | device_type = "watchdog"; | ||
68 | compatible = "mpc83xx_wdt"; | ||
69 | reg = <200 100>; | ||
70 | }; | ||
71 | |||
72 | i2c@3000 { | ||
73 | device_type = "i2c"; | ||
74 | compatible = "fsl-i2c"; | ||
75 | reg = <3000 100>; | ||
76 | interrupts = <e 8>; | ||
77 | interrupt-parent = <700>; | ||
78 | dfsrr; | ||
79 | }; | ||
80 | |||
81 | i2c@3100 { | ||
82 | device_type = "i2c"; | ||
83 | compatible = "fsl-i2c"; | ||
84 | reg = <3100 100>; | ||
85 | interrupts = <f 8>; | ||
86 | interrupt-parent = <700>; | ||
87 | dfsrr; | ||
88 | }; | ||
89 | |||
90 | serial@4500 { | ||
91 | device_type = "serial"; | ||
92 | compatible = "ns16550"; | ||
93 | reg = <4500 100>; | ||
94 | clock-frequency = <FBC5200>; | ||
95 | interrupts = <9 8>; | ||
96 | interrupt-parent = <700>; | ||
97 | }; | ||
98 | |||
99 | serial@4600 { | ||
100 | device_type = "serial"; | ||
101 | compatible = "ns16550"; | ||
102 | reg = <4600 100>; | ||
103 | clock-frequency = <FBC5200>; | ||
104 | interrupts = <a 8>; | ||
105 | interrupt-parent = <700>; | ||
106 | }; | ||
107 | |||
108 | crypto@30000 { | ||
109 | device_type = "crypto"; | ||
110 | model = "SEC2"; | ||
111 | compatible = "talitos"; | ||
112 | reg = <30000 10000>; | ||
113 | interrupts = <b 8>; | ||
114 | interrupt-parent = <700>; | ||
115 | num-channels = <4>; | ||
116 | channel-fifo-len = <18>; | ||
117 | exec-units-mask = <0000007e>; | ||
118 | /* desc mask is for rev1.x, we need runtime fixup for >=2.x */ | ||
119 | descriptor-types-mask = <01010ebf>; | ||
120 | }; | ||
121 | |||
122 | pci@8500 { | ||
123 | linux,phandle = <8500>; | ||
124 | interrupt-map-mask = <f800 0 0 7>; | ||
125 | interrupt-map = < | ||
126 | |||
127 | /* IDSEL 0x11 AD17 */ | ||
128 | 8800 0 0 1 700 14 8 | ||
129 | 8800 0 0 2 700 15 8 | ||
130 | 8800 0 0 3 700 16 8 | ||
131 | 8800 0 0 4 700 17 8 | ||
132 | |||
133 | /* IDSEL 0x12 AD18 */ | ||
134 | 9000 0 0 1 700 16 8 | ||
135 | 9000 0 0 2 700 17 8 | ||
136 | 9000 0 0 3 700 14 8 | ||
137 | 9000 0 0 4 700 15 8 | ||
138 | |||
139 | /* IDSEL 0x13 AD19 */ | ||
140 | 9800 0 0 1 700 17 8 | ||
141 | 9800 0 0 2 700 14 8 | ||
142 | 9800 0 0 3 700 15 8 | ||
143 | 9800 0 0 4 700 16 8 | ||
144 | |||
145 | /* IDSEL 0x15 AD21*/ | ||
146 | a800 0 0 1 700 14 8 | ||
147 | a800 0 0 2 700 15 8 | ||
148 | a800 0 0 3 700 16 8 | ||
149 | a800 0 0 4 700 17 8 | ||
150 | |||
151 | /* IDSEL 0x16 AD22*/ | ||
152 | b000 0 0 1 700 17 8 | ||
153 | b000 0 0 2 700 14 8 | ||
154 | b000 0 0 3 700 15 8 | ||
155 | b000 0 0 4 700 16 8 | ||
156 | |||
157 | /* IDSEL 0x17 AD23*/ | ||
158 | b800 0 0 1 700 16 8 | ||
159 | b800 0 0 2 700 17 8 | ||
160 | b800 0 0 3 700 14 8 | ||
161 | b800 0 0 4 700 15 8 | ||
162 | |||
163 | /* IDSEL 0x18 AD24*/ | ||
164 | c000 0 0 1 700 15 8 | ||
165 | c000 0 0 2 700 16 8 | ||
166 | c000 0 0 3 700 17 8 | ||
167 | c000 0 0 4 700 14 8>; | ||
168 | interrupt-parent = <700>; | ||
169 | interrupts = <42 8>; | ||
170 | bus-range = <0 0>; | ||
171 | ranges = <02000000 0 a0000000 a0000000 0 10000000 | ||
172 | 42000000 0 80000000 80000000 0 10000000 | ||
173 | 01000000 0 00000000 e2000000 0 00100000>; | ||
174 | clock-frequency = <3f940aa>; | ||
175 | #interrupt-cells = <1>; | ||
176 | #size-cells = <2>; | ||
177 | #address-cells = <3>; | ||
178 | reg = <8500 100>; | ||
179 | compatible = "83xx"; | ||
180 | device_type = "pci"; | ||
181 | }; | ||
182 | |||
183 | pic@700 { | ||
184 | linux,phandle = <700>; | ||
185 | interrupt-controller; | ||
186 | #address-cells = <0>; | ||
187 | #interrupt-cells = <2>; | ||
188 | reg = <700 100>; | ||
189 | built-in; | ||
190 | device_type = "ipic"; | ||
191 | }; | ||
192 | |||
193 | par_io@1400 { | ||
194 | reg = <1400 100>; | ||
195 | device_type = "par_io"; | ||
196 | num-ports = <7>; | ||
197 | |||
198 | ucc_pin@01 { | ||
199 | linux,phandle = <140001>; | ||
200 | pio-map = < | ||
201 | /* port pin dir open_drain assignment has_irq */ | ||
202 | 0 3 1 0 1 0 /* TxD0 */ | ||
203 | 0 4 1 0 1 0 /* TxD1 */ | ||
204 | 0 5 1 0 1 0 /* TxD2 */ | ||
205 | 0 6 1 0 1 0 /* TxD3 */ | ||
206 | 1 6 1 0 3 0 /* TxD4 */ | ||
207 | 1 7 1 0 1 0 /* TxD5 */ | ||
208 | 1 9 1 0 2 0 /* TxD6 */ | ||
209 | 1 a 1 0 2 0 /* TxD7 */ | ||
210 | 0 9 2 0 1 0 /* RxD0 */ | ||
211 | 0 a 2 0 1 0 /* RxD1 */ | ||
212 | 0 b 2 0 1 0 /* RxD2 */ | ||
213 | 0 c 2 0 1 0 /* RxD3 */ | ||
214 | 0 d 2 0 1 0 /* RxD4 */ | ||
215 | 1 1 2 0 2 0 /* RxD5 */ | ||
216 | 1 0 2 0 2 0 /* RxD6 */ | ||
217 | 1 4 2 0 2 0 /* RxD7 */ | ||
218 | 0 7 1 0 1 0 /* TX_EN */ | ||
219 | 0 8 1 0 1 0 /* TX_ER */ | ||
220 | 0 f 2 0 1 0 /* RX_DV */ | ||
221 | 0 10 2 0 1 0 /* RX_ER */ | ||
222 | 0 0 2 0 1 0 /* RX_CLK */ | ||
223 | 2 9 1 0 3 0 /* GTX_CLK - CLK10 */ | ||
224 | 2 8 2 0 1 0>; /* GTX125 - CLK9 */ | ||
225 | }; | ||
226 | ucc_pin@02 { | ||
227 | linux,phandle = <140002>; | ||
228 | pio-map = < | ||
229 | /* port pin dir open_drain assignment has_irq */ | ||
230 | 0 11 1 0 1 0 /* TxD0 */ | ||
231 | 0 12 1 0 1 0 /* TxD1 */ | ||
232 | 0 13 1 0 1 0 /* TxD2 */ | ||
233 | 0 14 1 0 1 0 /* TxD3 */ | ||
234 | 1 2 1 0 1 0 /* TxD4 */ | ||
235 | 1 3 1 0 2 0 /* TxD5 */ | ||
236 | 1 5 1 0 3 0 /* TxD6 */ | ||
237 | 1 8 1 0 3 0 /* TxD7 */ | ||
238 | 0 17 2 0 1 0 /* RxD0 */ | ||
239 | 0 18 2 0 1 0 /* RxD1 */ | ||
240 | 0 19 2 0 1 0 /* RxD2 */ | ||
241 | 0 1a 2 0 1 0 /* RxD3 */ | ||
242 | 0 1b 2 0 1 0 /* RxD4 */ | ||
243 | 1 c 2 0 2 0 /* RxD5 */ | ||
244 | 1 d 2 0 3 0 /* RxD6 */ | ||
245 | 1 b 2 0 2 0 /* RxD7 */ | ||
246 | 0 15 1 0 1 0 /* TX_EN */ | ||
247 | 0 16 1 0 1 0 /* TX_ER */ | ||
248 | 0 1d 2 0 1 0 /* RX_DV */ | ||
249 | 0 1e 2 0 1 0 /* RX_ER */ | ||
250 | 0 1f 2 0 1 0 /* RX_CLK */ | ||
251 | 2 2 1 0 2 0 /* GTX_CLK - CLK10 */ | ||
252 | 2 3 2 0 1 0 /* GTX125 - CLK4 */ | ||
253 | 0 1 3 0 2 0 /* MDIO */ | ||
254 | 0 2 1 0 1 0>; /* MDC */ | ||
255 | }; | ||
256 | |||
257 | }; | ||
258 | }; | ||
259 | |||
260 | qe@e0100000 { | ||
261 | #address-cells = <1>; | ||
262 | #size-cells = <1>; | ||
263 | device_type = "qe"; | ||
264 | model = "QE"; | ||
265 | ranges = <0 e0100000 00100000>; | ||
266 | reg = <e0100000 480>; | ||
267 | brg-frequency = <0>; | ||
268 | bus-frequency = <179A7B00>; | ||
269 | |||
270 | muram@10000 { | ||
271 | device_type = "muram"; | ||
272 | ranges = <0 00010000 0000c000>; | ||
273 | |||
274 | data-only@0{ | ||
275 | reg = <0 c000>; | ||
276 | }; | ||
277 | }; | ||
278 | |||
279 | spi@4c0 { | ||
280 | device_type = "spi"; | ||
281 | compatible = "fsl_spi"; | ||
282 | reg = <4c0 40>; | ||
283 | interrupts = <2>; | ||
284 | interrupt-parent = <80>; | ||
285 | mode = "cpu"; | ||
286 | }; | ||
287 | |||
288 | spi@500 { | ||
289 | device_type = "spi"; | ||
290 | compatible = "fsl_spi"; | ||
291 | reg = <500 40>; | ||
292 | interrupts = <1>; | ||
293 | interrupt-parent = <80>; | ||
294 | mode = "cpu"; | ||
295 | }; | ||
296 | |||
297 | usb@6c0 { | ||
298 | device_type = "usb"; | ||
299 | compatible = "qe_udc"; | ||
300 | reg = <6c0 40 8B00 100>; | ||
301 | interrupts = <b>; | ||
302 | interrupt-parent = <80>; | ||
303 | mode = "slave"; | ||
304 | }; | ||
305 | |||
306 | ucc@2000 { | ||
307 | device_type = "network"; | ||
308 | compatible = "ucc_geth"; | ||
309 | model = "UCC"; | ||
310 | device-id = <1>; | ||
311 | reg = <2000 200>; | ||
312 | interrupts = <20>; | ||
313 | interrupt-parent = <80>; | ||
314 | mac-address = [ 00 04 9f 00 23 23 ]; | ||
315 | rx-clock = <0>; | ||
316 | tx-clock = <19>; | ||
317 | phy-handle = <212000>; | ||
318 | pio-handle = <140001>; | ||
319 | }; | ||
320 | |||
321 | ucc@3000 { | ||
322 | device_type = "network"; | ||
323 | compatible = "ucc_geth"; | ||
324 | model = "UCC"; | ||
325 | device-id = <2>; | ||
326 | reg = <3000 200>; | ||
327 | interrupts = <21>; | ||
328 | interrupt-parent = <80>; | ||
329 | mac-address = [ 00 11 22 33 44 55 ]; | ||
330 | rx-clock = <0>; | ||
331 | tx-clock = <14>; | ||
332 | phy-handle = <212001>; | ||
333 | pio-handle = <140002>; | ||
334 | }; | ||
335 | |||
336 | mdio@2120 { | ||
337 | #address-cells = <1>; | ||
338 | #size-cells = <0>; | ||
339 | reg = <2120 18>; | ||
340 | device_type = "mdio"; | ||
341 | compatible = "ucc_geth_phy"; | ||
342 | |||
343 | ethernet-phy@00 { | ||
344 | linux,phandle = <212000>; | ||
345 | interrupt-parent = <700>; | ||
346 | interrupts = <11 2>; | ||
347 | reg = <0>; | ||
348 | device_type = "ethernet-phy"; | ||
349 | interface = <6>; //ENET_1000_GMII | ||
350 | }; | ||
351 | ethernet-phy@01 { | ||
352 | linux,phandle = <212001>; | ||
353 | interrupt-parent = <700>; | ||
354 | interrupts = <12 2>; | ||
355 | reg = <1>; | ||
356 | device_type = "ethernet-phy"; | ||
357 | interface = <6>; | ||
358 | }; | ||
359 | }; | ||
360 | |||
361 | qeic@80 { | ||
362 | linux,phandle = <80>; | ||
363 | interrupt-controller; | ||
364 | device_type = "qeic"; | ||
365 | #address-cells = <0>; | ||
366 | #interrupt-cells = <1>; | ||
367 | reg = <80 80>; | ||
368 | built-in; | ||
369 | big-endian; | ||
370 | interrupts = <20 8 21 8>; //high:32 low:33 | ||
371 | interrupt-parent = <700>; | ||
372 | }; | ||
373 | |||
374 | }; | ||
375 | }; | ||
diff --git a/arch/powerpc/boot/zImage.coff.lds.S b/arch/powerpc/boot/zImage.coff.lds.S index 6016251a1a2c..05f32388b953 100644 --- a/arch/powerpc/boot/zImage.coff.lds.S +++ b/arch/powerpc/boot/zImage.coff.lds.S | |||
@@ -15,6 +15,7 @@ SECTIONS | |||
15 | { | 15 | { |
16 | *(.rodata*) | 16 | *(.rodata*) |
17 | *(.data*) | 17 | *(.data*) |
18 | *(__builtin_*) | ||
18 | *(.sdata*) | 19 | *(.sdata*) |
19 | __got2_start = .; | 20 | __got2_start = .; |
20 | *(.got2) | 21 | *(.got2) |
diff --git a/arch/powerpc/configs/mpc8360emds_defconfig b/arch/powerpc/configs/mpc8360emds_defconfig new file mode 100644 index 000000000000..c0703415d608 --- /dev/null +++ b/arch/powerpc/configs/mpc8360emds_defconfig | |||
@@ -0,0 +1,1018 @@ | |||
1 | # | ||
2 | # Automatically generated make config: don't edit | ||
3 | # Linux kernel version: 2.6.18 | ||
4 | # Thu Sep 21 18:14:27 2006 | ||
5 | # | ||
6 | # CONFIG_PPC64 is not set | ||
7 | CONFIG_PPC32=y | ||
8 | CONFIG_PPC_MERGE=y | ||
9 | CONFIG_MMU=y | ||
10 | CONFIG_GENERIC_HARDIRQS=y | ||
11 | CONFIG_IRQ_PER_CPU=y | ||
12 | CONFIG_RWSEM_XCHGADD_ALGORITHM=y | ||
13 | CONFIG_GENERIC_HWEIGHT=y | ||
14 | CONFIG_GENERIC_CALIBRATE_DELAY=y | ||
15 | CONFIG_GENERIC_FIND_NEXT_BIT=y | ||
16 | CONFIG_PPC=y | ||
17 | CONFIG_EARLY_PRINTK=y | ||
18 | CONFIG_GENERIC_NVRAM=y | ||
19 | CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y | ||
20 | CONFIG_ARCH_MAY_HAVE_PC_FDC=y | ||
21 | CONFIG_PPC_OF=y | ||
22 | CONFIG_PPC_UDBG_16550=y | ||
23 | # CONFIG_GENERIC_TBSYNC is not set | ||
24 | CONFIG_AUDIT_ARCH=y | ||
25 | CONFIG_DEFAULT_UIMAGE=y | ||
26 | |||
27 | # | ||
28 | # Processor support | ||
29 | # | ||
30 | # CONFIG_CLASSIC32 is not set | ||
31 | # CONFIG_PPC_52xx is not set | ||
32 | # CONFIG_PPC_82xx is not set | ||
33 | CONFIG_PPC_83xx=y | ||
34 | # CONFIG_PPC_85xx is not set | ||
35 | # CONFIG_PPC_86xx is not set | ||
36 | # CONFIG_40x is not set | ||
37 | # CONFIG_44x is not set | ||
38 | # CONFIG_8xx is not set | ||
39 | # CONFIG_E200 is not set | ||
40 | CONFIG_6xx=y | ||
41 | CONFIG_83xx=y | ||
42 | CONFIG_PPC_FPU=y | ||
43 | CONFIG_PPC_STD_MMU=y | ||
44 | CONFIG_PPC_STD_MMU_32=y | ||
45 | # CONFIG_SMP is not set | ||
46 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | ||
47 | |||
48 | # | ||
49 | # Code maturity level options | ||
50 | # | ||
51 | CONFIG_EXPERIMENTAL=y | ||
52 | CONFIG_BROKEN_ON_SMP=y | ||
53 | CONFIG_INIT_ENV_ARG_LIMIT=32 | ||
54 | |||
55 | # | ||
56 | # General setup | ||
57 | # | ||
58 | CONFIG_LOCALVERSION="" | ||
59 | CONFIG_LOCALVERSION_AUTO=y | ||
60 | CONFIG_SWAP=y | ||
61 | CONFIG_SYSVIPC=y | ||
62 | # CONFIG_POSIX_MQUEUE is not set | ||
63 | # CONFIG_BSD_PROCESS_ACCT is not set | ||
64 | # CONFIG_TASKSTATS is not set | ||
65 | # CONFIG_AUDIT is not set | ||
66 | # CONFIG_IKCONFIG is not set | ||
67 | # CONFIG_RELAY is not set | ||
68 | CONFIG_INITRAMFS_SOURCE="" | ||
69 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | ||
70 | CONFIG_EMBEDDED=y | ||
71 | CONFIG_SYSCTL=y | ||
72 | # CONFIG_KALLSYMS is not set | ||
73 | CONFIG_HOTPLUG=y | ||
74 | CONFIG_PRINTK=y | ||
75 | CONFIG_BUG=y | ||
76 | CONFIG_ELF_CORE=y | ||
77 | CONFIG_BASE_FULL=y | ||
78 | CONFIG_FUTEX=y | ||
79 | # CONFIG_EPOLL is not set | ||
80 | CONFIG_SHMEM=y | ||
81 | CONFIG_SLAB=y | ||
82 | CONFIG_VM_EVENT_COUNTERS=y | ||
83 | CONFIG_RT_MUTEXES=y | ||
84 | # CONFIG_TINY_SHMEM is not set | ||
85 | CONFIG_BASE_SMALL=0 | ||
86 | # CONFIG_SLOB is not set | ||
87 | |||
88 | # | ||
89 | # Loadable module support | ||
90 | # | ||
91 | CONFIG_MODULES=y | ||
92 | CONFIG_MODULE_UNLOAD=y | ||
93 | # CONFIG_MODULE_FORCE_UNLOAD is not set | ||
94 | # CONFIG_MODVERSIONS is not set | ||
95 | # CONFIG_MODULE_SRCVERSION_ALL is not set | ||
96 | # CONFIG_KMOD is not set | ||
97 | |||
98 | # | ||
99 | # Block layer | ||
100 | # | ||
101 | # CONFIG_LBD is not set | ||
102 | # CONFIG_BLK_DEV_IO_TRACE is not set | ||
103 | # CONFIG_LSF is not set | ||
104 | |||
105 | # | ||
106 | # IO Schedulers | ||
107 | # | ||
108 | CONFIG_IOSCHED_NOOP=y | ||
109 | CONFIG_IOSCHED_AS=y | ||
110 | CONFIG_IOSCHED_DEADLINE=y | ||
111 | CONFIG_IOSCHED_CFQ=y | ||
112 | CONFIG_DEFAULT_AS=y | ||
113 | # CONFIG_DEFAULT_DEADLINE is not set | ||
114 | # CONFIG_DEFAULT_CFQ is not set | ||
115 | # CONFIG_DEFAULT_NOOP is not set | ||
116 | CONFIG_DEFAULT_IOSCHED="anticipatory" | ||
117 | CONFIG_QUICC_ENGINE=y | ||
118 | CONFIG_PPC_GEN550=y | ||
119 | # CONFIG_WANT_EARLY_SERIAL is not set | ||
120 | |||
121 | # | ||
122 | # Platform support | ||
123 | # | ||
124 | # CONFIG_MPC834x_SYS is not set | ||
125 | # CONFIG_MPC834x_ITX is not set | ||
126 | CONFIG_MPC8360E_PB=y | ||
127 | CONFIG_PPC_MPC836x=y | ||
128 | # CONFIG_MPIC is not set | ||
129 | |||
130 | # | ||
131 | # Kernel options | ||
132 | # | ||
133 | # CONFIG_HIGHMEM is not set | ||
134 | # CONFIG_HZ_100 is not set | ||
135 | CONFIG_HZ_250=y | ||
136 | # CONFIG_HZ_1000 is not set | ||
137 | CONFIG_HZ=250 | ||
138 | CONFIG_PREEMPT_NONE=y | ||
139 | # CONFIG_PREEMPT_VOLUNTARY is not set | ||
140 | # CONFIG_PREEMPT is not set | ||
141 | CONFIG_BINFMT_ELF=y | ||
142 | # CONFIG_BINFMT_MISC is not set | ||
143 | CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y | ||
144 | CONFIG_ARCH_FLATMEM_ENABLE=y | ||
145 | CONFIG_SELECT_MEMORY_MODEL=y | ||
146 | CONFIG_FLATMEM_MANUAL=y | ||
147 | # CONFIG_DISCONTIGMEM_MANUAL is not set | ||
148 | # CONFIG_SPARSEMEM_MANUAL is not set | ||
149 | CONFIG_FLATMEM=y | ||
150 | CONFIG_FLAT_NODE_MEM_MAP=y | ||
151 | # CONFIG_SPARSEMEM_STATIC is not set | ||
152 | CONFIG_SPLIT_PTLOCK_CPUS=4 | ||
153 | # CONFIG_RESOURCES_64BIT is not set | ||
154 | CONFIG_PROC_DEVICETREE=y | ||
155 | # CONFIG_CMDLINE_BOOL is not set | ||
156 | # CONFIG_PM is not set | ||
157 | CONFIG_SECCOMP=y | ||
158 | CONFIG_ISA_DMA_API=y | ||
159 | |||
160 | # | ||
161 | # Bus options | ||
162 | # | ||
163 | CONFIG_GENERIC_ISA_DMA=y | ||
164 | # CONFIG_MPIC_WEIRD is not set | ||
165 | # CONFIG_PPC_I8259 is not set | ||
166 | CONFIG_PPC_INDIRECT_PCI=y | ||
167 | CONFIG_FSL_SOC=y | ||
168 | CONFIG_PCI=y | ||
169 | CONFIG_PCI_DOMAINS=y | ||
170 | # CONFIG_PCIEPORTBUS is not set | ||
171 | |||
172 | # | ||
173 | # PCCARD (PCMCIA/CardBus) support | ||
174 | # | ||
175 | # CONFIG_PCCARD is not set | ||
176 | |||
177 | # | ||
178 | # PCI Hotplug Support | ||
179 | # | ||
180 | # CONFIG_HOTPLUG_PCI is not set | ||
181 | |||
182 | # | ||
183 | # Advanced setup | ||
184 | # | ||
185 | # CONFIG_ADVANCED_OPTIONS is not set | ||
186 | |||
187 | # | ||
188 | # Default settings for advanced configuration options are used | ||
189 | # | ||
190 | CONFIG_HIGHMEM_START=0xfe000000 | ||
191 | CONFIG_LOWMEM_SIZE=0x30000000 | ||
192 | CONFIG_KERNEL_START=0xc0000000 | ||
193 | CONFIG_TASK_SIZE=0x80000000 | ||
194 | CONFIG_BOOT_LOAD=0x00800000 | ||
195 | |||
196 | # | ||
197 | # Networking | ||
198 | # | ||
199 | CONFIG_NET=y | ||
200 | |||
201 | # | ||
202 | # Networking options | ||
203 | # | ||
204 | # CONFIG_NETDEBUG is not set | ||
205 | CONFIG_PACKET=y | ||
206 | # CONFIG_PACKET_MMAP is not set | ||
207 | CONFIG_UNIX=y | ||
208 | CONFIG_XFRM=y | ||
209 | # CONFIG_XFRM_USER is not set | ||
210 | # CONFIG_NET_KEY is not set | ||
211 | CONFIG_INET=y | ||
212 | CONFIG_IP_MULTICAST=y | ||
213 | # CONFIG_IP_ADVANCED_ROUTER is not set | ||
214 | CONFIG_IP_FIB_HASH=y | ||
215 | CONFIG_IP_PNP=y | ||
216 | CONFIG_IP_PNP_DHCP=y | ||
217 | CONFIG_IP_PNP_BOOTP=y | ||
218 | # CONFIG_IP_PNP_RARP is not set | ||
219 | # CONFIG_NET_IPIP is not set | ||
220 | # CONFIG_NET_IPGRE is not set | ||
221 | # CONFIG_IP_MROUTE is not set | ||
222 | # CONFIG_ARPD is not set | ||
223 | CONFIG_SYN_COOKIES=y | ||
224 | # CONFIG_INET_AH is not set | ||
225 | # CONFIG_INET_ESP is not set | ||
226 | # CONFIG_INET_IPCOMP is not set | ||
227 | # CONFIG_INET_XFRM_TUNNEL is not set | ||
228 | # CONFIG_INET_TUNNEL is not set | ||
229 | CONFIG_INET_XFRM_MODE_TRANSPORT=y | ||
230 | CONFIG_INET_XFRM_MODE_TUNNEL=y | ||
231 | CONFIG_INET_DIAG=y | ||
232 | CONFIG_INET_TCP_DIAG=y | ||
233 | # CONFIG_TCP_CONG_ADVANCED is not set | ||
234 | CONFIG_TCP_CONG_BIC=y | ||
235 | # CONFIG_IPV6 is not set | ||
236 | # CONFIG_INET6_XFRM_TUNNEL is not set | ||
237 | # CONFIG_INET6_TUNNEL is not set | ||
238 | # CONFIG_NETWORK_SECMARK is not set | ||
239 | # CONFIG_NETFILTER is not set | ||
240 | |||
241 | # | ||
242 | # DCCP Configuration (EXPERIMENTAL) | ||
243 | # | ||
244 | # CONFIG_IP_DCCP is not set | ||
245 | |||
246 | # | ||
247 | # SCTP Configuration (EXPERIMENTAL) | ||
248 | # | ||
249 | # CONFIG_IP_SCTP is not set | ||
250 | |||
251 | # | ||
252 | # TIPC Configuration (EXPERIMENTAL) | ||
253 | # | ||
254 | # CONFIG_TIPC is not set | ||
255 | # CONFIG_ATM is not set | ||
256 | # CONFIG_BRIDGE is not set | ||
257 | # CONFIG_VLAN_8021Q is not set | ||
258 | # CONFIG_DECNET is not set | ||
259 | # CONFIG_LLC2 is not set | ||
260 | # CONFIG_IPX is not set | ||
261 | # CONFIG_ATALK is not set | ||
262 | # CONFIG_X25 is not set | ||
263 | # CONFIG_LAPB is not set | ||
264 | # CONFIG_ECONET is not set | ||
265 | # CONFIG_WAN_ROUTER is not set | ||
266 | |||
267 | # | ||
268 | # QoS and/or fair queueing | ||
269 | # | ||
270 | # CONFIG_NET_SCHED is not set | ||
271 | |||
272 | # | ||
273 | # Network testing | ||
274 | # | ||
275 | # CONFIG_NET_PKTGEN is not set | ||
276 | # CONFIG_HAMRADIO is not set | ||
277 | # CONFIG_IRDA is not set | ||
278 | # CONFIG_BT is not set | ||
279 | # CONFIG_IEEE80211 is not set | ||
280 | |||
281 | # | ||
282 | # Device Drivers | ||
283 | # | ||
284 | |||
285 | # | ||
286 | # Generic Driver Options | ||
287 | # | ||
288 | CONFIG_STANDALONE=y | ||
289 | CONFIG_PREVENT_FIRMWARE_BUILD=y | ||
290 | # CONFIG_FW_LOADER is not set | ||
291 | # CONFIG_SYS_HYPERVISOR is not set | ||
292 | |||
293 | # | ||
294 | # Connector - unified userspace <-> kernelspace linker | ||
295 | # | ||
296 | # CONFIG_CONNECTOR is not set | ||
297 | |||
298 | # | ||
299 | # Memory Technology Devices (MTD) | ||
300 | # | ||
301 | # CONFIG_MTD is not set | ||
302 | |||
303 | # | ||
304 | # Parallel port support | ||
305 | # | ||
306 | # CONFIG_PARPORT is not set | ||
307 | |||
308 | # | ||
309 | # Plug and Play support | ||
310 | # | ||
311 | |||
312 | # | ||
313 | # Block devices | ||
314 | # | ||
315 | # CONFIG_BLK_DEV_FD is not set | ||
316 | # CONFIG_BLK_CPQ_DA is not set | ||
317 | # CONFIG_BLK_CPQ_CISS_DA is not set | ||
318 | # CONFIG_BLK_DEV_DAC960 is not set | ||
319 | # CONFIG_BLK_DEV_UMEM is not set | ||
320 | # CONFIG_BLK_DEV_COW_COMMON is not set | ||
321 | CONFIG_BLK_DEV_LOOP=y | ||
322 | # CONFIG_BLK_DEV_CRYPTOLOOP is not set | ||
323 | # CONFIG_BLK_DEV_NBD is not set | ||
324 | # CONFIG_BLK_DEV_SX8 is not set | ||
325 | CONFIG_BLK_DEV_RAM=y | ||
326 | CONFIG_BLK_DEV_RAM_COUNT=16 | ||
327 | CONFIG_BLK_DEV_RAM_SIZE=32768 | ||
328 | CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 | ||
329 | CONFIG_BLK_DEV_INITRD=y | ||
330 | # CONFIG_CDROM_PKTCDVD is not set | ||
331 | # CONFIG_ATA_OVER_ETH is not set | ||
332 | |||
333 | # | ||
334 | # ATA/ATAPI/MFM/RLL support | ||
335 | # | ||
336 | # CONFIG_IDE is not set | ||
337 | |||
338 | # | ||
339 | # SCSI device support | ||
340 | # | ||
341 | # CONFIG_RAID_ATTRS is not set | ||
342 | CONFIG_SCSI=y | ||
343 | CONFIG_SCSI_PROC_FS=y | ||
344 | |||
345 | # | ||
346 | # SCSI support type (disk, tape, CD-ROM) | ||
347 | # | ||
348 | # CONFIG_BLK_DEV_SD is not set | ||
349 | # CONFIG_CHR_DEV_ST is not set | ||
350 | # CONFIG_CHR_DEV_OSST is not set | ||
351 | # CONFIG_BLK_DEV_SR is not set | ||
352 | # CONFIG_CHR_DEV_SG is not set | ||
353 | # CONFIG_CHR_DEV_SCH is not set | ||
354 | |||
355 | # | ||
356 | # Some SCSI devices (e.g. CD jukebox) support multiple LUNs | ||
357 | # | ||
358 | # CONFIG_SCSI_MULTI_LUN is not set | ||
359 | # CONFIG_SCSI_CONSTANTS is not set | ||
360 | # CONFIG_SCSI_LOGGING is not set | ||
361 | |||
362 | # | ||
363 | # SCSI Transport Attributes | ||
364 | # | ||
365 | # CONFIG_SCSI_SPI_ATTRS is not set | ||
366 | # CONFIG_SCSI_FC_ATTRS is not set | ||
367 | # CONFIG_SCSI_ISCSI_ATTRS is not set | ||
368 | # CONFIG_SCSI_SAS_ATTRS is not set | ||
369 | |||
370 | # | ||
371 | # SCSI low-level drivers | ||
372 | # | ||
373 | # CONFIG_ISCSI_TCP is not set | ||
374 | # CONFIG_BLK_DEV_3W_XXXX_RAID is not set | ||
375 | # CONFIG_SCSI_3W_9XXX is not set | ||
376 | # CONFIG_SCSI_ACARD is not set | ||
377 | # CONFIG_SCSI_AACRAID is not set | ||
378 | # CONFIG_SCSI_AIC7XXX is not set | ||
379 | # CONFIG_SCSI_AIC7XXX_OLD is not set | ||
380 | # CONFIG_SCSI_AIC79XX is not set | ||
381 | # CONFIG_SCSI_DPT_I2O is not set | ||
382 | # CONFIG_MEGARAID_NEWGEN is not set | ||
383 | # CONFIG_MEGARAID_LEGACY is not set | ||
384 | # CONFIG_MEGARAID_SAS is not set | ||
385 | # CONFIG_SCSI_SATA is not set | ||
386 | # CONFIG_SCSI_HPTIOP is not set | ||
387 | # CONFIG_SCSI_BUSLOGIC is not set | ||
388 | # CONFIG_SCSI_DMX3191D is not set | ||
389 | # CONFIG_SCSI_EATA is not set | ||
390 | # CONFIG_SCSI_FUTURE_DOMAIN is not set | ||
391 | # CONFIG_SCSI_GDTH is not set | ||
392 | # CONFIG_SCSI_IPS is not set | ||
393 | # CONFIG_SCSI_INITIO is not set | ||
394 | # CONFIG_SCSI_INIA100 is not set | ||
395 | # CONFIG_SCSI_SYM53C8XX_2 is not set | ||
396 | # CONFIG_SCSI_IPR is not set | ||
397 | # CONFIG_SCSI_QLOGIC_1280 is not set | ||
398 | # CONFIG_SCSI_QLA_FC is not set | ||
399 | # CONFIG_SCSI_LPFC is not set | ||
400 | # CONFIG_SCSI_DC395x is not set | ||
401 | # CONFIG_SCSI_DC390T is not set | ||
402 | # CONFIG_SCSI_NSP32 is not set | ||
403 | # CONFIG_SCSI_DEBUG is not set | ||
404 | |||
405 | # | ||
406 | # Multi-device support (RAID and LVM) | ||
407 | # | ||
408 | # CONFIG_MD is not set | ||
409 | |||
410 | # | ||
411 | # Fusion MPT device support | ||
412 | # | ||
413 | # CONFIG_FUSION is not set | ||
414 | # CONFIG_FUSION_SPI is not set | ||
415 | # CONFIG_FUSION_FC is not set | ||
416 | # CONFIG_FUSION_SAS is not set | ||
417 | |||
418 | # | ||
419 | # IEEE 1394 (FireWire) support | ||
420 | # | ||
421 | # CONFIG_IEEE1394 is not set | ||
422 | |||
423 | # | ||
424 | # I2O device support | ||
425 | # | ||
426 | # CONFIG_I2O is not set | ||
427 | |||
428 | # | ||
429 | # Macintosh device drivers | ||
430 | # | ||
431 | # CONFIG_WINDFARM is not set | ||
432 | |||
433 | # | ||
434 | # Network device support | ||
435 | # | ||
436 | CONFIG_NETDEVICES=y | ||
437 | # CONFIG_DUMMY is not set | ||
438 | # CONFIG_BONDING is not set | ||
439 | # CONFIG_EQUALIZER is not set | ||
440 | # CONFIG_TUN is not set | ||
441 | |||
442 | # | ||
443 | # ARCnet devices | ||
444 | # | ||
445 | # CONFIG_ARCNET is not set | ||
446 | |||
447 | # | ||
448 | # PHY device support | ||
449 | # | ||
450 | # CONFIG_PHYLIB is not set | ||
451 | |||
452 | # | ||
453 | # Ethernet (10 or 100Mbit) | ||
454 | # | ||
455 | CONFIG_NET_ETHERNET=y | ||
456 | CONFIG_MII=y | ||
457 | # CONFIG_HAPPYMEAL is not set | ||
458 | # CONFIG_SUNGEM is not set | ||
459 | # CONFIG_CASSINI is not set | ||
460 | # CONFIG_NET_VENDOR_3COM is not set | ||
461 | |||
462 | # | ||
463 | # Tulip family network device support | ||
464 | # | ||
465 | # CONFIG_NET_TULIP is not set | ||
466 | # CONFIG_HP100 is not set | ||
467 | # CONFIG_NET_PCI is not set | ||
468 | |||
469 | # | ||
470 | # Ethernet (1000 Mbit) | ||
471 | # | ||
472 | # CONFIG_ACENIC is not set | ||
473 | # CONFIG_DL2K is not set | ||
474 | # CONFIG_E1000 is not set | ||
475 | # CONFIG_NS83820 is not set | ||
476 | # CONFIG_HAMACHI is not set | ||
477 | # CONFIG_YELLOWFIN is not set | ||
478 | # CONFIG_R8169 is not set | ||
479 | # CONFIG_SIS190 is not set | ||
480 | # CONFIG_SKGE is not set | ||
481 | # CONFIG_SKY2 is not set | ||
482 | # CONFIG_SK98LIN is not set | ||
483 | # CONFIG_TIGON3 is not set | ||
484 | # CONFIG_BNX2 is not set | ||
485 | # CONFIG_GIANFAR is not set | ||
486 | CONFIG_UCC_GETH=y | ||
487 | # CONFIG_UGETH_NAPI is not set | ||
488 | # CONFIG_UGETH_MAGIC_PACKET is not set | ||
489 | # CONFIG_UGETH_FILTERING is not set | ||
490 | # CONFIG_UGETH_TX_ON_DEMOND is not set | ||
491 | |||
492 | # | ||
493 | # Ethernet (10000 Mbit) | ||
494 | # | ||
495 | # CONFIG_CHELSIO_T1 is not set | ||
496 | # CONFIG_IXGB is not set | ||
497 | # CONFIG_S2IO is not set | ||
498 | # CONFIG_MYRI10GE is not set | ||
499 | |||
500 | # | ||
501 | # Token Ring devices | ||
502 | # | ||
503 | # CONFIG_TR is not set | ||
504 | |||
505 | # | ||
506 | # Wireless LAN (non-hamradio) | ||
507 | # | ||
508 | # CONFIG_NET_RADIO is not set | ||
509 | |||
510 | # | ||
511 | # Wan interfaces | ||
512 | # | ||
513 | # CONFIG_WAN is not set | ||
514 | # CONFIG_FDDI is not set | ||
515 | # CONFIG_HIPPI is not set | ||
516 | # CONFIG_PPP is not set | ||
517 | # CONFIG_SLIP is not set | ||
518 | # CONFIG_NET_FC is not set | ||
519 | # CONFIG_SHAPER is not set | ||
520 | # CONFIG_NETCONSOLE is not set | ||
521 | # CONFIG_NETPOLL is not set | ||
522 | # CONFIG_NET_POLL_CONTROLLER is not set | ||
523 | |||
524 | # | ||
525 | # ISDN subsystem | ||
526 | # | ||
527 | # CONFIG_ISDN is not set | ||
528 | |||
529 | # | ||
530 | # Telephony Support | ||
531 | # | ||
532 | # CONFIG_PHONE is not set | ||
533 | |||
534 | # | ||
535 | # Input device support | ||
536 | # | ||
537 | CONFIG_INPUT=y | ||
538 | |||
539 | # | ||
540 | # Userland interfaces | ||
541 | # | ||
542 | # CONFIG_INPUT_MOUSEDEV is not set | ||
543 | # CONFIG_INPUT_JOYDEV is not set | ||
544 | # CONFIG_INPUT_TSDEV is not set | ||
545 | # CONFIG_INPUT_EVDEV is not set | ||
546 | # CONFIG_INPUT_EVBUG is not set | ||
547 | |||
548 | # | ||
549 | # Input Device Drivers | ||
550 | # | ||
551 | # CONFIG_INPUT_KEYBOARD is not set | ||
552 | # CONFIG_INPUT_MOUSE is not set | ||
553 | # CONFIG_INPUT_JOYSTICK is not set | ||
554 | # CONFIG_INPUT_TOUCHSCREEN is not set | ||
555 | # CONFIG_INPUT_MISC is not set | ||
556 | |||
557 | # | ||
558 | # Hardware I/O ports | ||
559 | # | ||
560 | # CONFIG_SERIO is not set | ||
561 | # CONFIG_GAMEPORT is not set | ||
562 | |||
563 | # | ||
564 | # Character devices | ||
565 | # | ||
566 | # CONFIG_VT is not set | ||
567 | # CONFIG_SERIAL_NONSTANDARD is not set | ||
568 | |||
569 | # | ||
570 | # Serial drivers | ||
571 | # | ||
572 | CONFIG_SERIAL_8250=y | ||
573 | CONFIG_SERIAL_8250_CONSOLE=y | ||
574 | CONFIG_SERIAL_8250_PCI=y | ||
575 | CONFIG_SERIAL_8250_NR_UARTS=4 | ||
576 | CONFIG_SERIAL_8250_RUNTIME_UARTS=4 | ||
577 | # CONFIG_SERIAL_8250_EXTENDED is not set | ||
578 | |||
579 | # | ||
580 | # Non-8250 serial port support | ||
581 | # | ||
582 | CONFIG_SERIAL_CORE=y | ||
583 | CONFIG_SERIAL_CORE_CONSOLE=y | ||
584 | # CONFIG_SERIAL_JSM is not set | ||
585 | CONFIG_UNIX98_PTYS=y | ||
586 | CONFIG_LEGACY_PTYS=y | ||
587 | CONFIG_LEGACY_PTY_COUNT=256 | ||
588 | |||
589 | # | ||
590 | # IPMI | ||
591 | # | ||
592 | # CONFIG_IPMI_HANDLER is not set | ||
593 | |||
594 | # | ||
595 | # Watchdog Cards | ||
596 | # | ||
597 | CONFIG_WATCHDOG=y | ||
598 | # CONFIG_WATCHDOG_NOWAYOUT is not set | ||
599 | |||
600 | # | ||
601 | # Watchdog Device Drivers | ||
602 | # | ||
603 | # CONFIG_SOFT_WATCHDOG is not set | ||
604 | CONFIG_83xx_WDT=y | ||
605 | |||
606 | # | ||
607 | # PCI-based Watchdog Cards | ||
608 | # | ||
609 | # CONFIG_PCIPCWATCHDOG is not set | ||
610 | # CONFIG_WDTPCI is not set | ||
611 | CONFIG_HW_RANDOM=y | ||
612 | # CONFIG_NVRAM is not set | ||
613 | CONFIG_GEN_RTC=y | ||
614 | # CONFIG_GEN_RTC_X is not set | ||
615 | # CONFIG_DTLK is not set | ||
616 | # CONFIG_R3964 is not set | ||
617 | # CONFIG_APPLICOM is not set | ||
618 | |||
619 | # | ||
620 | # Ftape, the floppy tape device driver | ||
621 | # | ||
622 | # CONFIG_AGP is not set | ||
623 | # CONFIG_DRM is not set | ||
624 | # CONFIG_RAW_DRIVER is not set | ||
625 | |||
626 | # | ||
627 | # TPM devices | ||
628 | # | ||
629 | # CONFIG_TCG_TPM is not set | ||
630 | # CONFIG_TELCLOCK is not set | ||
631 | |||
632 | # | ||
633 | # I2C support | ||
634 | # | ||
635 | CONFIG_I2C=y | ||
636 | CONFIG_I2C_CHARDEV=y | ||
637 | |||
638 | # | ||
639 | # I2C Algorithms | ||
640 | # | ||
641 | # CONFIG_I2C_ALGOBIT is not set | ||
642 | # CONFIG_I2C_ALGOPCF is not set | ||
643 | # CONFIG_I2C_ALGOPCA is not set | ||
644 | |||
645 | # | ||
646 | # I2C Hardware Bus support | ||
647 | # | ||
648 | # CONFIG_I2C_ALI1535 is not set | ||
649 | # CONFIG_I2C_ALI1563 is not set | ||
650 | # CONFIG_I2C_ALI15X3 is not set | ||
651 | # CONFIG_I2C_AMD756 is not set | ||
652 | # CONFIG_I2C_AMD8111 is not set | ||
653 | # CONFIG_I2C_I801 is not set | ||
654 | # CONFIG_I2C_I810 is not set | ||
655 | # CONFIG_I2C_PIIX4 is not set | ||
656 | CONFIG_I2C_MPC=y | ||
657 | # CONFIG_I2C_NFORCE2 is not set | ||
658 | # CONFIG_I2C_OCORES is not set | ||
659 | # CONFIG_I2C_PARPORT_LIGHT is not set | ||
660 | # CONFIG_I2C_PROSAVAGE is not set | ||
661 | # CONFIG_I2C_SAVAGE4 is not set | ||
662 | # CONFIG_I2C_SIS5595 is not set | ||
663 | # CONFIG_I2C_SIS630 is not set | ||
664 | # CONFIG_I2C_SIS96X is not set | ||
665 | # CONFIG_I2C_STUB is not set | ||
666 | # CONFIG_I2C_VIA is not set | ||
667 | # CONFIG_I2C_VIAPRO is not set | ||
668 | # CONFIG_I2C_VOODOO3 is not set | ||
669 | # CONFIG_I2C_PCA_ISA is not set | ||
670 | |||
671 | # | ||
672 | # Miscellaneous I2C Chip support | ||
673 | # | ||
674 | # CONFIG_SENSORS_DS1337 is not set | ||
675 | # CONFIG_SENSORS_DS1374 is not set | ||
676 | # CONFIG_SENSORS_EEPROM is not set | ||
677 | # CONFIG_SENSORS_PCF8574 is not set | ||
678 | # CONFIG_SENSORS_PCA9539 is not set | ||
679 | # CONFIG_SENSORS_PCF8591 is not set | ||
680 | # CONFIG_SENSORS_M41T00 is not set | ||
681 | # CONFIG_SENSORS_MAX6875 is not set | ||
682 | # CONFIG_I2C_DEBUG_CORE is not set | ||
683 | # CONFIG_I2C_DEBUG_ALGO is not set | ||
684 | # CONFIG_I2C_DEBUG_BUS is not set | ||
685 | # CONFIG_I2C_DEBUG_CHIP is not set | ||
686 | |||
687 | # | ||
688 | # SPI support | ||
689 | # | ||
690 | # CONFIG_SPI is not set | ||
691 | # CONFIG_SPI_MASTER is not set | ||
692 | |||
693 | # | ||
694 | # Dallas's 1-wire bus | ||
695 | # | ||
696 | |||
697 | # | ||
698 | # Hardware Monitoring support | ||
699 | # | ||
700 | CONFIG_HWMON=y | ||
701 | # CONFIG_HWMON_VID is not set | ||
702 | # CONFIG_SENSORS_ABITUGURU is not set | ||
703 | # CONFIG_SENSORS_ADM1021 is not set | ||
704 | # CONFIG_SENSORS_ADM1025 is not set | ||
705 | # CONFIG_SENSORS_ADM1026 is not set | ||
706 | # CONFIG_SENSORS_ADM1031 is not set | ||
707 | # CONFIG_SENSORS_ADM9240 is not set | ||
708 | # CONFIG_SENSORS_ASB100 is not set | ||
709 | # CONFIG_SENSORS_ATXP1 is not set | ||
710 | # CONFIG_SENSORS_DS1621 is not set | ||
711 | # CONFIG_SENSORS_F71805F is not set | ||
712 | # CONFIG_SENSORS_FSCHER is not set | ||
713 | # CONFIG_SENSORS_FSCPOS is not set | ||
714 | # CONFIG_SENSORS_GL518SM is not set | ||
715 | # CONFIG_SENSORS_GL520SM is not set | ||
716 | # CONFIG_SENSORS_IT87 is not set | ||
717 | # CONFIG_SENSORS_LM63 is not set | ||
718 | # CONFIG_SENSORS_LM75 is not set | ||
719 | # CONFIG_SENSORS_LM77 is not set | ||
720 | # CONFIG_SENSORS_LM78 is not set | ||
721 | # CONFIG_SENSORS_LM80 is not set | ||
722 | # CONFIG_SENSORS_LM83 is not set | ||
723 | # CONFIG_SENSORS_LM85 is not set | ||
724 | # CONFIG_SENSORS_LM87 is not set | ||
725 | # CONFIG_SENSORS_LM90 is not set | ||
726 | # CONFIG_SENSORS_LM92 is not set | ||
727 | # CONFIG_SENSORS_MAX1619 is not set | ||
728 | # CONFIG_SENSORS_PC87360 is not set | ||
729 | # CONFIG_SENSORS_SIS5595 is not set | ||
730 | # CONFIG_SENSORS_SMSC47M1 is not set | ||
731 | # CONFIG_SENSORS_SMSC47M192 is not set | ||
732 | # CONFIG_SENSORS_SMSC47B397 is not set | ||
733 | # CONFIG_SENSORS_VIA686A is not set | ||
734 | # CONFIG_SENSORS_VT8231 is not set | ||
735 | # CONFIG_SENSORS_W83781D is not set | ||
736 | # CONFIG_SENSORS_W83791D is not set | ||
737 | # CONFIG_SENSORS_W83792D is not set | ||
738 | # CONFIG_SENSORS_W83L785TS is not set | ||
739 | # CONFIG_SENSORS_W83627HF is not set | ||
740 | # CONFIG_SENSORS_W83627EHF is not set | ||
741 | # CONFIG_HWMON_DEBUG_CHIP is not set | ||
742 | |||
743 | # | ||
744 | # Misc devices | ||
745 | # | ||
746 | |||
747 | # | ||
748 | # Multimedia devices | ||
749 | # | ||
750 | # CONFIG_VIDEO_DEV is not set | ||
751 | CONFIG_VIDEO_V4L2=y | ||
752 | |||
753 | # | ||
754 | # Digital Video Broadcasting Devices | ||
755 | # | ||
756 | # CONFIG_DVB is not set | ||
757 | |||
758 | # | ||
759 | # Graphics support | ||
760 | # | ||
761 | CONFIG_FIRMWARE_EDID=y | ||
762 | # CONFIG_FB is not set | ||
763 | # CONFIG_BACKLIGHT_LCD_SUPPORT is not set | ||
764 | |||
765 | # | ||
766 | # Sound | ||
767 | # | ||
768 | # CONFIG_SOUND is not set | ||
769 | |||
770 | # | ||
771 | # USB support | ||
772 | # | ||
773 | CONFIG_USB_ARCH_HAS_HCD=y | ||
774 | CONFIG_USB_ARCH_HAS_OHCI=y | ||
775 | CONFIG_USB_ARCH_HAS_EHCI=y | ||
776 | # CONFIG_USB is not set | ||
777 | |||
778 | # | ||
779 | # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' | ||
780 | # | ||
781 | |||
782 | # | ||
783 | # USB Gadget Support | ||
784 | # | ||
785 | # CONFIG_USB_GADGET is not set | ||
786 | |||
787 | # | ||
788 | # MMC/SD Card support | ||
789 | # | ||
790 | # CONFIG_MMC is not set | ||
791 | |||
792 | # | ||
793 | # LED devices | ||
794 | # | ||
795 | # CONFIG_NEW_LEDS is not set | ||
796 | |||
797 | # | ||
798 | # LED drivers | ||
799 | # | ||
800 | |||
801 | # | ||
802 | # LED Triggers | ||
803 | # | ||
804 | |||
805 | # | ||
806 | # InfiniBand support | ||
807 | # | ||
808 | # CONFIG_INFINIBAND is not set | ||
809 | |||
810 | # | ||
811 | # EDAC - error detection and reporting (RAS) (EXPERIMENTAL) | ||
812 | # | ||
813 | |||
814 | # | ||
815 | # Real Time Clock | ||
816 | # | ||
817 | # CONFIG_RTC_CLASS is not set | ||
818 | |||
819 | # | ||
820 | # DMA Engine support | ||
821 | # | ||
822 | # CONFIG_DMA_ENGINE is not set | ||
823 | |||
824 | # | ||
825 | # DMA Clients | ||
826 | # | ||
827 | |||
828 | # | ||
829 | # DMA Devices | ||
830 | # | ||
831 | |||
832 | # | ||
833 | # File systems | ||
834 | # | ||
835 | CONFIG_EXT2_FS=y | ||
836 | # CONFIG_EXT2_FS_XATTR is not set | ||
837 | # CONFIG_EXT2_FS_XIP is not set | ||
838 | CONFIG_EXT3_FS=y | ||
839 | CONFIG_EXT3_FS_XATTR=y | ||
840 | # CONFIG_EXT3_FS_POSIX_ACL is not set | ||
841 | # CONFIG_EXT3_FS_SECURITY is not set | ||
842 | CONFIG_JBD=y | ||
843 | # CONFIG_JBD_DEBUG is not set | ||
844 | CONFIG_FS_MBCACHE=y | ||
845 | # CONFIG_REISERFS_FS is not set | ||
846 | # CONFIG_JFS_FS is not set | ||
847 | # CONFIG_FS_POSIX_ACL is not set | ||
848 | # CONFIG_XFS_FS is not set | ||
849 | # CONFIG_OCFS2_FS is not set | ||
850 | # CONFIG_MINIX_FS is not set | ||
851 | # CONFIG_ROMFS_FS is not set | ||
852 | CONFIG_INOTIFY=y | ||
853 | CONFIG_INOTIFY_USER=y | ||
854 | # CONFIG_QUOTA is not set | ||
855 | CONFIG_DNOTIFY=y | ||
856 | # CONFIG_AUTOFS_FS is not set | ||
857 | # CONFIG_AUTOFS4_FS is not set | ||
858 | # CONFIG_FUSE_FS is not set | ||
859 | |||
860 | # | ||
861 | # CD-ROM/DVD Filesystems | ||
862 | # | ||
863 | # CONFIG_ISO9660_FS is not set | ||
864 | # CONFIG_UDF_FS is not set | ||
865 | |||
866 | # | ||
867 | # DOS/FAT/NT Filesystems | ||
868 | # | ||
869 | # CONFIG_MSDOS_FS is not set | ||
870 | # CONFIG_VFAT_FS is not set | ||
871 | # CONFIG_NTFS_FS is not set | ||
872 | |||
873 | # | ||
874 | # Pseudo filesystems | ||
875 | # | ||
876 | CONFIG_PROC_FS=y | ||
877 | CONFIG_PROC_KCORE=y | ||
878 | CONFIG_SYSFS=y | ||
879 | CONFIG_TMPFS=y | ||
880 | # CONFIG_HUGETLB_PAGE is not set | ||
881 | CONFIG_RAMFS=y | ||
882 | # CONFIG_CONFIGFS_FS is not set | ||
883 | |||
884 | # | ||
885 | # Miscellaneous filesystems | ||
886 | # | ||
887 | # CONFIG_ADFS_FS is not set | ||
888 | # CONFIG_AFFS_FS is not set | ||
889 | # CONFIG_HFS_FS is not set | ||
890 | # CONFIG_HFSPLUS_FS is not set | ||
891 | # CONFIG_BEFS_FS is not set | ||
892 | # CONFIG_BFS_FS is not set | ||
893 | # CONFIG_EFS_FS is not set | ||
894 | # CONFIG_CRAMFS is not set | ||
895 | # CONFIG_VXFS_FS is not set | ||
896 | # CONFIG_HPFS_FS is not set | ||
897 | # CONFIG_QNX4FS_FS is not set | ||
898 | # CONFIG_SYSV_FS is not set | ||
899 | # CONFIG_UFS_FS is not set | ||
900 | |||
901 | # | ||
902 | # Network File Systems | ||
903 | # | ||
904 | CONFIG_NFS_FS=y | ||
905 | CONFIG_NFS_V3=y | ||
906 | # CONFIG_NFS_V3_ACL is not set | ||
907 | CONFIG_NFS_V4=y | ||
908 | # CONFIG_NFS_DIRECTIO is not set | ||
909 | # CONFIG_NFSD is not set | ||
910 | CONFIG_ROOT_NFS=y | ||
911 | CONFIG_LOCKD=y | ||
912 | CONFIG_LOCKD_V4=y | ||
913 | CONFIG_NFS_COMMON=y | ||
914 | CONFIG_SUNRPC=y | ||
915 | CONFIG_SUNRPC_GSS=y | ||
916 | CONFIG_RPCSEC_GSS_KRB5=y | ||
917 | # CONFIG_RPCSEC_GSS_SPKM3 is not set | ||
918 | # CONFIG_SMB_FS is not set | ||
919 | # CONFIG_CIFS is not set | ||
920 | # CONFIG_NCP_FS is not set | ||
921 | # CONFIG_CODA_FS is not set | ||
922 | # CONFIG_AFS_FS is not set | ||
923 | # CONFIG_9P_FS is not set | ||
924 | |||
925 | # | ||
926 | # Partition Types | ||
927 | # | ||
928 | CONFIG_PARTITION_ADVANCED=y | ||
929 | # CONFIG_ACORN_PARTITION is not set | ||
930 | # CONFIG_OSF_PARTITION is not set | ||
931 | # CONFIG_AMIGA_PARTITION is not set | ||
932 | # CONFIG_ATARI_PARTITION is not set | ||
933 | # CONFIG_MAC_PARTITION is not set | ||
934 | # CONFIG_MSDOS_PARTITION is not set | ||
935 | # CONFIG_LDM_PARTITION is not set | ||
936 | # CONFIG_SGI_PARTITION is not set | ||
937 | # CONFIG_ULTRIX_PARTITION is not set | ||
938 | # CONFIG_SUN_PARTITION is not set | ||
939 | # CONFIG_KARMA_PARTITION is not set | ||
940 | # CONFIG_EFI_PARTITION is not set | ||
941 | |||
942 | # | ||
943 | # Native Language Support | ||
944 | # | ||
945 | # CONFIG_NLS is not set | ||
946 | |||
947 | # | ||
948 | # QE Options | ||
949 | # | ||
950 | # CONFIG_UCC_SLOW is not set | ||
951 | CONFIG_UCC_FAST=y | ||
952 | CONFIG_UCC=y | ||
953 | |||
954 | # | ||
955 | # Library routines | ||
956 | # | ||
957 | # CONFIG_CRC_CCITT is not set | ||
958 | # CONFIG_CRC16 is not set | ||
959 | CONFIG_CRC32=y | ||
960 | # CONFIG_LIBCRC32C is not set | ||
961 | CONFIG_PLIST=y | ||
962 | |||
963 | # | ||
964 | # Instrumentation Support | ||
965 | # | ||
966 | # CONFIG_PROFILING is not set | ||
967 | |||
968 | # | ||
969 | # Kernel hacking | ||
970 | # | ||
971 | # CONFIG_PRINTK_TIME is not set | ||
972 | # CONFIG_MAGIC_SYSRQ is not set | ||
973 | # CONFIG_UNUSED_SYMBOLS is not set | ||
974 | # CONFIG_DEBUG_KERNEL is not set | ||
975 | CONFIG_LOG_BUF_SHIFT=14 | ||
976 | # CONFIG_DEBUG_FS is not set | ||
977 | # CONFIG_BOOTX_TEXT is not set | ||
978 | # CONFIG_SERIAL_TEXT_DEBUG is not set | ||
979 | # CONFIG_PPC_EARLY_DEBUG is not set | ||
980 | |||
981 | # | ||
982 | # Security options | ||
983 | # | ||
984 | # CONFIG_KEYS is not set | ||
985 | # CONFIG_SECURITY is not set | ||
986 | |||
987 | # | ||
988 | # Cryptographic options | ||
989 | # | ||
990 | CONFIG_CRYPTO=y | ||
991 | # CONFIG_CRYPTO_HMAC is not set | ||
992 | # CONFIG_CRYPTO_NULL is not set | ||
993 | # CONFIG_CRYPTO_MD4 is not set | ||
994 | CONFIG_CRYPTO_MD5=y | ||
995 | # CONFIG_CRYPTO_SHA1 is not set | ||
996 | # CONFIG_CRYPTO_SHA256 is not set | ||
997 | # CONFIG_CRYPTO_SHA512 is not set | ||
998 | # CONFIG_CRYPTO_WP512 is not set | ||
999 | # CONFIG_CRYPTO_TGR192 is not set | ||
1000 | CONFIG_CRYPTO_DES=y | ||
1001 | # CONFIG_CRYPTO_BLOWFISH is not set | ||
1002 | # CONFIG_CRYPTO_TWOFISH is not set | ||
1003 | # CONFIG_CRYPTO_SERPENT is not set | ||
1004 | # CONFIG_CRYPTO_AES is not set | ||
1005 | # CONFIG_CRYPTO_CAST5 is not set | ||
1006 | # CONFIG_CRYPTO_CAST6 is not set | ||
1007 | # CONFIG_CRYPTO_TEA is not set | ||
1008 | # CONFIG_CRYPTO_ARC4 is not set | ||
1009 | # CONFIG_CRYPTO_KHAZAD is not set | ||
1010 | # CONFIG_CRYPTO_ANUBIS is not set | ||
1011 | # CONFIG_CRYPTO_DEFLATE is not set | ||
1012 | # CONFIG_CRYPTO_MICHAEL_MIC is not set | ||
1013 | # CONFIG_CRYPTO_CRC32C is not set | ||
1014 | # CONFIG_CRYPTO_TEST is not set | ||
1015 | |||
1016 | # | ||
1017 | # Hardware crypto devices | ||
1018 | # | ||
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 190a57e20765..47a613cdd775 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -763,10 +763,10 @@ struct cpu_spec cpu_specs[] = { | |||
763 | .cpu_setup = __setup_cpu_603, | 763 | .cpu_setup = __setup_cpu_603, |
764 | .platform = "ppc603", | 764 | .platform = "ppc603", |
765 | }, | 765 | }, |
766 | { /* e300 (a 603e core, plus some) on 83xx */ | 766 | { /* e300c1 (a 603e core, plus some) on 83xx */ |
767 | .pvr_mask = 0x7fff0000, | 767 | .pvr_mask = 0x7fff0000, |
768 | .pvr_value = 0x00830000, | 768 | .pvr_value = 0x00830000, |
769 | .cpu_name = "e300", | 769 | .cpu_name = "e300c1", |
770 | .cpu_features = CPU_FTRS_E300, | 770 | .cpu_features = CPU_FTRS_E300, |
771 | .cpu_user_features = COMMON_USER, | 771 | .cpu_user_features = COMMON_USER, |
772 | .icache_bsize = 32, | 772 | .icache_bsize = 32, |
@@ -774,6 +774,17 @@ struct cpu_spec cpu_specs[] = { | |||
774 | .cpu_setup = __setup_cpu_603, | 774 | .cpu_setup = __setup_cpu_603, |
775 | .platform = "ppc603", | 775 | .platform = "ppc603", |
776 | }, | 776 | }, |
777 | { /* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */ | ||
778 | .pvr_mask = 0x7fff0000, | ||
779 | .pvr_value = 0x00840000, | ||
780 | .cpu_name = "e300c2", | ||
781 | .cpu_features = CPU_FTRS_E300, | ||
782 | .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, | ||
783 | .icache_bsize = 32, | ||
784 | .dcache_bsize = 32, | ||
785 | .cpu_setup = __setup_cpu_603, | ||
786 | .platform = "ppc603", | ||
787 | }, | ||
777 | { /* default match, we assume split I/D cache & TB (non-601)... */ | 788 | { /* default match, we assume split I/D cache & TB (non-601)... */ |
778 | .pvr_mask = 0x00000000, | 789 | .pvr_mask = 0x00000000, |
779 | .pvr_value = 0x00000000, | 790 | .pvr_value = 0x00000000, |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 2cd872b5283b..748e74fcf541 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -27,10 +27,7 @@ | |||
27 | #include <asm/ppc_asm.h> | 27 | #include <asm/ppc_asm.h> |
28 | #include <asm/asm-offsets.h> | 28 | #include <asm/asm-offsets.h> |
29 | #include <asm/cputable.h> | 29 | #include <asm/cputable.h> |
30 | 30 | #include <asm/firmware.h> | |
31 | #ifdef CONFIG_PPC_ISERIES | ||
32 | #define DO_SOFT_DISABLE | ||
33 | #endif | ||
34 | 31 | ||
35 | /* | 32 | /* |
36 | * System calls. | 33 | * System calls. |
@@ -91,6 +88,7 @@ system_call_common: | |||
91 | ld r11,exception_marker@toc(r2) | 88 | ld r11,exception_marker@toc(r2) |
92 | std r11,-16(r9) /* "regshere" marker */ | 89 | std r11,-16(r9) /* "regshere" marker */ |
93 | #ifdef CONFIG_PPC_ISERIES | 90 | #ifdef CONFIG_PPC_ISERIES |
91 | BEGIN_FW_FTR_SECTION | ||
94 | /* Hack for handling interrupts when soft-enabling on iSeries */ | 92 | /* Hack for handling interrupts when soft-enabling on iSeries */ |
95 | cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ | 93 | cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ |
96 | andi. r10,r12,MSR_PR /* from kernel */ | 94 | andi. r10,r12,MSR_PR /* from kernel */ |
@@ -98,6 +96,7 @@ system_call_common: | |||
98 | beq hardware_interrupt_entry | 96 | beq hardware_interrupt_entry |
99 | lbz r10,PACAPROCENABLED(r13) | 97 | lbz r10,PACAPROCENABLED(r13) |
100 | std r10,SOFTE(r1) | 98 | std r10,SOFTE(r1) |
99 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
101 | #endif | 100 | #endif |
102 | mfmsr r11 | 101 | mfmsr r11 |
103 | ori r11,r11,MSR_EE | 102 | ori r11,r11,MSR_EE |
@@ -462,6 +461,7 @@ _GLOBAL(ret_from_except_lite) | |||
462 | 461 | ||
463 | restore: | 462 | restore: |
464 | #ifdef CONFIG_PPC_ISERIES | 463 | #ifdef CONFIG_PPC_ISERIES |
464 | BEGIN_FW_FTR_SECTION | ||
465 | ld r5,SOFTE(r1) | 465 | ld r5,SOFTE(r1) |
466 | cmpdi 0,r5,0 | 466 | cmpdi 0,r5,0 |
467 | beq 4f | 467 | beq 4f |
@@ -480,6 +480,7 @@ restore: | |||
480 | b .ret_from_except_lite /* loop back and handle more */ | 480 | b .ret_from_except_lite /* loop back and handle more */ |
481 | 481 | ||
482 | 4: stb r5,PACAPROCENABLED(r13) | 482 | 4: stb r5,PACAPROCENABLED(r13) |
483 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
483 | #endif | 484 | #endif |
484 | 485 | ||
485 | ld r3,_MSR(r1) | 486 | ld r3,_MSR(r1) |
@@ -538,18 +539,23 @@ do_work: | |||
538 | lwz r8,TI_PREEMPT(r9) | 539 | lwz r8,TI_PREEMPT(r9) |
539 | cmpwi cr1,r8,0 | 540 | cmpwi cr1,r8,0 |
540 | #ifdef CONFIG_PPC_ISERIES | 541 | #ifdef CONFIG_PPC_ISERIES |
542 | BEGIN_FW_FTR_SECTION | ||
541 | ld r0,SOFTE(r1) | 543 | ld r0,SOFTE(r1) |
542 | cmpdi r0,0 | 544 | cmpdi r0,0 |
543 | #else | 545 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
544 | andi. r0,r3,MSR_EE | ||
545 | #endif | 546 | #endif |
547 | BEGIN_FW_FTR_SECTION | ||
548 | andi. r0,r3,MSR_EE | ||
549 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
546 | crandc eq,cr1*4+eq,eq | 550 | crandc eq,cr1*4+eq,eq |
547 | bne restore | 551 | bne restore |
548 | /* here we are preempting the current task */ | 552 | /* here we are preempting the current task */ |
549 | 1: | 553 | 1: |
550 | #ifdef CONFIG_PPC_ISERIES | 554 | #ifdef CONFIG_PPC_ISERIES |
555 | BEGIN_FW_FTR_SECTION | ||
551 | li r0,1 | 556 | li r0,1 |
552 | stb r0,PACAPROCENABLED(r13) | 557 | stb r0,PACAPROCENABLED(r13) |
558 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
553 | #endif | 559 | #endif |
554 | ori r10,r10,MSR_EE | 560 | ori r10,r10,MSR_EE |
555 | mtmsrd r10,1 /* reenable interrupts */ | 561 | mtmsrd r10,1 /* reenable interrupts */ |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 3065b472b95d..645c7f10fb28 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/hvcall.h> | 33 | #include <asm/hvcall.h> |
34 | #include <asm/iseries/lpar_map.h> | 34 | #include <asm/iseries/lpar_map.h> |
35 | #include <asm/thread_info.h> | 35 | #include <asm/thread_info.h> |
36 | #include <asm/firmware.h> | ||
36 | 37 | ||
37 | #ifdef CONFIG_PPC_ISERIES | 38 | #ifdef CONFIG_PPC_ISERIES |
38 | #define DO_SOFT_DISABLE | 39 | #define DO_SOFT_DISABLE |
@@ -365,19 +366,28 @@ label##_iSeries: \ | |||
365 | 366 | ||
366 | #ifdef DO_SOFT_DISABLE | 367 | #ifdef DO_SOFT_DISABLE |
367 | #define DISABLE_INTS \ | 368 | #define DISABLE_INTS \ |
369 | BEGIN_FW_FTR_SECTION; \ | ||
368 | lbz r10,PACAPROCENABLED(r13); \ | 370 | lbz r10,PACAPROCENABLED(r13); \ |
369 | li r11,0; \ | 371 | li r11,0; \ |
370 | std r10,SOFTE(r1); \ | 372 | std r10,SOFTE(r1); \ |
371 | mfmsr r10; \ | 373 | mfmsr r10; \ |
372 | stb r11,PACAPROCENABLED(r13); \ | 374 | stb r11,PACAPROCENABLED(r13); \ |
373 | ori r10,r10,MSR_EE; \ | 375 | ori r10,r10,MSR_EE; \ |
374 | mtmsrd r10,1 | 376 | mtmsrd r10,1; \ |
377 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
375 | 378 | ||
376 | #define ENABLE_INTS \ | 379 | #define ENABLE_INTS \ |
380 | BEGIN_FW_FTR_SECTION; \ | ||
377 | lbz r10,PACAPROCENABLED(r13); \ | 381 | lbz r10,PACAPROCENABLED(r13); \ |
378 | mfmsr r11; \ | 382 | mfmsr r11; \ |
379 | std r10,SOFTE(r1); \ | 383 | std r10,SOFTE(r1); \ |
380 | ori r11,r11,MSR_EE; \ | 384 | ori r11,r11,MSR_EE; \ |
385 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \ | ||
386 | BEGIN_FW_FTR_SECTION; \ | ||
387 | ld r12,_MSR(r1); \ | ||
388 | mfmsr r11; \ | ||
389 | rlwimi r11,r12,0,MSR_EE; \ | ||
390 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ | ||
381 | mtmsrd r11,1 | 391 | mtmsrd r11,1 |
382 | 392 | ||
383 | #else /* hard enable/disable interrupts */ | 393 | #else /* hard enable/disable interrupts */ |
@@ -1071,8 +1081,10 @@ _GLOBAL(slb_miss_realmode) | |||
1071 | ld r3,PACA_EXSLB+EX_R3(r13) | 1081 | ld r3,PACA_EXSLB+EX_R3(r13) |
1072 | lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ | 1082 | lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ |
1073 | #ifdef CONFIG_PPC_ISERIES | 1083 | #ifdef CONFIG_PPC_ISERIES |
1084 | BEGIN_FW_FTR_SECTION | ||
1074 | ld r11,PACALPPACAPTR(r13) | 1085 | ld r11,PACALPPACAPTR(r13) |
1075 | ld r11,LPPACASRR0(r11) /* get SRR0 value */ | 1086 | ld r11,LPPACASRR0(r11) /* get SRR0 value */ |
1087 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
1076 | #endif /* CONFIG_PPC_ISERIES */ | 1088 | #endif /* CONFIG_PPC_ISERIES */ |
1077 | 1089 | ||
1078 | mtlr r10 | 1090 | mtlr r10 |
@@ -1087,8 +1099,10 @@ _GLOBAL(slb_miss_realmode) | |||
1087 | .machine pop | 1099 | .machine pop |
1088 | 1100 | ||
1089 | #ifdef CONFIG_PPC_ISERIES | 1101 | #ifdef CONFIG_PPC_ISERIES |
1102 | BEGIN_FW_FTR_SECTION | ||
1090 | mtspr SPRN_SRR0,r11 | 1103 | mtspr SPRN_SRR0,r11 |
1091 | mtspr SPRN_SRR1,r12 | 1104 | mtspr SPRN_SRR1,r12 |
1105 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
1092 | #endif /* CONFIG_PPC_ISERIES */ | 1106 | #endif /* CONFIG_PPC_ISERIES */ |
1093 | ld r9,PACA_EXSLB+EX_R9(r13) | 1107 | ld r9,PACA_EXSLB+EX_R9(r13) |
1094 | ld r10,PACA_EXSLB+EX_R10(r13) | 1108 | ld r10,PACA_EXSLB+EX_R10(r13) |
@@ -1301,6 +1315,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | |||
1301 | cmpdi r3,0 /* see if hash_page succeeded */ | 1315 | cmpdi r3,0 /* see if hash_page succeeded */ |
1302 | 1316 | ||
1303 | #ifdef DO_SOFT_DISABLE | 1317 | #ifdef DO_SOFT_DISABLE |
1318 | BEGIN_FW_FTR_SECTION | ||
1304 | /* | 1319 | /* |
1305 | * If we had interrupts soft-enabled at the point where the | 1320 | * If we had interrupts soft-enabled at the point where the |
1306 | * DSI/ISI occurred, and an interrupt came in during hash_page, | 1321 | * DSI/ISI occurred, and an interrupt came in during hash_page, |
@@ -1321,12 +1336,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | |||
1321 | ld r3,SOFTE(r1) | 1336 | ld r3,SOFTE(r1) |
1322 | bl .local_irq_restore | 1337 | bl .local_irq_restore |
1323 | b 11f | 1338 | b 11f |
1324 | #else | 1339 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) |
1340 | #endif | ||
1341 | BEGIN_FW_FTR_SECTION | ||
1325 | beq fast_exception_return /* Return from exception on success */ | 1342 | beq fast_exception_return /* Return from exception on success */ |
1326 | ble- 12f /* Failure return from hash_page */ | 1343 | ble- 12f /* Failure return from hash_page */ |
1327 | 1344 | ||
1328 | /* fall through */ | 1345 | /* fall through */ |
1329 | #endif | 1346 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) |
1330 | 1347 | ||
1331 | /* Here we have a page fault that hash_page can't handle. */ | 1348 | /* Here we have a page fault that hash_page can't handle. */ |
1332 | _GLOBAL(handle_page_fault) | 1349 | _GLOBAL(handle_page_fault) |
@@ -1861,7 +1878,9 @@ _GLOBAL(__secondary_start) | |||
1861 | LOAD_REG_ADDR(r3, .start_secondary_prolog) | 1878 | LOAD_REG_ADDR(r3, .start_secondary_prolog) |
1862 | LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) | 1879 | LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) |
1863 | #ifdef DO_SOFT_DISABLE | 1880 | #ifdef DO_SOFT_DISABLE |
1881 | BEGIN_FW_FTR_SECTION | ||
1864 | ori r4,r4,MSR_EE | 1882 | ori r4,r4,MSR_EE |
1883 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
1865 | #endif | 1884 | #endif |
1866 | mtspr SPRN_SRR0,r3 | 1885 | mtspr SPRN_SRR0,r3 |
1867 | mtspr SPRN_SRR1,r4 | 1886 | mtspr SPRN_SRR1,r4 |
@@ -1986,6 +2005,7 @@ _STATIC(start_here_common) | |||
1986 | */ | 2005 | */ |
1987 | li r3,0 | 2006 | li r3,0 |
1988 | bl .do_cpu_ftr_fixups | 2007 | bl .do_cpu_ftr_fixups |
2008 | bl .do_fw_ftr_fixups | ||
1989 | 2009 | ||
1990 | /* ptr to current */ | 2010 | /* ptr to current */ |
1991 | LOAD_REG_IMMEDIATE(r4, init_task) | 2011 | LOAD_REG_IMMEDIATE(r4, init_task) |
@@ -2000,11 +2020,13 @@ _STATIC(start_here_common) | |||
2000 | /* Load up the kernel context */ | 2020 | /* Load up the kernel context */ |
2001 | 5: | 2021 | 5: |
2002 | #ifdef DO_SOFT_DISABLE | 2022 | #ifdef DO_SOFT_DISABLE |
2023 | BEGIN_FW_FTR_SECTION | ||
2003 | li r5,0 | 2024 | li r5,0 |
2004 | stb r5,PACAPROCENABLED(r13) /* Soft Disabled */ | 2025 | stb r5,PACAPROCENABLED(r13) /* Soft Disabled */ |
2005 | mfmsr r5 | 2026 | mfmsr r5 |
2006 | ori r5,r5,MSR_EE /* Hard Enabled */ | 2027 | ori r5,r5,MSR_EE /* Hard Enabled */ |
2007 | mtmsrd r5 | 2028 | mtmsrd r5 |
2029 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
2008 | #endif | 2030 | #endif |
2009 | 2031 | ||
2010 | bl .start_kernel | 2032 | bl .start_kernel |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 9c54eccad993..41521b30c3cd 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
@@ -325,6 +325,52 @@ _GLOBAL(do_cpu_ftr_fixups) | |||
325 | isync | 325 | isync |
326 | b 1b | 326 | b 1b |
327 | 327 | ||
328 | /* | ||
329 | * do_fw_ftr_fixups - goes through the list of firmware feature fixups | ||
330 | * and writes nop's over sections of code that don't apply for this firmware. | ||
331 | * r3 = data offset (not changed) | ||
332 | */ | ||
333 | _GLOBAL(do_fw_ftr_fixups) | ||
334 | /* Get firmware features */ | ||
335 | LOAD_REG_IMMEDIATE(r6,powerpc_firmware_features) | ||
336 | sub r6,r6,r3 | ||
337 | ld r4,0(r6) | ||
338 | /* Get the fixup table */ | ||
339 | LOAD_REG_IMMEDIATE(r6,__start___fw_ftr_fixup) | ||
340 | sub r6,r6,r3 | ||
341 | LOAD_REG_IMMEDIATE(r7,__stop___fw_ftr_fixup) | ||
342 | sub r7,r7,r3 | ||
343 | /* Do the fixup */ | ||
344 | 1: cmpld r6,r7 | ||
345 | bgelr | ||
346 | addi r6,r6,32 | ||
347 | ld r8,-32(r6) /* mask */ | ||
348 | and r8,r8,r4 | ||
349 | ld r9,-24(r6) /* value */ | ||
350 | cmpld r8,r9 | ||
351 | beq 1b | ||
352 | ld r8,-16(r6) /* section begin */ | ||
353 | ld r9,-8(r6) /* section end */ | ||
354 | subf. r9,r8,r9 | ||
355 | beq 1b | ||
356 | /* write nops over the section of code */ | ||
357 | /* todo: if large section, add a branch at the start of it */ | ||
358 | srwi r9,r9,2 | ||
359 | mtctr r9 | ||
360 | sub r8,r8,r3 | ||
361 | lis r0,0x60000000@h /* nop */ | ||
362 | 3: stw r0,0(r8) | ||
363 | BEGIN_FTR_SECTION | ||
364 | dcbst 0,r8 /* suboptimal, but simpler */ | ||
365 | sync | ||
366 | icbi 0,r8 | ||
367 | END_FTR_SECTION_IFSET(CPU_FTR_SPLIT_ID_CACHE) | ||
368 | addi r8,r8,4 | ||
369 | bdnz 3b | ||
370 | sync /* additional sync needed on g4 */ | ||
371 | isync | ||
372 | b 1b | ||
373 | |||
328 | #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) | 374 | #if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) |
329 | /* | 375 | /* |
330 | * Do an IO access in real mode | 376 | * Do an IO access in real mode |
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index c1b1e14775e4..78d3c0fc8dfb 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/byteorder.h> | 30 | #include <asm/byteorder.h> |
31 | #include <asm/machdep.h> | 31 | #include <asm/machdep.h> |
32 | #include <asm/ppc-pci.h> | 32 | #include <asm/ppc-pci.h> |
33 | #include <asm/firmware.h> | ||
33 | 34 | ||
34 | #ifdef DEBUG | 35 | #ifdef DEBUG |
35 | #include <asm/udbg.h> | 36 | #include <asm/udbg.h> |
@@ -209,7 +210,6 @@ void pcibios_free_controller(struct pci_controller *phb) | |||
209 | kfree(phb); | 210 | kfree(phb); |
210 | } | 211 | } |
211 | 212 | ||
212 | #ifndef CONFIG_PPC_ISERIES | ||
213 | void __devinit pcibios_claim_one_bus(struct pci_bus *b) | 213 | void __devinit pcibios_claim_one_bus(struct pci_bus *b) |
214 | { | 214 | { |
215 | struct pci_dev *dev; | 215 | struct pci_dev *dev; |
@@ -238,10 +238,12 @@ static void __init pcibios_claim_of_setup(void) | |||
238 | { | 238 | { |
239 | struct pci_bus *b; | 239 | struct pci_bus *b; |
240 | 240 | ||
241 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
242 | return; | ||
243 | |||
241 | list_for_each_entry(b, &pci_root_buses, node) | 244 | list_for_each_entry(b, &pci_root_buses, node) |
242 | pcibios_claim_one_bus(b); | 245 | pcibios_claim_one_bus(b); |
243 | } | 246 | } |
244 | #endif | ||
245 | 247 | ||
246 | #ifdef CONFIG_PPC_MULTIPLATFORM | 248 | #ifdef CONFIG_PPC_MULTIPLATFORM |
247 | static u32 get_int_prop(struct device_node *np, const char *name, u32 def) | 249 | static u32 get_int_prop(struct device_node *np, const char *name, u32 def) |
@@ -554,9 +556,8 @@ static int __init pcibios_init(void) | |||
554 | */ | 556 | */ |
555 | ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; | 557 | ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot; |
556 | 558 | ||
557 | #ifdef CONFIG_PPC_ISERIES | 559 | if (firmware_has_feature(FW_FEATURE_ISERIES)) |
558 | iSeries_pcibios_init(); | 560 | iSeries_pcibios_init(); |
559 | #endif | ||
560 | 561 | ||
561 | printk(KERN_DEBUG "PCI: Probing PCI hardware\n"); | 562 | printk(KERN_DEBUG "PCI: Probing PCI hardware\n"); |
562 | 563 | ||
@@ -566,15 +567,15 @@ static int __init pcibios_init(void) | |||
566 | pci_bus_add_devices(hose->bus); | 567 | pci_bus_add_devices(hose->bus); |
567 | } | 568 | } |
568 | 569 | ||
569 | #ifndef CONFIG_PPC_ISERIES | 570 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) { |
570 | if (pci_probe_only) | 571 | if (pci_probe_only) |
571 | pcibios_claim_of_setup(); | 572 | pcibios_claim_of_setup(); |
572 | else | 573 | else |
573 | /* FIXME: `else' will be removed when | 574 | /* FIXME: `else' will be removed when |
574 | pci_assign_unassigned_resources() is able to work | 575 | pci_assign_unassigned_resources() is able to work |
575 | correctly with [partially] allocated PCI tree. */ | 576 | correctly with [partially] allocated PCI tree. */ |
576 | pci_assign_unassigned_resources(); | 577 | pci_assign_unassigned_resources(); |
577 | #endif /* !CONFIG_PPC_ISERIES */ | 578 | } |
578 | 579 | ||
579 | /* Call machine dependent final fixup */ | 580 | /* Call machine dependent final fixup */ |
580 | if (ppc_md.pcibios_fixup) | 581 | if (ppc_md.pcibios_fixup) |
@@ -586,8 +587,9 @@ static int __init pcibios_init(void) | |||
586 | printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); | 587 | printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev)); |
587 | 588 | ||
588 | #ifdef CONFIG_PPC_MULTIPLATFORM | 589 | #ifdef CONFIG_PPC_MULTIPLATFORM |
589 | /* map in PCI I/O space */ | 590 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) |
590 | phbs_remap_io(); | 591 | /* map in PCI I/O space */ |
592 | phbs_remap_io(); | ||
591 | #endif | 593 | #endif |
592 | 594 | ||
593 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); | 595 | printk(KERN_DEBUG "PCI: Probing PCI hardware done\n"); |
@@ -637,13 +639,13 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) | |||
637 | */ | 639 | */ |
638 | int pci_domain_nr(struct pci_bus *bus) | 640 | int pci_domain_nr(struct pci_bus *bus) |
639 | { | 641 | { |
640 | #ifdef CONFIG_PPC_ISERIES | 642 | if (firmware_has_feature(FW_FEATURE_ISERIES)) |
641 | return 0; | 643 | return 0; |
642 | #else | 644 | else { |
643 | struct pci_controller *hose = pci_bus_to_host(bus); | 645 | struct pci_controller *hose = pci_bus_to_host(bus); |
644 | 646 | ||
645 | return hose->global_number; | 647 | return hose->global_number; |
646 | #endif | 648 | } |
647 | } | 649 | } |
648 | 650 | ||
649 | EXPORT_SYMBOL(pci_domain_nr); | 651 | EXPORT_SYMBOL(pci_domain_nr); |
@@ -651,12 +653,12 @@ EXPORT_SYMBOL(pci_domain_nr); | |||
651 | /* Decide whether to display the domain number in /proc */ | 653 | /* Decide whether to display the domain number in /proc */ |
652 | int pci_proc_domain(struct pci_bus *bus) | 654 | int pci_proc_domain(struct pci_bus *bus) |
653 | { | 655 | { |
654 | #ifdef CONFIG_PPC_ISERIES | 656 | if (firmware_has_feature(FW_FEATURE_ISERIES)) |
655 | return 0; | 657 | return 0; |
656 | #else | 658 | else { |
657 | struct pci_controller *hose = pci_bus_to_host(bus); | 659 | struct pci_controller *hose = pci_bus_to_host(bus); |
658 | return hose->buid; | 660 | return hose->buid; |
659 | #endif | 661 | } |
660 | } | 662 | } |
661 | 663 | ||
662 | /* | 664 | /* |
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 0af3fc1bdcc9..89cfaf49d3de 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
@@ -442,31 +442,6 @@ void __init smp_setup_cpu_maps(void) | |||
442 | } | 442 | } |
443 | #endif /* CONFIG_SMP */ | 443 | #endif /* CONFIG_SMP */ |
444 | 444 | ||
445 | int __initdata do_early_xmon; | ||
446 | #ifdef CONFIG_XMON | ||
447 | extern int xmon_no_auto_backtrace; | ||
448 | |||
449 | static int __init early_xmon(char *p) | ||
450 | { | ||
451 | /* ensure xmon is enabled */ | ||
452 | if (p) { | ||
453 | if (strncmp(p, "on", 2) == 0) | ||
454 | xmon_init(1); | ||
455 | if (strncmp(p, "off", 3) == 0) | ||
456 | xmon_init(0); | ||
457 | if (strncmp(p, "nobt", 4) == 0) | ||
458 | xmon_no_auto_backtrace = 1; | ||
459 | if (strncmp(p, "early", 5) != 0) | ||
460 | return 0; | ||
461 | } | ||
462 | xmon_init(1); | ||
463 | do_early_xmon = 1; | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | early_param("xmon", early_xmon); | ||
468 | #endif | ||
469 | |||
470 | static __init int add_pcspkr(void) | 445 | static __init int add_pcspkr(void) |
471 | { | 446 | { |
472 | struct device_node *np; | 447 | struct device_node *np; |
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 79a17795d17b..191d0ab09222 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
@@ -238,12 +238,11 @@ void __init setup_arch(char **cmdline_p) | |||
238 | 238 | ||
239 | smp_setup_cpu_maps(); | 239 | smp_setup_cpu_maps(); |
240 | 240 | ||
241 | #ifdef CONFIG_XMON_DEFAULT | ||
242 | xmon_init(1); | ||
243 | #endif | ||
244 | /* Register early console */ | 241 | /* Register early console */ |
245 | register_early_udbg_console(); | 242 | register_early_udbg_console(); |
246 | 243 | ||
244 | xmon_setup(); | ||
245 | |||
247 | #if defined(CONFIG_KGDB) | 246 | #if defined(CONFIG_KGDB) |
248 | if (ppc_md.kgdb_map_scc) | 247 | if (ppc_md.kgdb_map_scc) |
249 | ppc_md.kgdb_map_scc(); | 248 | ppc_md.kgdb_map_scc(); |
@@ -280,9 +279,6 @@ void __init setup_arch(char **cmdline_p) | |||
280 | init_mm.end_data = (unsigned long) _edata; | 279 | init_mm.end_data = (unsigned long) _edata; |
281 | init_mm.brk = klimit; | 280 | init_mm.brk = klimit; |
282 | 281 | ||
283 | if (do_early_xmon) | ||
284 | debugger(NULL); | ||
285 | |||
286 | /* set up the bootmem stuff with available memory */ | 282 | /* set up the bootmem stuff with available memory */ |
287 | do_init_bootmem(); | 283 | do_init_bootmem(); |
288 | if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); | 284 | if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index cda2dbe70a76..4b2e32eab9dc 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -391,18 +391,14 @@ void __init setup_system(void) | |||
391 | find_legacy_serial_ports(); | 391 | find_legacy_serial_ports(); |
392 | 392 | ||
393 | /* | 393 | /* |
394 | * Initialize xmon | ||
395 | */ | ||
396 | #ifdef CONFIG_XMON_DEFAULT | ||
397 | xmon_init(1); | ||
398 | #endif | ||
399 | /* | ||
400 | * Register early console | 394 | * Register early console |
401 | */ | 395 | */ |
402 | register_early_udbg_console(); | 396 | register_early_udbg_console(); |
403 | 397 | ||
404 | if (do_early_xmon) | 398 | /* |
405 | debugger(NULL); | 399 | * Initialize xmon |
400 | */ | ||
401 | xmon_setup(); | ||
406 | 402 | ||
407 | check_smt_enabled(); | 403 | check_smt_enabled(); |
408 | smp_setup_cpu_maps(); | 404 | smp_setup_cpu_maps(); |
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 02665a02130d..cb0e8d46c3e8 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
@@ -132,6 +132,14 @@ SECTIONS | |||
132 | *(__ftr_fixup) | 132 | *(__ftr_fixup) |
133 | __stop___ftr_fixup = .; | 133 | __stop___ftr_fixup = .; |
134 | } | 134 | } |
135 | #ifdef CONFIG_PPC64 | ||
136 | . = ALIGN(8); | ||
137 | __fw_ftr_fixup : { | ||
138 | __start___fw_ftr_fixup = .; | ||
139 | *(__fw_ftr_fixup) | ||
140 | __stop___fw_ftr_fixup = .; | ||
141 | } | ||
142 | #endif | ||
135 | 143 | ||
136 | . = ALIGN(PAGE_SIZE); | 144 | . = ALIGN(PAGE_SIZE); |
137 | .init.ramfs : { | 145 | .init.ramfs : { |
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index b1da03165496..ac64f4aaa509 100644 --- a/arch/powerpc/mm/pgtable_64.c +++ b/arch/powerpc/mm/pgtable_64.c | |||
@@ -63,32 +63,13 @@ | |||
63 | #include <asm/iommu.h> | 63 | #include <asm/iommu.h> |
64 | #include <asm/abs_addr.h> | 64 | #include <asm/abs_addr.h> |
65 | #include <asm/vdso.h> | 65 | #include <asm/vdso.h> |
66 | #include <asm/firmware.h> | ||
66 | 67 | ||
67 | #include "mmu_decl.h" | 68 | #include "mmu_decl.h" |
68 | 69 | ||
69 | unsigned long ioremap_bot = IMALLOC_BASE; | 70 | unsigned long ioremap_bot = IMALLOC_BASE; |
70 | static unsigned long phbs_io_bot = PHBS_IO_BASE; | 71 | static unsigned long phbs_io_bot = PHBS_IO_BASE; |
71 | 72 | ||
72 | #ifdef CONFIG_PPC_ISERIES | ||
73 | |||
74 | void __iomem *ioremap(unsigned long addr, unsigned long size) | ||
75 | { | ||
76 | return (void __iomem *)addr; | ||
77 | } | ||
78 | |||
79 | extern void __iomem *__ioremap(unsigned long addr, unsigned long size, | ||
80 | unsigned long flags) | ||
81 | { | ||
82 | return (void __iomem *)addr; | ||
83 | } | ||
84 | |||
85 | void iounmap(volatile void __iomem *addr) | ||
86 | { | ||
87 | return; | ||
88 | } | ||
89 | |||
90 | #else | ||
91 | |||
92 | /* | 73 | /* |
93 | * map_io_page currently only called by __ioremap | 74 | * map_io_page currently only called by __ioremap |
94 | * map_io_page adds an entry to the ioremap page table | 75 | * map_io_page adds an entry to the ioremap page table |
@@ -161,6 +142,9 @@ void __iomem * __ioremap(unsigned long addr, unsigned long size, | |||
161 | unsigned long pa, ea; | 142 | unsigned long pa, ea; |
162 | void __iomem *ret; | 143 | void __iomem *ret; |
163 | 144 | ||
145 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
146 | return (void __iomem *)addr; | ||
147 | |||
164 | /* | 148 | /* |
165 | * Choose an address to map it to. | 149 | * Choose an address to map it to. |
166 | * Once the imalloc system is running, we use it. | 150 | * Once the imalloc system is running, we use it. |
@@ -255,6 +239,9 @@ void iounmap(volatile void __iomem *token) | |||
255 | { | 239 | { |
256 | void *addr; | 240 | void *addr; |
257 | 241 | ||
242 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
243 | return; | ||
244 | |||
258 | if (!mem_init_done) | 245 | if (!mem_init_done) |
259 | return; | 246 | return; |
260 | 247 | ||
@@ -315,8 +302,6 @@ int iounmap_explicit(volatile void __iomem *start, unsigned long size) | |||
315 | return 0; | 302 | return 0; |
316 | } | 303 | } |
317 | 304 | ||
318 | #endif | ||
319 | |||
320 | EXPORT_SYMBOL(ioremap); | 305 | EXPORT_SYMBOL(ioremap); |
321 | EXPORT_SYMBOL(__ioremap); | 306 | EXPORT_SYMBOL(__ioremap); |
322 | EXPORT_SYMBOL(iounmap); | 307 | EXPORT_SYMBOL(iounmap); |
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index dbc1abbde038..b10e4707d7c1 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/page.h> | 21 | #include <asm/page.h> |
22 | #include <asm/mmu.h> | 22 | #include <asm/mmu.h> |
23 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
24 | #include <asm/firmware.h> | ||
24 | 25 | ||
25 | /* void slb_allocate_realmode(unsigned long ea); | 26 | /* void slb_allocate_realmode(unsigned long ea); |
26 | * | 27 | * |
@@ -183,6 +184,7 @@ slb_finish_load: | |||
183 | * dont have any LRU information to help us choose a slot. | 184 | * dont have any LRU information to help us choose a slot. |
184 | */ | 185 | */ |
185 | #ifdef CONFIG_PPC_ISERIES | 186 | #ifdef CONFIG_PPC_ISERIES |
187 | BEGIN_FW_FTR_SECTION | ||
186 | /* | 188 | /* |
187 | * On iSeries, the "bolted" stack segment can be cast out on | 189 | * On iSeries, the "bolted" stack segment can be cast out on |
188 | * shared processor switch so we need to check for a miss on | 190 | * shared processor switch so we need to check for a miss on |
@@ -194,6 +196,7 @@ slb_finish_load: | |||
194 | li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */ | 196 | li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */ |
195 | cmpld r9,r3 | 197 | cmpld r9,r3 |
196 | beq 3f | 198 | beq 3f |
199 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
197 | #endif /* CONFIG_PPC_ISERIES */ | 200 | #endif /* CONFIG_PPC_ISERIES */ |
198 | 201 | ||
199 | ld r10,PACASTABRR(r13) | 202 | ld r10,PACASTABRR(r13) |
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig new file mode 100644 index 000000000000..47d841ecf2e2 --- /dev/null +++ b/arch/powerpc/platforms/82xx/Kconfig | |||
@@ -0,0 +1,21 @@ | |||
1 | menu "Platform support" | ||
2 | depends on PPC_82xx | ||
3 | |||
4 | choice | ||
5 | prompt "Machine Type" | ||
6 | default MPC82xx_ADS | ||
7 | |||
8 | config MPC82xx_ADS | ||
9 | bool "Freescale MPC82xx ADS" | ||
10 | select DEFAULT_UIMAGE | ||
11 | select PQ2ADS | ||
12 | select 8272 | ||
13 | select 8260 | ||
14 | select CPM2 | ||
15 | select FSL_SOC | ||
16 | help | ||
17 | This option enables support for the MPC8272 ADS board | ||
18 | |||
19 | endchoice | ||
20 | |||
21 | endmenu | ||
diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile new file mode 100644 index 000000000000..d9fd4c84d2e0 --- /dev/null +++ b/arch/powerpc/platforms/82xx/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | # | ||
2 | # Makefile for the PowerPC 82xx linux kernel. | ||
3 | # | ||
4 | obj-$(CONFIG_PPC_82xx) += mpc82xx.o | ||
5 | obj-$(CONFIG_MPC82xx_ADS) += mpc82xx_ads.o | ||
diff --git a/arch/powerpc/platforms/82xx/m82xx_pci.h b/arch/powerpc/platforms/82xx/m82xx_pci.h new file mode 100644 index 000000000000..9cd8893b5a32 --- /dev/null +++ b/arch/powerpc/platforms/82xx/m82xx_pci.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef _PPC_KERNEL_M82XX_PCI_H | ||
2 | #define _PPC_KERNEL_M82XX_PCI_H | ||
3 | |||
4 | /* | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <asm/m8260_pci.h> | ||
12 | |||
13 | #define SIU_INT_IRQ1 ((uint)0x13 + CPM_IRQ_OFFSET) | ||
14 | |||
15 | #ifndef _IO_BASE | ||
16 | #define _IO_BASE isa_io_base | ||
17 | #endif | ||
18 | |||
19 | #endif /* _PPC_KERNEL_M8260_PCI_H */ | ||
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c new file mode 100644 index 000000000000..89d702de4863 --- /dev/null +++ b/arch/powerpc/platforms/82xx/mpc82xx.c | |||
@@ -0,0 +1,111 @@ | |||
1 | /* | ||
2 | * MPC82xx setup and early boot code plus other random bits. | ||
3 | * | ||
4 | * Author: Vitaly Bordug <vbordug@ru.mvista.com> | ||
5 | * | ||
6 | * Copyright (c) 2006 MontaVista Software, Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/stddef.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/reboot.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/kdev_t.h> | ||
23 | #include <linux/major.h> | ||
24 | #include <linux/console.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/seq_file.h> | ||
27 | #include <linux/root_dev.h> | ||
28 | #include <linux/initrd.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/fsl_devices.h> | ||
31 | #include <linux/fs_uart_pd.h> | ||
32 | |||
33 | #include <asm/system.h> | ||
34 | #include <asm/pgtable.h> | ||
35 | #include <asm/page.h> | ||
36 | #include <asm/atomic.h> | ||
37 | #include <asm/time.h> | ||
38 | #include <asm/io.h> | ||
39 | #include <asm/machdep.h> | ||
40 | #include <asm/bootinfo.h> | ||
41 | #include <asm/pci-bridge.h> | ||
42 | #include <asm/mpc8260.h> | ||
43 | #include <asm/irq.h> | ||
44 | #include <mm/mmu_decl.h> | ||
45 | #include <asm/prom.h> | ||
46 | #include <asm/cpm2.h> | ||
47 | #include <asm/udbg.h> | ||
48 | #include <asm/i8259.h> | ||
49 | #include <linux/fs_enet_pd.h> | ||
50 | |||
51 | #include <sysdev/fsl_soc.h> | ||
52 | #include <sysdev/cpm2_pic.h> | ||
53 | |||
54 | #include "pq2ads_pd.h" | ||
55 | |||
56 | static int __init get_freq(char *name, unsigned long *val) | ||
57 | { | ||
58 | struct device_node *cpu; | ||
59 | unsigned int *fp; | ||
60 | int found = 0; | ||
61 | |||
62 | /* The cpu node should have timebase and clock frequency properties */ | ||
63 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
64 | |||
65 | if (cpu) { | ||
66 | fp = (unsigned int *)get_property(cpu, name, NULL); | ||
67 | if (fp) { | ||
68 | found = 1; | ||
69 | *val = *fp++; | ||
70 | } | ||
71 | |||
72 | of_node_put(cpu); | ||
73 | } | ||
74 | |||
75 | return found; | ||
76 | } | ||
77 | |||
78 | void __init m82xx_calibrate_decr(void) | ||
79 | { | ||
80 | ppc_tb_freq = 125000000; | ||
81 | if (!get_freq("bus-frequency", &ppc_tb_freq)) { | ||
82 | printk(KERN_ERR "WARNING: Estimating decrementer frequency " | ||
83 | "(not found)\n"); | ||
84 | } | ||
85 | ppc_tb_freq /= 4; | ||
86 | ppc_proc_freq = 1000000000; | ||
87 | if (!get_freq("clock-frequency", &ppc_proc_freq)) | ||
88 | printk(KERN_ERR "WARNING: Estimating processor frequency" | ||
89 | "(not found)\n"); | ||
90 | } | ||
91 | |||
92 | void mpc82xx_ads_show_cpuinfo(struct seq_file *m) | ||
93 | { | ||
94 | uint pvid, svid, phid1; | ||
95 | uint memsize = total_memory; | ||
96 | |||
97 | pvid = mfspr(SPRN_PVR); | ||
98 | svid = mfspr(SPRN_SVR); | ||
99 | |||
100 | seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); | ||
101 | seq_printf(m, "Machine\t\t: %s\n", CPUINFO_MACHINE); | ||
102 | seq_printf(m, "PVR\t\t: 0x%x\n", pvid); | ||
103 | seq_printf(m, "SVR\t\t: 0x%x\n", svid); | ||
104 | |||
105 | /* Display cpu Pll setting */ | ||
106 | phid1 = mfspr(SPRN_HID1); | ||
107 | seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); | ||
108 | |||
109 | /* Display the amount of memory */ | ||
110 | seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); | ||
111 | } | ||
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c new file mode 100644 index 000000000000..4276f087f26e --- /dev/null +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c | |||
@@ -0,0 +1,661 @@ | |||
1 | /* | ||
2 | * MPC82xx_ads setup and early boot code plus other random bits. | ||
3 | * | ||
4 | * Author: Vitaly Bordug <vbordug@ru.mvista.com> | ||
5 | * m82xx_restart fix by Wade Farnsworth <wfarnsworth@mvista.com> | ||
6 | * | ||
7 | * Copyright (c) 2006 MontaVista Software, Inc. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | */ | ||
14 | |||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/stddef.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/reboot.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/kdev_t.h> | ||
25 | #include <linux/major.h> | ||
26 | #include <linux/console.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/seq_file.h> | ||
29 | #include <linux/root_dev.h> | ||
30 | #include <linux/initrd.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/fsl_devices.h> | ||
33 | #include <linux/fs_uart_pd.h> | ||
34 | |||
35 | #include <asm/system.h> | ||
36 | #include <asm/pgtable.h> | ||
37 | #include <asm/page.h> | ||
38 | #include <asm/atomic.h> | ||
39 | #include <asm/time.h> | ||
40 | #include <asm/io.h> | ||
41 | #include <asm/machdep.h> | ||
42 | #include <asm/bootinfo.h> | ||
43 | #include <asm/pci-bridge.h> | ||
44 | #include <asm/mpc8260.h> | ||
45 | #include <asm/irq.h> | ||
46 | #include <mm/mmu_decl.h> | ||
47 | #include <asm/prom.h> | ||
48 | #include <asm/cpm2.h> | ||
49 | #include <asm/udbg.h> | ||
50 | #include <asm/i8259.h> | ||
51 | #include <linux/fs_enet_pd.h> | ||
52 | |||
53 | #include <sysdev/fsl_soc.h> | ||
54 | #include <../sysdev/cpm2_pic.h> | ||
55 | |||
56 | #include "pq2ads_pd.h" | ||
57 | |||
58 | #ifdef CONFIG_PCI | ||
59 | static uint pci_clk_frq; | ||
60 | static struct { | ||
61 | unsigned long *pci_int_stat_reg; | ||
62 | unsigned long *pci_int_mask_reg; | ||
63 | } pci_regs; | ||
64 | |||
65 | static unsigned long pci_int_base; | ||
66 | static struct irq_host *pci_pic_host; | ||
67 | static struct device_node *pci_pic_node; | ||
68 | #endif | ||
69 | |||
70 | static void __init mpc82xx_ads_pic_init(void) | ||
71 | { | ||
72 | struct device_node *np = of_find_compatible_node(NULL, "cpm-pic", "CPM2"); | ||
73 | struct resource r; | ||
74 | cpm2_map_t *cpm_reg; | ||
75 | |||
76 | if (np == NULL) { | ||
77 | printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); | ||
78 | return; | ||
79 | } | ||
80 | if (of_address_to_resource(np, 0, &r)) { | ||
81 | printk(KERN_ERR "PIC init: invalid resource\n"); | ||
82 | of_node_put(np); | ||
83 | return; | ||
84 | } | ||
85 | cpm2_pic_init(np); | ||
86 | of_node_put(np); | ||
87 | |||
88 | /* Initialize the default interrupt mapping priorities, | ||
89 | * in case the boot rom changed something on us. | ||
90 | */ | ||
91 | cpm_reg = (cpm2_map_t *) ioremap(get_immrbase(), sizeof(cpm2_map_t)); | ||
92 | cpm_reg->im_intctl.ic_siprr = 0x05309770; | ||
93 | iounmap(cpm_reg); | ||
94 | #ifdef CONFIG_PCI | ||
95 | /* Initialize stuff for the 82xx CPLD IC and install demux */ | ||
96 | m82xx_pci_init_irq(); | ||
97 | #endif | ||
98 | } | ||
99 | |||
100 | static void init_fcc1_ioports(struct fs_platform_info *fpi) | ||
101 | { | ||
102 | struct io_port *io; | ||
103 | u32 tempval; | ||
104 | cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); | ||
105 | struct device_node *np; | ||
106 | struct resource r; | ||
107 | u32 *bcsr; | ||
108 | |||
109 | np = of_find_node_by_type(NULL, "memory"); | ||
110 | if (!np) { | ||
111 | printk(KERN_INFO "No memory node in device tree\n"); | ||
112 | return; | ||
113 | } | ||
114 | if (of_address_to_resource(np, 1, &r)) { | ||
115 | printk(KERN_INFO "No memory reg property [1] in devicetree\n"); | ||
116 | return; | ||
117 | } | ||
118 | of_node_put(np); | ||
119 | bcsr = ioremap(r.start + 4, sizeof(u32)); | ||
120 | io = &immap->im_ioport; | ||
121 | |||
122 | /* Enable the PHY */ | ||
123 | clrbits32(bcsr, BCSR1_FETHIEN); | ||
124 | setbits32(bcsr, BCSR1_FETH_RST); | ||
125 | |||
126 | /* FCC1 pins are on port A/C. */ | ||
127 | /* Configure port A and C pins for FCC1 Ethernet. */ | ||
128 | |||
129 | tempval = in_be32(&io->iop_pdira); | ||
130 | tempval &= ~PA1_DIRA0; | ||
131 | tempval |= PA1_DIRA1; | ||
132 | out_be32(&io->iop_pdira, tempval); | ||
133 | |||
134 | tempval = in_be32(&io->iop_psora); | ||
135 | tempval &= ~PA1_PSORA0; | ||
136 | tempval |= PA1_PSORA1; | ||
137 | out_be32(&io->iop_psora, tempval); | ||
138 | |||
139 | setbits32(&io->iop_ppara, PA1_DIRA0 | PA1_DIRA1); | ||
140 | |||
141 | /* Alter clocks */ | ||
142 | tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8); | ||
143 | |||
144 | clrbits32(&io->iop_psorc, tempval); | ||
145 | clrbits32(&io->iop_pdirc, tempval); | ||
146 | setbits32(&io->iop_pparc, tempval); | ||
147 | |||
148 | cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_rx, CPM_CLK_RX); | ||
149 | cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_tx, CPM_CLK_TX); | ||
150 | |||
151 | iounmap(bcsr); | ||
152 | iounmap(immap); | ||
153 | } | ||
154 | |||
155 | static void init_fcc2_ioports(struct fs_platform_info *fpi) | ||
156 | { | ||
157 | cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); | ||
158 | struct device_node *np; | ||
159 | struct resource r; | ||
160 | u32 *bcsr; | ||
161 | |||
162 | struct io_port *io; | ||
163 | u32 tempval; | ||
164 | |||
165 | np = of_find_node_by_type(NULL, "memory"); | ||
166 | if (!np) { | ||
167 | printk(KERN_INFO "No memory node in device tree\n"); | ||
168 | return; | ||
169 | } | ||
170 | if (of_address_to_resource(np, 1, &r)) { | ||
171 | printk(KERN_INFO "No memory reg property [1] in devicetree\n"); | ||
172 | return; | ||
173 | } | ||
174 | of_node_put(np); | ||
175 | io = &immap->im_ioport; | ||
176 | bcsr = ioremap(r.start + 12, sizeof(u32)); | ||
177 | |||
178 | /* Enable the PHY */ | ||
179 | clrbits32(bcsr, BCSR3_FETHIEN2); | ||
180 | setbits32(bcsr, BCSR3_FETH2_RST); | ||
181 | |||
182 | /* FCC2 are port B/C. */ | ||
183 | /* Configure port A and C pins for FCC2 Ethernet. */ | ||
184 | |||
185 | tempval = in_be32(&io->iop_pdirb); | ||
186 | tempval &= ~PB2_DIRB0; | ||
187 | tempval |= PB2_DIRB1; | ||
188 | out_be32(&io->iop_pdirb, tempval); | ||
189 | |||
190 | tempval = in_be32(&io->iop_psorb); | ||
191 | tempval &= ~PB2_PSORB0; | ||
192 | tempval |= PB2_PSORB1; | ||
193 | out_be32(&io->iop_psorb, tempval); | ||
194 | |||
195 | setbits32(&io->iop_pparb, PB2_DIRB0 | PB2_DIRB1); | ||
196 | |||
197 | tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8); | ||
198 | |||
199 | /* Alter clocks */ | ||
200 | clrbits32(&io->iop_psorc, tempval); | ||
201 | clrbits32(&io->iop_pdirc, tempval); | ||
202 | setbits32(&io->iop_pparc, tempval); | ||
203 | |||
204 | cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_rx, CPM_CLK_RX); | ||
205 | cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_tx, CPM_CLK_TX); | ||
206 | |||
207 | iounmap(bcsr); | ||
208 | iounmap(immap); | ||
209 | } | ||
210 | |||
211 | void init_fcc_ioports(struct fs_platform_info *fpi) | ||
212 | { | ||
213 | int fcc_no = fs_get_fcc_index(fpi->fs_no); | ||
214 | |||
215 | switch (fcc_no) { | ||
216 | case 0: | ||
217 | init_fcc1_ioports(fpi); | ||
218 | break; | ||
219 | case 1: | ||
220 | init_fcc2_ioports(fpi); | ||
221 | break; | ||
222 | default: | ||
223 | printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n"); | ||
224 | return; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | static void init_scc1_uart_ioports(struct fs_uart_platform_info *data) | ||
229 | { | ||
230 | cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); | ||
231 | |||
232 | /* SCC1 is only on port D */ | ||
233 | setbits32(&immap->im_ioport.iop_ppard, 0x00000003); | ||
234 | clrbits32(&immap->im_ioport.iop_psord, 0x00000001); | ||
235 | setbits32(&immap->im_ioport.iop_psord, 0x00000002); | ||
236 | clrbits32(&immap->im_ioport.iop_pdird, 0x00000001); | ||
237 | setbits32(&immap->im_ioport.iop_pdird, 0x00000002); | ||
238 | |||
239 | clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx))); | ||
240 | clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx))); | ||
241 | setbits32(&immap->im_cpmux.cmx_scr, | ||
242 | ((data->clk_tx - 1) << (4 - data->clk_tx))); | ||
243 | setbits32(&immap->im_cpmux.cmx_scr, | ||
244 | ((data->clk_rx - 1) << (4 - data->clk_rx))); | ||
245 | |||
246 | iounmap(immap); | ||
247 | } | ||
248 | |||
249 | static void init_scc4_uart_ioports(struct fs_uart_platform_info *data) | ||
250 | { | ||
251 | cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); | ||
252 | |||
253 | setbits32(&immap->im_ioport.iop_ppard, 0x00000600); | ||
254 | clrbits32(&immap->im_ioport.iop_psord, 0x00000600); | ||
255 | clrbits32(&immap->im_ioport.iop_pdird, 0x00000200); | ||
256 | setbits32(&immap->im_ioport.iop_pdird, 0x00000400); | ||
257 | |||
258 | clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx))); | ||
259 | clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx))); | ||
260 | setbits32(&immap->im_cpmux.cmx_scr, | ||
261 | ((data->clk_tx - 1) << (4 - data->clk_tx))); | ||
262 | setbits32(&immap->im_cpmux.cmx_scr, | ||
263 | ((data->clk_rx - 1) << (4 - data->clk_rx))); | ||
264 | |||
265 | iounmap(immap); | ||
266 | } | ||
267 | |||
268 | void init_scc_ioports(struct fs_uart_platform_info *data) | ||
269 | { | ||
270 | int scc_no = fs_get_scc_index(data->fs_no); | ||
271 | |||
272 | switch (scc_no) { | ||
273 | case 0: | ||
274 | init_scc1_uart_ioports(data); | ||
275 | data->brg = data->clk_rx; | ||
276 | break; | ||
277 | case 3: | ||
278 | init_scc4_uart_ioports(data); | ||
279 | data->brg = data->clk_rx; | ||
280 | break; | ||
281 | default: | ||
282 | printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); | ||
283 | return; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | void __init m82xx_board_setup(void) | ||
288 | { | ||
289 | cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t)); | ||
290 | struct device_node *np; | ||
291 | struct resource r; | ||
292 | u32 *bcsr; | ||
293 | |||
294 | np = of_find_node_by_type(NULL, "memory"); | ||
295 | if (!np) { | ||
296 | printk(KERN_INFO "No memory node in device tree\n"); | ||
297 | return; | ||
298 | } | ||
299 | if (of_address_to_resource(np, 1, &r)) { | ||
300 | printk(KERN_INFO "No memory reg property [1] in devicetree\n"); | ||
301 | return; | ||
302 | } | ||
303 | of_node_put(np); | ||
304 | bcsr = ioremap(r.start + 4, sizeof(u32)); | ||
305 | /* Enable the 2nd UART port */ | ||
306 | clrbits32(bcsr, BCSR1_RS232_EN2); | ||
307 | |||
308 | #ifdef CONFIG_SERIAL_CPM_SCC1 | ||
309 | clrbits32((u32 *) & immap->im_scc[0].scc_sccm, | ||
310 | UART_SCCM_TX | UART_SCCM_RX); | ||
311 | clrbits32((u32 *) & immap->im_scc[0].scc_gsmrl, | ||
312 | SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
313 | #endif | ||
314 | |||
315 | #ifdef CONFIG_SERIAL_CPM_SCC2 | ||
316 | clrbits32((u32 *) & immap->im_scc[1].scc_sccm, | ||
317 | UART_SCCM_TX | UART_SCCM_RX); | ||
318 | clrbits32((u32 *) & immap->im_scc[1].scc_gsmrl, | ||
319 | SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
320 | #endif | ||
321 | |||
322 | #ifdef CONFIG_SERIAL_CPM_SCC3 | ||
323 | clrbits32((u32 *) & immap->im_scc[2].scc_sccm, | ||
324 | UART_SCCM_TX | UART_SCCM_RX); | ||
325 | clrbits32((u32 *) & immap->im_scc[2].scc_gsmrl, | ||
326 | SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
327 | #endif | ||
328 | |||
329 | #ifdef CONFIG_SERIAL_CPM_SCC4 | ||
330 | clrbits32((u32 *) & immap->im_scc[3].scc_sccm, | ||
331 | UART_SCCM_TX | UART_SCCM_RX); | ||
332 | clrbits32((u32 *) & immap->im_scc[3].scc_gsmrl, | ||
333 | SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
334 | #endif | ||
335 | |||
336 | iounmap(bcsr); | ||
337 | iounmap(immap); | ||
338 | } | ||
339 | |||
340 | #ifdef CONFIG_PCI | ||
341 | static void m82xx_pci_mask_irq(unsigned int irq) | ||
342 | { | ||
343 | int bit = irq - pci_int_base; | ||
344 | |||
345 | *pci_regs.pci_int_mask_reg |= (1 << (31 - bit)); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | static void m82xx_pci_unmask_irq(unsigned int irq) | ||
350 | { | ||
351 | int bit = irq - pci_int_base; | ||
352 | |||
353 | *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit)); | ||
354 | return; | ||
355 | } | ||
356 | |||
357 | static void m82xx_pci_mask_and_ack(unsigned int irq) | ||
358 | { | ||
359 | int bit = irq - pci_int_base; | ||
360 | |||
361 | *pci_regs.pci_int_mask_reg |= (1 << (31 - bit)); | ||
362 | return; | ||
363 | } | ||
364 | |||
365 | static void m82xx_pci_end_irq(unsigned int irq) | ||
366 | { | ||
367 | int bit = irq - pci_int_base; | ||
368 | |||
369 | *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit)); | ||
370 | return; | ||
371 | } | ||
372 | |||
373 | struct hw_interrupt_type m82xx_pci_ic = { | ||
374 | .typename = "MPC82xx ADS PCI", | ||
375 | .name = "MPC82xx ADS PCI", | ||
376 | .enable = m82xx_pci_unmask_irq, | ||
377 | .disable = m82xx_pci_mask_irq, | ||
378 | .ack = m82xx_pci_mask_and_ack, | ||
379 | .end = m82xx_pci_end_irq, | ||
380 | .mask = m82xx_pci_mask_irq, | ||
381 | .mask_ack = m82xx_pci_mask_and_ack, | ||
382 | .unmask = m82xx_pci_unmask_irq, | ||
383 | .eoi = m82xx_pci_end_irq, | ||
384 | }; | ||
385 | |||
386 | static void | ||
387 | m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc, | ||
388 | struct pt_regs *regs) | ||
389 | { | ||
390 | unsigned long stat, mask, pend; | ||
391 | int bit; | ||
392 | |||
393 | for (;;) { | ||
394 | stat = *pci_regs.pci_int_stat_reg; | ||
395 | mask = *pci_regs.pci_int_mask_reg; | ||
396 | pend = stat & ~mask & 0xf0000000; | ||
397 | if (!pend) | ||
398 | break; | ||
399 | for (bit = 0; pend != 0; ++bit, pend <<= 1) { | ||
400 | if (pend & 0x80000000) | ||
401 | __do_IRQ(pci_int_base + bit, regs); | ||
402 | } | ||
403 | } | ||
404 | } | ||
405 | |||
406 | static int pci_pic_host_match(struct irq_host *h, struct device_node *node) | ||
407 | { | ||
408 | return node == pci_pic_node; | ||
409 | } | ||
410 | |||
411 | static int pci_pic_host_map(struct irq_host *h, unsigned int virq, | ||
412 | irq_hw_number_t hw) | ||
413 | { | ||
414 | get_irq_desc(virq)->status |= IRQ_LEVEL; | ||
415 | set_irq_chip(virq, &m82xx_pci_ic); | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static void pci_host_unmap(struct irq_host *h, unsigned int virq) | ||
420 | { | ||
421 | /* remove chip and handler */ | ||
422 | set_irq_chip(virq, NULL); | ||
423 | } | ||
424 | |||
425 | static struct irq_host_ops pci_pic_host_ops = { | ||
426 | .match = pci_pic_host_match, | ||
427 | .map = pci_pic_host_map, | ||
428 | .unmap = pci_host_unmap, | ||
429 | }; | ||
430 | |||
431 | void m82xx_pci_init_irq(void) | ||
432 | { | ||
433 | int irq; | ||
434 | cpm2_map_t *immap; | ||
435 | struct device_node *np; | ||
436 | struct resource r; | ||
437 | const u32 *regs; | ||
438 | unsigned int size; | ||
439 | const u32 *irq_map; | ||
440 | int i; | ||
441 | unsigned int irq_max, irq_min; | ||
442 | |||
443 | if ((np = of_find_node_by_type(NULL, "soc")) == NULL) { | ||
444 | printk(KERN_INFO "No SOC node in device tree\n"); | ||
445 | return; | ||
446 | } | ||
447 | memset(&r, 0, sizeof(r)); | ||
448 | if (of_address_to_resource(np, 0, &r)) { | ||
449 | printk(KERN_INFO "No SOC reg property in device tree\n"); | ||
450 | return; | ||
451 | } | ||
452 | immap = ioremap(r.start, sizeof(*immap)); | ||
453 | of_node_put(np); | ||
454 | |||
455 | /* install the demultiplexer for the PCI cascade interrupt */ | ||
456 | np = of_find_node_by_type(NULL, "pci"); | ||
457 | if (!np) { | ||
458 | printk(KERN_INFO "No pci node on device tree\n"); | ||
459 | iounmap(immap); | ||
460 | return; | ||
461 | } | ||
462 | irq_map = get_property(np, "interrupt-map", &size); | ||
463 | if ((!irq_map) || (size <= 7)) { | ||
464 | printk(KERN_INFO "No interrupt-map property of pci node\n"); | ||
465 | iounmap(immap); | ||
466 | return; | ||
467 | } | ||
468 | size /= sizeof(irq_map[0]); | ||
469 | for (i = 0, irq_max = 0, irq_min = 512; i < size; i += 7, irq_map += 7) { | ||
470 | if (irq_map[5] < irq_min) | ||
471 | irq_min = irq_map[5]; | ||
472 | if (irq_map[5] > irq_max) | ||
473 | irq_max = irq_map[5]; | ||
474 | } | ||
475 | pci_int_base = irq_min; | ||
476 | irq = irq_of_parse_and_map(np, 0); | ||
477 | set_irq_chained_handler(irq, m82xx_pci_irq_demux); | ||
478 | of_node_put(np); | ||
479 | np = of_find_node_by_type(NULL, "pci-pic"); | ||
480 | if (!np) { | ||
481 | printk(KERN_INFO "No pci pic node on device tree\n"); | ||
482 | iounmap(immap); | ||
483 | return; | ||
484 | } | ||
485 | pci_pic_node = of_node_get(np); | ||
486 | /* PCI interrupt controller registers: status and mask */ | ||
487 | regs = get_property(np, "reg", &size); | ||
488 | if ((!regs) || (size <= 2)) { | ||
489 | printk(KERN_INFO "No reg property in pci pic node\n"); | ||
490 | iounmap(immap); | ||
491 | return; | ||
492 | } | ||
493 | pci_regs.pci_int_stat_reg = | ||
494 | ioremap(regs[0], sizeof(*pci_regs.pci_int_stat_reg)); | ||
495 | pci_regs.pci_int_mask_reg = | ||
496 | ioremap(regs[1], sizeof(*pci_regs.pci_int_mask_reg)); | ||
497 | of_node_put(np); | ||
498 | /* configure chip select for PCI interrupt controller */ | ||
499 | immap->im_memctl.memc_br3 = regs[0] | 0x00001801; | ||
500 | immap->im_memctl.memc_or3 = 0xffff8010; | ||
501 | /* make PCI IRQ level sensitive */ | ||
502 | immap->im_intctl.ic_siexr &= ~(1 << (14 - (irq - SIU_INT_IRQ1))); | ||
503 | |||
504 | /* mask all PCI interrupts */ | ||
505 | *pci_regs.pci_int_mask_reg |= 0xfff00000; | ||
506 | iounmap(immap); | ||
507 | pci_pic_host = | ||
508 | irq_alloc_host(IRQ_HOST_MAP_LINEAR, irq_max - irq_min + 1, | ||
509 | &pci_pic_host_ops, irq_max + 1); | ||
510 | return; | ||
511 | } | ||
512 | |||
513 | static int m82xx_pci_exclude_device(u_char bus, u_char devfn) | ||
514 | { | ||
515 | if (bus == 0 && PCI_SLOT(devfn) == 0) | ||
516 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
517 | else | ||
518 | return PCIBIOS_SUCCESSFUL; | ||
519 | } | ||
520 | |||
521 | static void | ||
522 | __init mpc82xx_pcibios_fixup(void) | ||
523 | { | ||
524 | struct pci_dev *dev = NULL; | ||
525 | |||
526 | for_each_pci_dev(dev) { | ||
527 | pci_read_irq_line(dev); | ||
528 | } | ||
529 | } | ||
530 | |||
531 | void __init add_bridge(struct device_node *np) | ||
532 | { | ||
533 | int len; | ||
534 | struct pci_controller *hose; | ||
535 | struct resource r; | ||
536 | const int *bus_range; | ||
537 | const void *ptr; | ||
538 | |||
539 | memset(&r, 0, sizeof(r)); | ||
540 | if (of_address_to_resource(np, 0, &r)) { | ||
541 | printk(KERN_INFO "No PCI reg property in device tree\n"); | ||
542 | return; | ||
543 | } | ||
544 | if (!(ptr = get_property(np, "clock-frequency", NULL))) { | ||
545 | printk(KERN_INFO "No clock-frequency property in PCI node"); | ||
546 | return; | ||
547 | } | ||
548 | pci_clk_frq = *(uint *) ptr; | ||
549 | of_node_put(np); | ||
550 | bus_range = get_property(np, "bus-range", &len); | ||
551 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
552 | printk(KERN_WARNING "Can't get bus-range for %s, assume" | ||
553 | " bus 0\n", np->full_name); | ||
554 | } | ||
555 | |||
556 | pci_assign_all_buses = 1; | ||
557 | |||
558 | hose = pcibios_alloc_controller(); | ||
559 | |||
560 | if (!hose) | ||
561 | return; | ||
562 | |||
563 | hose->arch_data = np; | ||
564 | hose->set_cfg_type = 1; | ||
565 | |||
566 | hose->first_busno = bus_range ? bus_range[0] : 0; | ||
567 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
568 | hose->bus_offset = 0; | ||
569 | |||
570 | hose->set_cfg_type = 1; | ||
571 | |||
572 | setup_indirect_pci(hose, | ||
573 | r.start + offsetof(pci_cpm2_t, pci_cfg_addr), | ||
574 | r.start + offsetof(pci_cpm2_t, pci_cfg_data)); | ||
575 | |||
576 | pci_process_bridge_OF_ranges(hose, np, 1); | ||
577 | } | ||
578 | #endif | ||
579 | |||
580 | /* | ||
581 | * Setup the architecture | ||
582 | */ | ||
583 | static void __init mpc82xx_ads_setup_arch(void) | ||
584 | { | ||
585 | #ifdef CONFIG_PCI | ||
586 | struct device_node *np; | ||
587 | #endif | ||
588 | |||
589 | if (ppc_md.progress) | ||
590 | ppc_md.progress("mpc82xx_ads_setup_arch()", 0); | ||
591 | cpm2_reset(); | ||
592 | |||
593 | /* Map I/O region to a 256MB BAT */ | ||
594 | |||
595 | m82xx_board_setup(); | ||
596 | |||
597 | #ifdef CONFIG_PCI | ||
598 | ppc_md.pci_exclude_device = m82xx_pci_exclude_device; | ||
599 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | ||
600 | add_bridge(np); | ||
601 | |||
602 | of_node_put(np); | ||
603 | ppc_md.pci_map_irq = NULL; | ||
604 | ppc_md.pcibios_fixup = mpc82xx_pcibios_fixup; | ||
605 | ppc_md.pcibios_fixup_bus = NULL; | ||
606 | #endif | ||
607 | |||
608 | #ifdef CONFIG_ROOT_NFS | ||
609 | ROOT_DEV = Root_NFS; | ||
610 | #else | ||
611 | ROOT_DEV = Root_HDA1; | ||
612 | #endif | ||
613 | |||
614 | if (ppc_md.progress) | ||
615 | ppc_md.progress("mpc82xx_ads_setup_arch(), finish", 0); | ||
616 | } | ||
617 | |||
618 | /* | ||
619 | * Called very early, device-tree isn't unflattened | ||
620 | */ | ||
621 | static int __init mpc82xx_ads_probe(void) | ||
622 | { | ||
623 | /* We always match for now, eventually we should look at | ||
624 | * the flat dev tree to ensure this is the board we are | ||
625 | * supposed to run on | ||
626 | */ | ||
627 | return 1; | ||
628 | } | ||
629 | |||
630 | #define RMR_CSRE 0x00000001 | ||
631 | static void m82xx_restart(char *cmd) | ||
632 | { | ||
633 | __volatile__ unsigned char dummy; | ||
634 | |||
635 | local_irq_disable(); | ||
636 | ((cpm2_map_t *) cpm2_immr)->im_clkrst.car_rmr |= RMR_CSRE; | ||
637 | |||
638 | /* Clear the ME,EE,IR & DR bits in MSR to cause checkstop */ | ||
639 | mtmsr(mfmsr() & ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR)); | ||
640 | dummy = ((cpm2_map_t *) cpm2_immr)->im_clkrst.res[0]; | ||
641 | printk("Restart failed\n"); | ||
642 | while (1) ; | ||
643 | } | ||
644 | |||
645 | static void m82xx_halt(void) | ||
646 | { | ||
647 | local_irq_disable(); | ||
648 | while (1) ; | ||
649 | } | ||
650 | |||
651 | define_machine(mpc82xx_ads) | ||
652 | { | ||
653 | .name = "MPC82xx ADS", | ||
654 | .probe = mpc82xx_ads_probe, | ||
655 | .setup_arch = mpc82xx_ads_setup_arch, | ||
656 | .init_IRQ = mpc82xx_ads_pic_init, | ||
657 | .show_cpuinfo = mpc82xx_ads_show_cpuinfo, | ||
658 | .get_irq = cpm2_get_irq, | ||
659 | .calibrate_decr = m82xx_calibrate_decr, | ||
660 | .restart = m82xx_restart,.halt = m82xx_halt, | ||
661 | }; | ||
diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h new file mode 100644 index 000000000000..a7348213508f --- /dev/null +++ b/arch/powerpc/platforms/82xx/pq2ads.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * PQ2/mpc8260 board-specific stuff | ||
3 | * | ||
4 | * A collection of structures, addresses, and values associated with | ||
5 | * the Freescale MPC8260ADS/MPC8266ADS-PCI boards. | ||
6 | * Copied from the RPX-Classic and SBS8260 stuff. | ||
7 | * | ||
8 | * Author: Vitaly Bordug <vbordug@ru.mvista.com> | ||
9 | * | ||
10 | * Originally written by Dan Malek for Motorola MPC8260 family | ||
11 | * | ||
12 | * Copyright (c) 2001 Dan Malek <dan@embeddedalley.com> | ||
13 | * Copyright (c) 2006 MontaVista Software, Inc. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License as published by the | ||
17 | * Free Software Foundation; either version 2 of the License, or (at your | ||
18 | * option) any later version. | ||
19 | */ | ||
20 | |||
21 | #ifdef __KERNEL__ | ||
22 | #ifndef __MACH_ADS8260_DEFS | ||
23 | #define __MACH_ADS8260_DEFS | ||
24 | |||
25 | #include <linux/config.h> | ||
26 | |||
27 | #include <asm/ppcboot.h> | ||
28 | |||
29 | /* For our show_cpuinfo hooks. */ | ||
30 | #define CPUINFO_VENDOR "Freescale Semiconductor" | ||
31 | #define CPUINFO_MACHINE "PQ2 ADS PowerPC" | ||
32 | |||
33 | /* Backword-compatibility stuff for the drivers */ | ||
34 | #define CPM_MAP_ADDR ((uint)0xf0000000) | ||
35 | #define CPM_IRQ_OFFSET 0 | ||
36 | |||
37 | /* The ADS8260 has 16, 32-bit wide control/status registers, accessed | ||
38 | * only on word boundaries. | ||
39 | * Not all are used (yet), or are interesting to us (yet). | ||
40 | */ | ||
41 | |||
42 | /* Things of interest in the CSR. | ||
43 | */ | ||
44 | #define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */ | ||
45 | #define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */ | ||
46 | #define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable*/ | ||
47 | #define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */ | ||
48 | #define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */ | ||
49 | #define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */ | ||
50 | #define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/ | ||
51 | #define BCSR3_FETH2_RS ((uint)0x80000000) /* 0 == reset */ | ||
52 | |||
53 | /* cpm serial driver works with constants below */ | ||
54 | |||
55 | #define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET) | ||
56 | #define SIU_INT_SMC2i ((uint)0x05+CPM_IRQ_OFFSET) | ||
57 | #define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET) | ||
58 | #define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET) | ||
59 | #define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) | ||
60 | #define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET) | ||
61 | |||
62 | void m82xx_pci_init_irq(void); | ||
63 | void mpc82xx_ads_show_cpuinfo(struct seq_file*); | ||
64 | void m82xx_calibrate_decr(void); | ||
65 | |||
66 | #endif /* __MACH_ADS8260_DEFS */ | ||
67 | #endif /* __KERNEL__ */ | ||
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 5fe7b7faf45f..0975e94ac7c4 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig | |||
@@ -5,6 +5,13 @@ choice | |||
5 | prompt "Machine Type" | 5 | prompt "Machine Type" |
6 | default MPC834x_SYS | 6 | default MPC834x_SYS |
7 | 7 | ||
8 | config MPC832x_MDS | ||
9 | bool "Freescale MPC832x MDS" | ||
10 | select DEFAULT_UIMAGE | ||
11 | select QUICC_ENGINE | ||
12 | help | ||
13 | This option enables support for the MPC832x MDS evaluation board. | ||
14 | |||
8 | config MPC834x_SYS | 15 | config MPC834x_SYS |
9 | bool "Freescale MPC834x SYS" | 16 | bool "Freescale MPC834x SYS" |
10 | select DEFAULT_UIMAGE | 17 | select DEFAULT_UIMAGE |
@@ -27,6 +34,12 @@ config MPC834x_ITX | |||
27 | 34 | ||
28 | endchoice | 35 | endchoice |
29 | 36 | ||
37 | config PPC_MPC832x | ||
38 | bool | ||
39 | select PPC_UDBG_16550 | ||
40 | select PPC_INDIRECT_PCI | ||
41 | default y if MPC832x_MDS | ||
42 | |||
30 | config MPC834x | 43 | config MPC834x |
31 | bool | 44 | bool |
32 | select PPC_UDBG_16550 | 45 | select PPC_UDBG_16550 |
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c new file mode 100644 index 000000000000..54dea9d42dc9 --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. | ||
3 | * | ||
4 | * Description: | ||
5 | * MPC832xE MDS board specific routines. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/stddef.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/reboot.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/kdev_t.h> | ||
20 | #include <linux/major.h> | ||
21 | #include <linux/console.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/seq_file.h> | ||
24 | #include <linux/root_dev.h> | ||
25 | #include <linux/initrd.h> | ||
26 | |||
27 | #include <asm/system.h> | ||
28 | #include <asm/atomic.h> | ||
29 | #include <asm/time.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/machdep.h> | ||
32 | #include <asm/ipic.h> | ||
33 | #include <asm/bootinfo.h> | ||
34 | #include <asm/irq.h> | ||
35 | #include <asm/prom.h> | ||
36 | #include <asm/udbg.h> | ||
37 | #include <sysdev/fsl_soc.h> | ||
38 | #include <asm/qe.h> | ||
39 | #include <asm/qe_ic.h> | ||
40 | |||
41 | #include "mpc83xx.h" | ||
42 | #include "mpc832x_mds.h" | ||
43 | |||
44 | #undef DEBUG | ||
45 | #ifdef DEBUG | ||
46 | #define DBG(fmt...) udbg_printf(fmt) | ||
47 | #else | ||
48 | #define DBG(fmt...) | ||
49 | #endif | ||
50 | |||
51 | #ifndef CONFIG_PCI | ||
52 | unsigned long isa_io_base = 0; | ||
53 | unsigned long isa_mem_base = 0; | ||
54 | #endif | ||
55 | |||
56 | static u8 *bcsr_regs = NULL; | ||
57 | |||
58 | u8 *get_bcsr(void) | ||
59 | { | ||
60 | return bcsr_regs; | ||
61 | } | ||
62 | |||
63 | /* ************************************************************************ | ||
64 | * | ||
65 | * Setup the architecture | ||
66 | * | ||
67 | */ | ||
68 | static void __init mpc832x_sys_setup_arch(void) | ||
69 | { | ||
70 | struct device_node *np; | ||
71 | |||
72 | if (ppc_md.progress) | ||
73 | ppc_md.progress("mpc832x_sys_setup_arch()", 0); | ||
74 | |||
75 | np = of_find_node_by_type(NULL, "cpu"); | ||
76 | if (np != 0) { | ||
77 | unsigned int *fp = | ||
78 | (int *)get_property(np, "clock-frequency", NULL); | ||
79 | if (fp != 0) | ||
80 | loops_per_jiffy = *fp / HZ; | ||
81 | else | ||
82 | loops_per_jiffy = 50000000 / HZ; | ||
83 | of_node_put(np); | ||
84 | } | ||
85 | |||
86 | /* Map BCSR area */ | ||
87 | np = of_find_node_by_name(NULL, "bcsr"); | ||
88 | if (np != 0) { | ||
89 | struct resource res; | ||
90 | |||
91 | of_address_to_resource(np, 0, &res); | ||
92 | bcsr_regs = ioremap(res.start, res.end - res.start +1); | ||
93 | of_node_put(np); | ||
94 | } | ||
95 | |||
96 | #ifdef CONFIG_PCI | ||
97 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | ||
98 | add_bridge(np); | ||
99 | |||
100 | ppc_md.pci_swizzle = common_swizzle; | ||
101 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | ||
102 | #endif | ||
103 | |||
104 | #ifdef CONFIG_QUICC_ENGINE | ||
105 | qe_reset(); | ||
106 | |||
107 | if ((np = of_find_node_by_name(np, "par_io")) != NULL) { | ||
108 | par_io_init(np); | ||
109 | of_node_put(np); | ||
110 | |||
111 | for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;) | ||
112 | par_io_of_config(np); | ||
113 | } | ||
114 | |||
115 | if ((np = of_find_compatible_node(NULL, "network", "ucc_geth")) | ||
116 | != NULL){ | ||
117 | /* Reset the Ethernet PHY */ | ||
118 | bcsr_regs[9] &= ~0x20; | ||
119 | udelay(1000); | ||
120 | bcsr_regs[9] |= 0x20; | ||
121 | iounmap(bcsr_regs); | ||
122 | of_node_put(np); | ||
123 | } | ||
124 | |||
125 | #endif /* CONFIG_QUICC_ENGINE */ | ||
126 | |||
127 | #ifdef CONFIG_BLK_DEV_INITRD | ||
128 | if (initrd_start) | ||
129 | ROOT_DEV = Root_RAM0; | ||
130 | else | ||
131 | #endif | ||
132 | #ifdef CONFIG_ROOT_NFS | ||
133 | ROOT_DEV = Root_NFS; | ||
134 | #else | ||
135 | ROOT_DEV = Root_HDA1; | ||
136 | #endif | ||
137 | } | ||
138 | |||
139 | void __init mpc832x_sys_init_IRQ(void) | ||
140 | { | ||
141 | |||
142 | struct device_node *np; | ||
143 | |||
144 | np = of_find_node_by_type(NULL, "ipic"); | ||
145 | if (!np) | ||
146 | return; | ||
147 | |||
148 | ipic_init(np, 0); | ||
149 | |||
150 | /* Initialize the default interrupt mapping priorities, | ||
151 | * in case the boot rom changed something on us. | ||
152 | */ | ||
153 | ipic_set_default_priority(); | ||
154 | of_node_put(np); | ||
155 | |||
156 | #ifdef CONFIG_QUICC_ENGINE | ||
157 | np = of_find_node_by_type(NULL, "qeic"); | ||
158 | if (!np) | ||
159 | return; | ||
160 | |||
161 | qe_ic_init(np, 0); | ||
162 | of_node_put(np); | ||
163 | #endif /* CONFIG_QUICC_ENGINE */ | ||
164 | } | ||
165 | |||
166 | #if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374) | ||
167 | extern ulong ds1374_get_rtc_time(void); | ||
168 | extern int ds1374_set_rtc_time(ulong); | ||
169 | |||
170 | static int __init mpc832x_rtc_hookup(void) | ||
171 | { | ||
172 | struct timespec tv; | ||
173 | |||
174 | ppc_md.get_rtc_time = ds1374_get_rtc_time; | ||
175 | ppc_md.set_rtc_time = ds1374_set_rtc_time; | ||
176 | |||
177 | tv.tv_nsec = 0; | ||
178 | tv.tv_sec = (ppc_md.get_rtc_time) (); | ||
179 | do_settimeofday(&tv); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | late_initcall(mpc832x_rtc_hookup); | ||
185 | #endif | ||
186 | |||
187 | /* | ||
188 | * Called very early, MMU is off, device-tree isn't unflattened | ||
189 | */ | ||
190 | static int __init mpc832x_sys_probe(void) | ||
191 | { | ||
192 | char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), | ||
193 | "model", NULL); | ||
194 | |||
195 | if (model == NULL) | ||
196 | return 0; | ||
197 | if (strcmp(model, "MPC8323EMDS")) | ||
198 | return 0; | ||
199 | |||
200 | DBG("%s found\n", model); | ||
201 | |||
202 | return 1; | ||
203 | } | ||
204 | |||
205 | define_machine(mpc832x_mds) { | ||
206 | .name = "MPC832x MDS", | ||
207 | .probe = mpc832x_sys_probe, | ||
208 | .setup_arch = mpc832x_sys_setup_arch, | ||
209 | .init_IRQ = mpc832x_sys_init_IRQ, | ||
210 | .get_irq = ipic_get_irq, | ||
211 | .restart = mpc83xx_restart, | ||
212 | .time_init = mpc83xx_time_init, | ||
213 | .calibrate_decr = generic_calibrate_decr, | ||
214 | .progress = udbg_progress, | ||
215 | }; | ||
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.h b/arch/powerpc/platforms/83xx/mpc832x_mds.h new file mode 100644 index 000000000000..a49588904f8a --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. | ||
3 | * | ||
4 | * Description: | ||
5 | * MPC832x MDS board specific header. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef __MACH_MPC832x_MDS_H__ | ||
15 | #define __MACH_MPC832x_MDS_H__ | ||
16 | |||
17 | extern u8 *get_bcsr(void); | ||
18 | |||
19 | #endif /* __MACH_MPC832x_MDS_H__ */ | ||
diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c new file mode 100644 index 000000000000..c0191900fc25 --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c | |||
@@ -0,0 +1,219 @@ | |||
1 | /* | ||
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. | ||
3 | * | ||
4 | * Author: Li Yang <LeoLi@freescale.com> | ||
5 | * Yin Olivia <Hong-hua.Yin@freescale.com> | ||
6 | * | ||
7 | * Description: | ||
8 | * MPC8360E MDS PB board specific routines. | ||
9 | * | ||
10 | * Changelog: | ||
11 | * Jun 21, 2006 Initial version | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/stddef.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/reboot.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/kdev_t.h> | ||
26 | #include <linux/major.h> | ||
27 | #include <linux/console.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/seq_file.h> | ||
30 | #include <linux/root_dev.h> | ||
31 | #include <linux/initrd.h> | ||
32 | |||
33 | #include <asm/system.h> | ||
34 | #include <asm/atomic.h> | ||
35 | #include <asm/time.h> | ||
36 | #include <asm/io.h> | ||
37 | #include <asm/machdep.h> | ||
38 | #include <asm/ipic.h> | ||
39 | #include <asm/bootinfo.h> | ||
40 | #include <asm/irq.h> | ||
41 | #include <asm/prom.h> | ||
42 | #include <asm/udbg.h> | ||
43 | #include <sysdev/fsl_soc.h> | ||
44 | #include <asm/qe.h> | ||
45 | #include <asm/qe_ic.h> | ||
46 | |||
47 | #include "mpc83xx.h" | ||
48 | |||
49 | #undef DEBUG | ||
50 | #ifdef DEBUG | ||
51 | #define DBG(fmt...) udbg_printf(fmt) | ||
52 | #else | ||
53 | #define DBG(fmt...) | ||
54 | #endif | ||
55 | |||
56 | #ifndef CONFIG_PCI | ||
57 | unsigned long isa_io_base = 0; | ||
58 | unsigned long isa_mem_base = 0; | ||
59 | #endif | ||
60 | |||
61 | static u8 *bcsr_regs = NULL; | ||
62 | |||
63 | u8 *get_bcsr(void) | ||
64 | { | ||
65 | return bcsr_regs; | ||
66 | } | ||
67 | |||
68 | /* ************************************************************************ | ||
69 | * | ||
70 | * Setup the architecture | ||
71 | * | ||
72 | */ | ||
73 | static void __init mpc8360_sys_setup_arch(void) | ||
74 | { | ||
75 | struct device_node *np; | ||
76 | |||
77 | if (ppc_md.progress) | ||
78 | ppc_md.progress("mpc8360_sys_setup_arch()", 0); | ||
79 | |||
80 | np = of_find_node_by_type(NULL, "cpu"); | ||
81 | if (np != 0) { | ||
82 | const unsigned int *fp = | ||
83 | get_property(np, "clock-frequency", NULL); | ||
84 | if (fp != 0) | ||
85 | loops_per_jiffy = *fp / HZ; | ||
86 | else | ||
87 | loops_per_jiffy = 50000000 / HZ; | ||
88 | of_node_put(np); | ||
89 | } | ||
90 | |||
91 | /* Map BCSR area */ | ||
92 | np = of_find_node_by_name(NULL, "bcsr"); | ||
93 | if (np != 0) { | ||
94 | struct resource res; | ||
95 | |||
96 | of_address_to_resource(np, 0, &res); | ||
97 | bcsr_regs = ioremap(res.start, res.end - res.start +1); | ||
98 | of_node_put(np); | ||
99 | } | ||
100 | |||
101 | #ifdef CONFIG_PCI | ||
102 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | ||
103 | add_bridge(np); | ||
104 | |||
105 | ppc_md.pci_swizzle = common_swizzle; | ||
106 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | ||
107 | #endif | ||
108 | |||
109 | #ifdef CONFIG_QUICC_ENGINE | ||
110 | qe_reset(); | ||
111 | |||
112 | if ((np = of_find_node_by_name(np, "par_io")) != NULL) { | ||
113 | par_io_init(np); | ||
114 | of_node_put(np); | ||
115 | |||
116 | for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;) | ||
117 | par_io_of_config(np); | ||
118 | } | ||
119 | |||
120 | if ((np = of_find_compatible_node(NULL, "network", "ucc_geth")) | ||
121 | != NULL){ | ||
122 | /* Reset the Ethernet PHY */ | ||
123 | bcsr_regs[9] &= ~0x20; | ||
124 | udelay(1000); | ||
125 | bcsr_regs[9] |= 0x20; | ||
126 | iounmap(bcsr_regs); | ||
127 | of_node_put(np); | ||
128 | } | ||
129 | |||
130 | #endif /* CONFIG_QUICC_ENGINE */ | ||
131 | |||
132 | #ifdef CONFIG_BLK_DEV_INITRD | ||
133 | if (initrd_start) | ||
134 | ROOT_DEV = Root_RAM0; | ||
135 | else | ||
136 | #endif | ||
137 | #ifdef CONFIG_ROOT_NFS | ||
138 | ROOT_DEV = Root_NFS; | ||
139 | #else | ||
140 | ROOT_DEV = Root_HDA1; | ||
141 | #endif | ||
142 | } | ||
143 | |||
144 | void __init mpc8360_sys_init_IRQ(void) | ||
145 | { | ||
146 | |||
147 | struct device_node *np; | ||
148 | |||
149 | np = of_find_node_by_type(NULL, "ipic"); | ||
150 | if (!np) | ||
151 | return; | ||
152 | |||
153 | ipic_init(np, 0); | ||
154 | |||
155 | /* Initialize the default interrupt mapping priorities, | ||
156 | * in case the boot rom changed something on us. | ||
157 | */ | ||
158 | ipic_set_default_priority(); | ||
159 | of_node_put(np); | ||
160 | |||
161 | #ifdef CONFIG_QUICC_ENGINE | ||
162 | np = of_find_node_by_type(NULL, "qeic"); | ||
163 | if (!np) | ||
164 | return; | ||
165 | |||
166 | qe_ic_init(np, 0); | ||
167 | of_node_put(np); | ||
168 | #endif /* CONFIG_QUICC_ENGINE */ | ||
169 | } | ||
170 | |||
171 | #if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374) | ||
172 | extern ulong ds1374_get_rtc_time(void); | ||
173 | extern int ds1374_set_rtc_time(ulong); | ||
174 | |||
175 | static int __init mpc8360_rtc_hookup(void) | ||
176 | { | ||
177 | struct timespec tv; | ||
178 | |||
179 | ppc_md.get_rtc_time = ds1374_get_rtc_time; | ||
180 | ppc_md.set_rtc_time = ds1374_set_rtc_time; | ||
181 | |||
182 | tv.tv_nsec = 0; | ||
183 | tv.tv_sec = (ppc_md.get_rtc_time) (); | ||
184 | do_settimeofday(&tv); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | late_initcall(mpc8360_rtc_hookup); | ||
190 | #endif | ||
191 | |||
192 | /* | ||
193 | * Called very early, MMU is off, device-tree isn't unflattened | ||
194 | */ | ||
195 | static int __init mpc8360_sys_probe(void) | ||
196 | { | ||
197 | char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), | ||
198 | "model", NULL); | ||
199 | if (model == NULL) | ||
200 | return 0; | ||
201 | if (strcmp(model, "MPC8360EPB")) | ||
202 | return 0; | ||
203 | |||
204 | DBG("MPC8360EMDS-PB found\n"); | ||
205 | |||
206 | return 1; | ||
207 | } | ||
208 | |||
209 | define_machine(mpc8360_sys) { | ||
210 | .name = "MPC8360E PB", | ||
211 | .probe = mpc8360_sys_probe, | ||
212 | .setup_arch = mpc8360_sys_setup_arch, | ||
213 | .init_IRQ = mpc8360_sys_init_IRQ, | ||
214 | .get_irq = ipic_get_irq, | ||
215 | .restart = mpc83xx_restart, | ||
216 | .time_init = mpc83xx_time_init, | ||
217 | .calibrate_decr = generic_calibrate_decr, | ||
218 | .progress = udbg_progress, | ||
219 | }; | ||
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 6b57a47c5d37..6cc59e0b4582 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c | |||
@@ -21,6 +21,12 @@ | |||
21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, write to the Free Software |
23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 23 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
24 | * | ||
25 | * TODO: | ||
26 | * - Fix various assumptions related to HW CPU numbers vs. linux CPU numbers | ||
27 | * vs node numbers in the setup code | ||
28 | * - Implement proper handling of maxcpus=1/2 (that is, routing of irqs from | ||
29 | * a non-active node to the active node) | ||
24 | */ | 30 | */ |
25 | 31 | ||
26 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
@@ -44,24 +50,25 @@ struct iic { | |||
44 | u8 target_id; | 50 | u8 target_id; |
45 | u8 eoi_stack[16]; | 51 | u8 eoi_stack[16]; |
46 | int eoi_ptr; | 52 | int eoi_ptr; |
47 | struct irq_host *host; | 53 | struct device_node *node; |
48 | }; | 54 | }; |
49 | 55 | ||
50 | static DEFINE_PER_CPU(struct iic, iic); | 56 | static DEFINE_PER_CPU(struct iic, iic); |
51 | #define IIC_NODE_COUNT 2 | 57 | #define IIC_NODE_COUNT 2 |
52 | static struct irq_host *iic_hosts[IIC_NODE_COUNT]; | 58 | static struct irq_host *iic_host; |
53 | 59 | ||
54 | /* Convert between "pending" bits and hw irq number */ | 60 | /* Convert between "pending" bits and hw irq number */ |
55 | static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) | 61 | static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits) |
56 | { | 62 | { |
57 | unsigned char unit = bits.source & 0xf; | 63 | unsigned char unit = bits.source & 0xf; |
64 | unsigned char node = bits.source >> 4; | ||
65 | unsigned char class = bits.class & 3; | ||
58 | 66 | ||
67 | /* Decode IPIs */ | ||
59 | if (bits.flags & CBE_IIC_IRQ_IPI) | 68 | if (bits.flags & CBE_IIC_IRQ_IPI) |
60 | return IIC_IRQ_IPI0 | (bits.prio >> 4); | 69 | return IIC_IRQ_TYPE_IPI | (bits.prio >> 4); |
61 | else if (bits.class <= 3) | ||
62 | return (bits.class << 4) | unit; | ||
63 | else | 70 | else |
64 | return IIC_IRQ_INVALID; | 71 | return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit; |
65 | } | 72 | } |
66 | 73 | ||
67 | static void iic_mask(unsigned int irq) | 74 | static void iic_mask(unsigned int irq) |
@@ -86,21 +93,70 @@ static struct irq_chip iic_chip = { | |||
86 | .eoi = iic_eoi, | 93 | .eoi = iic_eoi, |
87 | }; | 94 | }; |
88 | 95 | ||
96 | |||
97 | static void iic_ioexc_eoi(unsigned int irq) | ||
98 | { | ||
99 | } | ||
100 | |||
101 | static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc, | ||
102 | struct pt_regs *regs) | ||
103 | { | ||
104 | struct cbe_iic_regs *node_iic = desc->handler_data; | ||
105 | unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC; | ||
106 | unsigned long bits, ack; | ||
107 | int cascade; | ||
108 | |||
109 | for (;;) { | ||
110 | bits = in_be64(&node_iic->iic_is); | ||
111 | if (bits == 0) | ||
112 | break; | ||
113 | /* pre-ack edge interrupts */ | ||
114 | ack = bits & IIC_ISR_EDGE_MASK; | ||
115 | if (ack) | ||
116 | out_be64(&node_iic->iic_is, ack); | ||
117 | /* handle them */ | ||
118 | for (cascade = 63; cascade >= 0; cascade--) | ||
119 | if (bits & (0x8000000000000000UL >> cascade)) { | ||
120 | unsigned int cirq = | ||
121 | irq_linear_revmap(iic_host, | ||
122 | base | cascade); | ||
123 | if (cirq != NO_IRQ) | ||
124 | generic_handle_irq(cirq, regs); | ||
125 | } | ||
126 | /* post-ack level interrupts */ | ||
127 | ack = bits & ~IIC_ISR_EDGE_MASK; | ||
128 | if (ack) | ||
129 | out_be64(&node_iic->iic_is, ack); | ||
130 | } | ||
131 | desc->chip->eoi(irq); | ||
132 | } | ||
133 | |||
134 | |||
135 | static struct irq_chip iic_ioexc_chip = { | ||
136 | .typename = " CELL-IOEX", | ||
137 | .mask = iic_mask, | ||
138 | .unmask = iic_unmask, | ||
139 | .eoi = iic_ioexc_eoi, | ||
140 | }; | ||
141 | |||
89 | /* Get an IRQ number from the pending state register of the IIC */ | 142 | /* Get an IRQ number from the pending state register of the IIC */ |
90 | static unsigned int iic_get_irq(struct pt_regs *regs) | 143 | static unsigned int iic_get_irq(struct pt_regs *regs) |
91 | { | 144 | { |
92 | struct cbe_iic_pending_bits pending; | 145 | struct cbe_iic_pending_bits pending; |
93 | struct iic *iic; | 146 | struct iic *iic; |
147 | unsigned int virq; | ||
94 | 148 | ||
95 | iic = &__get_cpu_var(iic); | 149 | iic = &__get_cpu_var(iic); |
96 | *(unsigned long *) &pending = | 150 | *(unsigned long *) &pending = |
97 | in_be64((unsigned long __iomem *) &iic->regs->pending_destr); | 151 | in_be64((unsigned long __iomem *) &iic->regs->pending_destr); |
152 | if (!(pending.flags & CBE_IIC_IRQ_VALID)) | ||
153 | return NO_IRQ; | ||
154 | virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending)); | ||
155 | if (virq == NO_IRQ) | ||
156 | return NO_IRQ; | ||
98 | iic->eoi_stack[++iic->eoi_ptr] = pending.prio; | 157 | iic->eoi_stack[++iic->eoi_ptr] = pending.prio; |
99 | BUG_ON(iic->eoi_ptr > 15); | 158 | BUG_ON(iic->eoi_ptr > 15); |
100 | if (pending.flags & CBE_IIC_IRQ_VALID) | 159 | return virq; |
101 | return irq_linear_revmap(iic->host, | ||
102 | iic_pending_to_hwnum(pending)); | ||
103 | return NO_IRQ; | ||
104 | } | 160 | } |
105 | 161 | ||
106 | #ifdef CONFIG_SMP | 162 | #ifdef CONFIG_SMP |
@@ -108,12 +164,7 @@ static unsigned int iic_get_irq(struct pt_regs *regs) | |||
108 | /* Use the highest interrupt priorities for IPI */ | 164 | /* Use the highest interrupt priorities for IPI */ |
109 | static inline int iic_ipi_to_irq(int ipi) | 165 | static inline int iic_ipi_to_irq(int ipi) |
110 | { | 166 | { |
111 | return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi; | 167 | return IIC_IRQ_TYPE_IPI + 0xf - ipi; |
112 | } | ||
113 | |||
114 | static inline int iic_irq_to_ipi(int irq) | ||
115 | { | ||
116 | return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0); | ||
117 | } | 168 | } |
118 | 169 | ||
119 | void iic_setup_cpu(void) | 170 | void iic_setup_cpu(void) |
@@ -123,7 +174,7 @@ void iic_setup_cpu(void) | |||
123 | 174 | ||
124 | void iic_cause_IPI(int cpu, int mesg) | 175 | void iic_cause_IPI(int cpu, int mesg) |
125 | { | 176 | { |
126 | out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4); | 177 | out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4); |
127 | } | 178 | } |
128 | 179 | ||
129 | u8 iic_get_target_id(int cpu) | 180 | u8 iic_get_target_id(int cpu) |
@@ -134,9 +185,7 @@ EXPORT_SYMBOL_GPL(iic_get_target_id); | |||
134 | 185 | ||
135 | struct irq_host *iic_get_irq_host(int node) | 186 | struct irq_host *iic_get_irq_host(int node) |
136 | { | 187 | { |
137 | if (node < 0 || node >= IIC_NODE_COUNT) | 188 | return iic_host; |
138 | return NULL; | ||
139 | return iic_hosts[node]; | ||
140 | } | 189 | } |
141 | EXPORT_SYMBOL_GPL(iic_get_irq_host); | 190 | EXPORT_SYMBOL_GPL(iic_get_irq_host); |
142 | 191 | ||
@@ -149,34 +198,20 @@ static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | |||
149 | 198 | ||
150 | return IRQ_HANDLED; | 199 | return IRQ_HANDLED; |
151 | } | 200 | } |
152 | |||
153 | static void iic_request_ipi(int ipi, const char *name) | 201 | static void iic_request_ipi(int ipi, const char *name) |
154 | { | 202 | { |
155 | int node, virq; | 203 | int virq; |
156 | 204 | ||
157 | for (node = 0; node < IIC_NODE_COUNT; node++) { | 205 | virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi)); |
158 | char *rname; | 206 | if (virq == NO_IRQ) { |
159 | if (iic_hosts[node] == NULL) | 207 | printk(KERN_ERR |
160 | continue; | 208 | "iic: failed to map IPI %s\n", name); |
161 | virq = irq_create_mapping(iic_hosts[node], | 209 | return; |
162 | iic_ipi_to_irq(ipi)); | ||
163 | if (virq == NO_IRQ) { | ||
164 | printk(KERN_ERR | ||
165 | "iic: failed to map IPI %s on node %d\n", | ||
166 | name, node); | ||
167 | continue; | ||
168 | } | ||
169 | rname = kzalloc(strlen(name) + 16, GFP_KERNEL); | ||
170 | if (rname) | ||
171 | sprintf(rname, "%s node %d", name, node); | ||
172 | else | ||
173 | rname = (char *)name; | ||
174 | if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, | ||
175 | rname, (void *)(long)ipi)) | ||
176 | printk(KERN_ERR | ||
177 | "iic: failed to request IPI %s on node %d\n", | ||
178 | name, node); | ||
179 | } | 210 | } |
211 | if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name, | ||
212 | (void *)(long)ipi)) | ||
213 | printk(KERN_ERR | ||
214 | "iic: failed to request IPI %s\n", name); | ||
180 | } | 215 | } |
181 | 216 | ||
182 | void iic_request_IPIs(void) | 217 | void iic_request_IPIs(void) |
@@ -193,16 +228,24 @@ void iic_request_IPIs(void) | |||
193 | 228 | ||
194 | static int iic_host_match(struct irq_host *h, struct device_node *node) | 229 | static int iic_host_match(struct irq_host *h, struct device_node *node) |
195 | { | 230 | { |
196 | return h->host_data != NULL && node == h->host_data; | 231 | return device_is_compatible(node, |
232 | "IBM,CBEA-Internal-Interrupt-Controller"); | ||
197 | } | 233 | } |
198 | 234 | ||
199 | static int iic_host_map(struct irq_host *h, unsigned int virq, | 235 | static int iic_host_map(struct irq_host *h, unsigned int virq, |
200 | irq_hw_number_t hw) | 236 | irq_hw_number_t hw) |
201 | { | 237 | { |
202 | if (hw < IIC_IRQ_IPI0) | 238 | switch (hw & IIC_IRQ_TYPE_MASK) { |
203 | set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq); | 239 | case IIC_IRQ_TYPE_IPI: |
204 | else | ||
205 | set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq); | 240 | set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq); |
241 | break; | ||
242 | case IIC_IRQ_TYPE_IOEXC: | ||
243 | set_irq_chip_and_handler(virq, &iic_ioexc_chip, | ||
244 | handle_fasteoi_irq); | ||
245 | break; | ||
246 | default: | ||
247 | set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq); | ||
248 | } | ||
206 | return 0; | 249 | return 0; |
207 | } | 250 | } |
208 | 251 | ||
@@ -211,11 +254,39 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct, | |||
211 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 254 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
212 | 255 | ||
213 | { | 256 | { |
214 | /* Currently, we don't translate anything. That needs to be fixed as | 257 | unsigned int node, ext, unit, class; |
215 | * we get better defined device-trees. iic interrupts have to be | 258 | const u32 *val; |
216 | * explicitely mapped by whoever needs them | 259 | |
217 | */ | 260 | if (!device_is_compatible(ct, |
218 | return -ENODEV; | 261 | "IBM,CBEA-Internal-Interrupt-Controller")) |
262 | return -ENODEV; | ||
263 | if (intsize != 1) | ||
264 | return -ENODEV; | ||
265 | val = get_property(ct, "#interrupt-cells", NULL); | ||
266 | if (val == NULL || *val != 1) | ||
267 | return -ENODEV; | ||
268 | |||
269 | node = intspec[0] >> 24; | ||
270 | ext = (intspec[0] >> 16) & 0xff; | ||
271 | class = (intspec[0] >> 8) & 0xff; | ||
272 | unit = intspec[0] & 0xff; | ||
273 | |||
274 | /* Check if node is in supported range */ | ||
275 | if (node > 1) | ||
276 | return -EINVAL; | ||
277 | |||
278 | /* Build up interrupt number, special case for IO exceptions */ | ||
279 | *out_hwirq = (node << IIC_IRQ_NODE_SHIFT); | ||
280 | if (unit == IIC_UNIT_IIC && class == 1) | ||
281 | *out_hwirq |= IIC_IRQ_TYPE_IOEXC | ext; | ||
282 | else | ||
283 | *out_hwirq |= IIC_IRQ_TYPE_NORMAL | | ||
284 | (class << IIC_IRQ_CLASS_SHIFT) | unit; | ||
285 | |||
286 | /* Dummy flags, ignored by iic code */ | ||
287 | *out_flags = IRQ_TYPE_EDGE_RISING; | ||
288 | |||
289 | return 0; | ||
219 | } | 290 | } |
220 | 291 | ||
221 | static struct irq_host_ops iic_host_ops = { | 292 | static struct irq_host_ops iic_host_ops = { |
@@ -225,7 +296,7 @@ static struct irq_host_ops iic_host_ops = { | |||
225 | }; | 296 | }; |
226 | 297 | ||
227 | static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr, | 298 | static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr, |
228 | struct irq_host *host) | 299 | struct device_node *node) |
229 | { | 300 | { |
230 | /* XXX FIXME: should locate the linux CPU number from the HW cpu | 301 | /* XXX FIXME: should locate the linux CPU number from the HW cpu |
231 | * number properly. We are lucky for now | 302 | * number properly. We are lucky for now |
@@ -237,19 +308,19 @@ static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr, | |||
237 | 308 | ||
238 | iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe); | 309 | iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe); |
239 | iic->eoi_stack[0] = 0xff; | 310 | iic->eoi_stack[0] = 0xff; |
240 | iic->host = host; | 311 | iic->node = of_node_get(node); |
241 | out_be64(&iic->regs->prio, 0); | 312 | out_be64(&iic->regs->prio, 0); |
242 | 313 | ||
243 | printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n", | 314 | printk(KERN_INFO "IIC for CPU %d target id 0x%x : %s\n", |
244 | hw_cpu, addr, iic->regs, iic->target_id); | 315 | hw_cpu, iic->target_id, node->full_name); |
245 | } | 316 | } |
246 | 317 | ||
247 | static int __init setup_iic(void) | 318 | static int __init setup_iic(void) |
248 | { | 319 | { |
249 | struct device_node *dn; | 320 | struct device_node *dn; |
250 | struct resource r0, r1; | 321 | struct resource r0, r1; |
251 | struct irq_host *host; | 322 | unsigned int node, cascade, found = 0; |
252 | int found = 0; | 323 | struct cbe_iic_regs *node_iic; |
253 | const u32 *np; | 324 | const u32 *np; |
254 | 325 | ||
255 | for (dn = NULL; | 326 | for (dn = NULL; |
@@ -269,19 +340,33 @@ static int __init setup_iic(void) | |||
269 | of_node_put(dn); | 340 | of_node_put(dn); |
270 | return -ENODEV; | 341 | return -ENODEV; |
271 | } | 342 | } |
272 | host = NULL; | 343 | found++; |
273 | if (found < IIC_NODE_COUNT) { | 344 | init_one_iic(np[0], r0.start, dn); |
274 | host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, | 345 | init_one_iic(np[1], r1.start, dn); |
275 | IIC_SOURCE_COUNT, | 346 | |
276 | &iic_host_ops, | 347 | /* Setup cascade for IO exceptions. XXX cleanup tricks to get |
277 | IIC_IRQ_INVALID); | 348 | * node vs CPU etc... |
278 | iic_hosts[found] = host; | 349 | * Note that we configure the IIC_IRR here with a hard coded |
279 | BUG_ON(iic_hosts[found] == NULL); | 350 | * priority of 1. We might want to improve that later. |
280 | iic_hosts[found]->host_data = of_node_get(dn); | 351 | */ |
281 | found++; | 352 | node = np[0] >> 1; |
282 | } | 353 | node_iic = cbe_get_cpu_iic_regs(np[0]); |
283 | init_one_iic(np[0], r0.start, host); | 354 | cascade = node << IIC_IRQ_NODE_SHIFT; |
284 | init_one_iic(np[1], r1.start, host); | 355 | cascade |= 1 << IIC_IRQ_CLASS_SHIFT; |
356 | cascade |= IIC_UNIT_IIC; | ||
357 | cascade = irq_create_mapping(iic_host, cascade); | ||
358 | if (cascade == NO_IRQ) | ||
359 | continue; | ||
360 | set_irq_data(cascade, node_iic); | ||
361 | set_irq_chained_handler(cascade , iic_ioexc_cascade); | ||
362 | out_be64(&node_iic->iic_ir, | ||
363 | (1 << 12) /* priority */ | | ||
364 | (node << 4) /* dest node */ | | ||
365 | IIC_UNIT_THREAD_0 /* route them to thread 0 */); | ||
366 | /* Flush pending (make sure it triggers if there is | ||
367 | * anything pending | ||
368 | */ | ||
369 | out_be64(&node_iic->iic_is, 0xfffffffffffffffful); | ||
285 | } | 370 | } |
286 | 371 | ||
287 | if (found) | 372 | if (found) |
@@ -292,6 +377,12 @@ static int __init setup_iic(void) | |||
292 | 377 | ||
293 | void __init iic_init_IRQ(void) | 378 | void __init iic_init_IRQ(void) |
294 | { | 379 | { |
380 | /* Setup an irq host data structure */ | ||
381 | iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT, | ||
382 | &iic_host_ops, IIC_IRQ_INVALID); | ||
383 | BUG_ON(iic_host == NULL); | ||
384 | irq_set_default_host(iic_host); | ||
385 | |||
295 | /* Discover and initialize iics */ | 386 | /* Discover and initialize iics */ |
296 | if (setup_iic() < 0) | 387 | if (setup_iic() < 0) |
297 | panic("IIC: Failed to initialize !\n"); | 388 | panic("IIC: Failed to initialize !\n"); |
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h index 5560a92ec3ab..9ba1d3c17b4b 100644 --- a/arch/powerpc/platforms/cell/interrupt.h +++ b/arch/powerpc/platforms/cell/interrupt.h | |||
@@ -2,48 +2,76 @@ | |||
2 | #define ASM_CELL_PIC_H | 2 | #define ASM_CELL_PIC_H |
3 | #ifdef __KERNEL__ | 3 | #ifdef __KERNEL__ |
4 | /* | 4 | /* |
5 | * Mapping of IIC pending bits into per-node | 5 | * Mapping of IIC pending bits into per-node interrupt numbers. |
6 | * interrupt numbers. | ||
7 | * | 6 | * |
8 | * IRQ FF CC SS PP FF CC SS PP Description | 7 | * Interrupt numbers are in the range 0...0x1ff where the top bit |
8 | * (0x100) represent the source node. Only 2 nodes are supported with | ||
9 | * the current code though it's trivial to extend that if necessary using | ||
10 | * higher level bits | ||
9 | * | 11 | * |
10 | * 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge | 12 | * The bottom 8 bits are split into 2 type bits and 6 data bits that |
11 | * 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge | 13 | * depend on the type: |
12 | * 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0 | ||
13 | * 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1 | ||
14 | * 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2 | ||
15 | * 70-7f C0 ** ** 00 - C0 ** ** 0f IPI | ||
16 | * | 14 | * |
17 | * F flags | 15 | * 00 (0x00 | data) : normal interrupt. data is (class << 4) | source |
18 | * C class | 16 | * 01 (0x40 | data) : IO exception. data is the exception number as |
19 | * S source | 17 | * defined by bit numbers in IIC_SR |
20 | * P Priority | 18 | * 10 (0x80 | data) : IPI. data is the IPI number (obtained from the priority) |
21 | * + node number | 19 | * and node is always 0 (IPIs are per-cpu, their source is |
22 | * * don't care | 20 | * not relevant) |
21 | * 11 (0xc0 | data) : reserved | ||
23 | * | 22 | * |
24 | * A node consists of a Cell Broadband Engine and an optional | 23 | * In addition, interrupt number 0x80000000 is defined as always invalid |
25 | * south bridge device providing a maximum of 64 IRQs. | 24 | * (that is the node field is expected to never extend to move than 23 bits) |
26 | * The south bridge may be connected to either IOIF0 | ||
27 | * or IOIF1. | ||
28 | * Each SPE is represented as three IRQ lines, one per | ||
29 | * interrupt class. | ||
30 | * 16 IRQ numbers are reserved for inter processor | ||
31 | * interruptions, although these are only used in the | ||
32 | * range of the first node. | ||
33 | * | 25 | * |
34 | * This scheme needs 128 IRQ numbers per BIF node ID, | ||
35 | * which means that with the total of 512 lines | ||
36 | * available, we can have a maximum of four nodes. | ||
37 | */ | 26 | */ |
38 | 27 | ||
39 | enum { | 28 | enum { |
40 | IIC_IRQ_INVALID = 0xff, | 29 | IIC_IRQ_INVALID = 0x80000000u, |
41 | IIC_IRQ_MAX = 0x3f, | 30 | IIC_IRQ_NODE_MASK = 0x100, |
42 | IIC_IRQ_EXT_IOIF0 = 0x20, | 31 | IIC_IRQ_NODE_SHIFT = 8, |
43 | IIC_IRQ_EXT_IOIF1 = 0x2b, | 32 | IIC_IRQ_MAX = 0x1ff, |
44 | IIC_IRQ_IPI0 = 0x40, | 33 | IIC_IRQ_TYPE_MASK = 0xc0, |
45 | IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */ | 34 | IIC_IRQ_TYPE_NORMAL = 0x00, |
46 | IIC_SOURCE_COUNT = 0x50, | 35 | IIC_IRQ_TYPE_IOEXC = 0x40, |
36 | IIC_IRQ_TYPE_IPI = 0x80, | ||
37 | IIC_IRQ_CLASS_SHIFT = 4, | ||
38 | IIC_IRQ_CLASS_0 = 0x00, | ||
39 | IIC_IRQ_CLASS_1 = 0x10, | ||
40 | IIC_IRQ_CLASS_2 = 0x20, | ||
41 | IIC_SOURCE_COUNT = 0x200, | ||
42 | |||
43 | /* Here are defined the various source/dest units. Avoid using those | ||
44 | * definitions if you can, they are mostly here for reference | ||
45 | */ | ||
46 | IIC_UNIT_SPU_0 = 0x4, | ||
47 | IIC_UNIT_SPU_1 = 0x7, | ||
48 | IIC_UNIT_SPU_2 = 0x3, | ||
49 | IIC_UNIT_SPU_3 = 0x8, | ||
50 | IIC_UNIT_SPU_4 = 0x2, | ||
51 | IIC_UNIT_SPU_5 = 0x9, | ||
52 | IIC_UNIT_SPU_6 = 0x1, | ||
53 | IIC_UNIT_SPU_7 = 0xa, | ||
54 | IIC_UNIT_IOC_0 = 0x0, | ||
55 | IIC_UNIT_IOC_1 = 0xb, | ||
56 | IIC_UNIT_THREAD_0 = 0xe, /* target only */ | ||
57 | IIC_UNIT_THREAD_1 = 0xf, /* target only */ | ||
58 | IIC_UNIT_IIC = 0xe, /* source only (IO exceptions) */ | ||
59 | |||
60 | /* Base numbers for the external interrupts */ | ||
61 | IIC_IRQ_EXT_IOIF0 = | ||
62 | IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_0, | ||
63 | IIC_IRQ_EXT_IOIF1 = | ||
64 | IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_1, | ||
65 | |||
66 | /* Base numbers for the IIC_ISR interrupts */ | ||
67 | IIC_IRQ_IOEX_TMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 63, | ||
68 | IIC_IRQ_IOEX_PMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 62, | ||
69 | IIC_IRQ_IOEX_ATI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 61, | ||
70 | IIC_IRQ_IOEX_MATBFI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 60, | ||
71 | IIC_IRQ_IOEX_ELDI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 59, | ||
72 | |||
73 | /* Which bits in IIC_ISR are edge sensitive */ | ||
74 | IIC_ISR_EDGE_MASK = 0x4ul, | ||
47 | }; | 75 | }; |
48 | 76 | ||
49 | extern void iic_init_IRQ(void); | 77 | extern void iic_init_IRQ(void); |
@@ -52,7 +80,6 @@ extern void iic_request_IPIs(void); | |||
52 | extern void iic_setup_cpu(void); | 80 | extern void iic_setup_cpu(void); |
53 | 81 | ||
54 | extern u8 iic_get_target_id(int cpu); | 82 | extern u8 iic_get_target_id(int cpu); |
55 | extern struct irq_host *iic_get_irq_host(int node); | ||
56 | 83 | ||
57 | extern void spider_init_IRQ(void); | 84 | extern void spider_init_IRQ(void); |
58 | 85 | ||
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 742a03282b44..608b1ebc56b2 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c | |||
@@ -243,7 +243,6 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) | |||
243 | const u32 *imap, *tmp; | 243 | const u32 *imap, *tmp; |
244 | int imaplen, intsize, unit; | 244 | int imaplen, intsize, unit; |
245 | struct device_node *iic; | 245 | struct device_node *iic; |
246 | struct irq_host *iic_host; | ||
247 | 246 | ||
248 | #if 0 /* Enable that when we have a way to retreive the node as well */ | 247 | #if 0 /* Enable that when we have a way to retreive the node as well */ |
249 | /* First, we check wether we have a real "interrupts" in the device | 248 | /* First, we check wether we have a real "interrupts" in the device |
@@ -289,11 +288,11 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) | |||
289 | * the iic host from the iic OF node, but that way I'm still compatible | 288 | * the iic host from the iic OF node, but that way I'm still compatible |
290 | * with really really old old firmwares for which we don't have a node | 289 | * with really really old old firmwares for which we don't have a node |
291 | */ | 290 | */ |
292 | iic_host = iic_get_irq_host(pic->node_id); | ||
293 | if (iic_host == NULL) | ||
294 | return NO_IRQ; | ||
295 | /* Manufacture an IIC interrupt number of class 2 */ | 291 | /* Manufacture an IIC interrupt number of class 2 */ |
296 | virq = irq_create_mapping(iic_host, 0x20 | unit); | 292 | virq = irq_create_mapping(NULL, |
293 | (pic->node_id << IIC_IRQ_NODE_SHIFT) | | ||
294 | (2 << IIC_IRQ_CLASS_SHIFT) | | ||
295 | unit); | ||
297 | if (virq == NO_IRQ) | 296 | if (virq == NO_IRQ) |
298 | printk(KERN_ERR "spider_pic: failed to map cascade !"); | 297 | printk(KERN_ERR "spider_pic: failed to map cascade !"); |
299 | return virq; | 298 | return virq; |
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index 0f5c8ebc7fc3..f78680346e5f 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -568,24 +568,23 @@ static void spu_unmap(struct spu *spu) | |||
568 | /* This function shall be abstracted for HV platforms */ | 568 | /* This function shall be abstracted for HV platforms */ |
569 | static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) | 569 | static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) |
570 | { | 570 | { |
571 | struct irq_host *host; | ||
572 | unsigned int isrc; | 571 | unsigned int isrc; |
573 | const u32 *tmp; | 572 | const u32 *tmp; |
574 | 573 | ||
575 | host = iic_get_irq_host(spu->node); | 574 | /* Get the interrupt source unit from the device-tree */ |
576 | if (host == NULL) | ||
577 | return -ENODEV; | ||
578 | |||
579 | /* Get the interrupt source from the device-tree */ | ||
580 | tmp = get_property(np, "isrc", NULL); | 575 | tmp = get_property(np, "isrc", NULL); |
581 | if (!tmp) | 576 | if (!tmp) |
582 | return -ENODEV; | 577 | return -ENODEV; |
583 | spu->isrc = isrc = tmp[0]; | 578 | isrc = tmp[0]; |
579 | |||
580 | /* Add the node number */ | ||
581 | isrc |= spu->node << IIC_IRQ_NODE_SHIFT; | ||
582 | spu->isrc = isrc; | ||
584 | 583 | ||
585 | /* Now map interrupts of all 3 classes */ | 584 | /* Now map interrupts of all 3 classes */ |
586 | spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc); | 585 | spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); |
587 | spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc); | 586 | spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc); |
588 | spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc); | 587 | spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); |
589 | 588 | ||
590 | /* Right now, we only fail if class 2 failed */ | 589 | /* Right now, we only fail if class 2 failed */ |
591 | return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; | 590 | return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; |
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index 3eb12065df23..4aa165e010d9 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c | |||
@@ -262,14 +262,6 @@ void __init iSeries_pci_final_fixup(void) | |||
262 | mf_display_src(0xC9000200); | 262 | mf_display_src(0xC9000200); |
263 | } | 263 | } |
264 | 264 | ||
265 | void pcibios_fixup_bus(struct pci_bus *PciBus) | ||
266 | { | ||
267 | } | ||
268 | |||
269 | void pcibios_fixup_resources(struct pci_dev *pdev) | ||
270 | { | ||
271 | } | ||
272 | |||
273 | /* | 265 | /* |
274 | * Look down the chain to find the matching Device Device | 266 | * Look down the chain to find the matching Device Device |
275 | */ | 267 | */ |
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 7f1953066ff8..a0ff7ba7d666 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c | |||
@@ -649,15 +649,21 @@ static void iseries_dedicated_idle(void) | |||
649 | void __init iSeries_init_IRQ(void) { } | 649 | void __init iSeries_init_IRQ(void) { } |
650 | #endif | 650 | #endif |
651 | 651 | ||
652 | /* | ||
653 | * iSeries has no legacy IO, anything calling this function has to | ||
654 | * fail or bad things will happen | ||
655 | */ | ||
656 | static int iseries_check_legacy_ioport(unsigned int baseport) | ||
657 | { | ||
658 | return -ENODEV; | ||
659 | } | ||
660 | |||
652 | static int __init iseries_probe(void) | 661 | static int __init iseries_probe(void) |
653 | { | 662 | { |
654 | unsigned long root = of_get_flat_dt_root(); | 663 | unsigned long root = of_get_flat_dt_root(); |
655 | if (!of_flat_dt_is_compatible(root, "IBM,iSeries")) | 664 | if (!of_flat_dt_is_compatible(root, "IBM,iSeries")) |
656 | return 0; | 665 | return 0; |
657 | 666 | ||
658 | powerpc_firmware_features |= FW_FEATURE_ISERIES; | ||
659 | powerpc_firmware_features |= FW_FEATURE_LPAR; | ||
660 | |||
661 | hpte_init_iSeries(); | 667 | hpte_init_iSeries(); |
662 | 668 | ||
663 | return 1; | 669 | return 1; |
@@ -680,6 +686,7 @@ define_machine(iseries) { | |||
680 | .calibrate_decr = generic_calibrate_decr, | 686 | .calibrate_decr = generic_calibrate_decr, |
681 | .progress = iSeries_progress, | 687 | .progress = iSeries_progress, |
682 | .probe = iseries_probe, | 688 | .probe = iseries_probe, |
689 | .check_legacy_ioport = iseries_check_legacy_ioport, | ||
683 | /* XXX Implement enable_pmcs for iSeries */ | 690 | /* XXX Implement enable_pmcs for iSeries */ |
684 | }; | 691 | }; |
685 | 692 | ||
@@ -687,6 +694,9 @@ void * __init iSeries_early_setup(void) | |||
687 | { | 694 | { |
688 | unsigned long phys_mem_size; | 695 | unsigned long phys_mem_size; |
689 | 696 | ||
697 | powerpc_firmware_features |= FW_FEATURE_ISERIES; | ||
698 | powerpc_firmware_features |= FW_FEATURE_LPAR; | ||
699 | |||
690 | iSeries_fixup_klimit(); | 700 | iSeries_fixup_klimit(); |
691 | 701 | ||
692 | /* | 702 | /* |
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c index ce1a235855f7..379db05b0082 100644 --- a/arch/powerpc/platforms/powermac/udbg_scc.c +++ b/arch/powerpc/platforms/powermac/udbg_scc.c | |||
@@ -111,8 +111,6 @@ void udbg_scc_init(int force_scc) | |||
111 | pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch, | 111 | pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch, |
112 | PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); | 112 | PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1); |
113 | 113 | ||
114 | |||
115 | /* Setup for 57600 8N1 */ | ||
116 | if (ch == ch_a) | 114 | if (ch == ch_a) |
117 | addr += 0x20; | 115 | addr += 0x20; |
118 | sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ; | 116 | sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ; |
@@ -125,9 +123,21 @@ void udbg_scc_init(int force_scc) | |||
125 | x = in_8(sccc); | 123 | x = in_8(sccc); |
126 | out_8(sccc, 0x09); /* reset A or B side */ | 124 | out_8(sccc, 0x09); /* reset A or B side */ |
127 | out_8(sccc, 0xc0); | 125 | out_8(sccc, 0xc0); |
126 | |||
127 | /* If SCC was the OF output port, read the BRG value, else | ||
128 | * Setup for 57600 8N1 | ||
129 | */ | ||
130 | if (ch_def != NULL) { | ||
131 | out_8(sccc, 13); | ||
132 | scc_inittab[1] = in_8(sccc); | ||
133 | out_8(sccc, 12); | ||
134 | scc_inittab[3] = in_8(sccc); | ||
135 | } | ||
136 | |||
128 | for (i = 0; i < sizeof(scc_inittab); ++i) | 137 | for (i = 0; i < sizeof(scc_inittab); ++i) |
129 | out_8(sccc, scc_inittab[i]); | 138 | out_8(sccc, scc_inittab[i]); |
130 | 139 | ||
140 | |||
131 | udbg_putc = udbg_scc_putc; | 141 | udbg_putc = udbg_scc_putc; |
132 | udbg_getc = udbg_scc_getc; | 142 | udbg_getc = udbg_scc_getc; |
133 | udbg_getc_poll = udbg_scc_getc_poll; | 143 | udbg_getc_poll = udbg_scc_getc_poll; |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 43dbf737698c..f82b13e531a3 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -180,7 +180,7 @@ static void __init pseries_mpic_init_IRQ(void) | |||
180 | 180 | ||
181 | cascade_irq = irq_of_parse_and_map(cascade, 0); | 181 | cascade_irq = irq_of_parse_and_map(cascade, 0); |
182 | if (cascade == NO_IRQ) { | 182 | if (cascade == NO_IRQ) { |
183 | printk(KERN_ERR "xics: failed to map cascade interrupt"); | 183 | printk(KERN_ERR "mpic: failed to map cascade interrupt"); |
184 | return; | 184 | return; |
185 | } | 185 | } |
186 | 186 | ||
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index f15f4d78aee9..91f052d8cce0 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile | |||
@@ -12,6 +12,7 @@ obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o | |||
12 | obj-$(CONFIG_FSL_SOC) += fsl_soc.o | 12 | obj-$(CONFIG_FSL_SOC) += fsl_soc.o |
13 | obj-$(CONFIG_PPC_TODC) += todc.o | 13 | obj-$(CONFIG_PPC_TODC) += todc.o |
14 | obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o | 14 | obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o |
15 | obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ | ||
15 | 16 | ||
16 | ifeq ($(CONFIG_PPC_MERGE),y) | 17 | ifeq ($(CONFIG_PPC_MERGE),y) |
17 | obj-$(CONFIG_PPC_I8259) += i8259.o | 18 | obj-$(CONFIG_PPC_I8259) += i8259.o |
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 51752990f7b9..28b018994746 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c | |||
@@ -147,7 +147,7 @@ static struct irq_chip cpm2_pic = { | |||
147 | .end = cpm2_end_irq, | 147 | .end = cpm2_end_irq, |
148 | }; | 148 | }; |
149 | 149 | ||
150 | int cpm2_get_irq(struct pt_regs *regs) | 150 | unsigned int cpm2_get_irq(struct pt_regs *regs) |
151 | { | 151 | { |
152 | int irq; | 152 | int irq; |
153 | unsigned long bits; | 153 | unsigned long bits; |
diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h index d63e45d4df58..3c513e5a688e 100644 --- a/arch/powerpc/sysdev/cpm2_pic.h +++ b/arch/powerpc/sysdev/cpm2_pic.h | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | extern intctl_cpm2_t *cpm2_intctl; | 4 | extern intctl_cpm2_t *cpm2_intctl; |
5 | 5 | ||
6 | extern int cpm2_get_irq(struct pt_regs *regs); | 6 | extern unsigned int cpm2_get_irq(struct pt_regs *regs); |
7 | 7 | ||
8 | extern void cpm2_pic_init(struct device_node*); | 8 | extern void cpm2_pic_init(struct device_node*); |
9 | 9 | ||
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 022ed275ea68..7d759f1c26b1 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <asm/cpm2.h> | 37 | #include <asm/cpm2.h> |
38 | 38 | ||
39 | extern void init_fcc_ioports(struct fs_platform_info*); | 39 | extern void init_fcc_ioports(struct fs_platform_info*); |
40 | extern void init_scc_ioports(struct fs_uart_platform_info*); | ||
40 | static phys_addr_t immrbase = -1; | 41 | static phys_addr_t immrbase = -1; |
41 | 42 | ||
42 | phys_addr_t get_immrbase(void) | 43 | phys_addr_t get_immrbase(void) |
@@ -566,7 +567,7 @@ static int __init fs_enet_of_init(void) | |||
566 | struct resource r[4]; | 567 | struct resource r[4]; |
567 | struct device_node *phy, *mdio; | 568 | struct device_node *phy, *mdio; |
568 | struct fs_platform_info fs_enet_data; | 569 | struct fs_platform_info fs_enet_data; |
569 | const unsigned int *id, *phy_addr; | 570 | const unsigned int *id, *phy_addr, phy_irq; |
570 | const void *mac_addr; | 571 | const void *mac_addr; |
571 | const phandle *ph; | 572 | const phandle *ph; |
572 | const char *model; | 573 | const char *model; |
@@ -588,6 +589,7 @@ static int __init fs_enet_of_init(void) | |||
588 | if (ret) | 589 | if (ret) |
589 | goto err; | 590 | goto err; |
590 | r[2].name = fcc_regs_c; | 591 | r[2].name = fcc_regs_c; |
592 | fs_enet_data.fcc_regs_c = r[2].start; | ||
591 | 593 | ||
592 | r[3].start = r[3].end = irq_of_parse_and_map(np, 0); | 594 | r[3].start = r[3].end = irq_of_parse_and_map(np, 0); |
593 | r[3].flags = IORESOURCE_IRQ; | 595 | r[3].flags = IORESOURCE_IRQ; |
@@ -620,6 +622,8 @@ static int __init fs_enet_of_init(void) | |||
620 | phy_addr = get_property(phy, "reg", NULL); | 622 | phy_addr = get_property(phy, "reg", NULL); |
621 | fs_enet_data.phy_addr = *phy_addr; | 623 | fs_enet_data.phy_addr = *phy_addr; |
622 | 624 | ||
625 | phy_irq = get_property(phy, "interrupts", NULL); | ||
626 | |||
623 | id = get_property(np, "device-id", NULL); | 627 | id = get_property(np, "device-id", NULL); |
624 | fs_enet_data.fs_no = *id; | 628 | fs_enet_data.fs_no = *id; |
625 | strcpy(fs_enet_data.fs_type, model); | 629 | strcpy(fs_enet_data.fs_type, model); |
@@ -637,6 +641,7 @@ static int __init fs_enet_of_init(void) | |||
637 | 641 | ||
638 | if (strstr(model, "FCC")) { | 642 | if (strstr(model, "FCC")) { |
639 | int fcc_index = *id - 1; | 643 | int fcc_index = *id - 1; |
644 | unsigned char* mdio_bb_prop; | ||
640 | 645 | ||
641 | fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0); | 646 | fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0); |
642 | fs_enet_data.rx_ring = 32; | 647 | fs_enet_data.rx_ring = 32; |
@@ -652,14 +657,57 @@ static int __init fs_enet_of_init(void) | |||
652 | (u32)res.start, fs_enet_data.phy_addr); | 657 | (u32)res.start, fs_enet_data.phy_addr); |
653 | fs_enet_data.bus_id = (char*)&bus_id[(*id)]; | 658 | fs_enet_data.bus_id = (char*)&bus_id[(*id)]; |
654 | fs_enet_data.init_ioports = init_fcc_ioports; | 659 | fs_enet_data.init_ioports = init_fcc_ioports; |
655 | } | ||
656 | 660 | ||
657 | of_node_put(phy); | 661 | mdio_bb_prop = get_property(phy, "bitbang", NULL); |
658 | of_node_put(mdio); | 662 | if (mdio_bb_prop) { |
663 | struct platform_device *fs_enet_mdio_bb_dev; | ||
664 | struct fs_mii_bb_platform_info fs_enet_mdio_bb_data; | ||
665 | |||
666 | fs_enet_mdio_bb_dev = | ||
667 | platform_device_register_simple("fsl-bb-mdio", | ||
668 | i, NULL, 0); | ||
669 | memset(&fs_enet_mdio_bb_data, 0, | ||
670 | sizeof(struct fs_mii_bb_platform_info)); | ||
671 | fs_enet_mdio_bb_data.mdio_dat.bit = | ||
672 | mdio_bb_prop[0]; | ||
673 | fs_enet_mdio_bb_data.mdio_dir.bit = | ||
674 | mdio_bb_prop[1]; | ||
675 | fs_enet_mdio_bb_data.mdc_dat.bit = | ||
676 | mdio_bb_prop[2]; | ||
677 | fs_enet_mdio_bb_data.mdio_port = | ||
678 | mdio_bb_prop[3]; | ||
679 | fs_enet_mdio_bb_data.mdc_port = | ||
680 | mdio_bb_prop[4]; | ||
681 | fs_enet_mdio_bb_data.delay = | ||
682 | mdio_bb_prop[5]; | ||
683 | |||
684 | fs_enet_mdio_bb_data.irq[0] = phy_irq[0]; | ||
685 | fs_enet_mdio_bb_data.irq[1] = -1; | ||
686 | fs_enet_mdio_bb_data.irq[2] = -1; | ||
687 | fs_enet_mdio_bb_data.irq[3] = phy_irq[0]; | ||
688 | fs_enet_mdio_bb_data.irq[31] = -1; | ||
689 | |||
690 | fs_enet_mdio_bb_data.mdio_dat.offset = | ||
691 | (u32)&cpm2_immr->im_ioport.iop_pdatc; | ||
692 | fs_enet_mdio_bb_data.mdio_dir.offset = | ||
693 | (u32)&cpm2_immr->im_ioport.iop_pdirc; | ||
694 | fs_enet_mdio_bb_data.mdc_dat.offset = | ||
695 | (u32)&cpm2_immr->im_ioport.iop_pdatc; | ||
696 | |||
697 | ret = platform_device_add_data( | ||
698 | fs_enet_mdio_bb_dev, | ||
699 | &fs_enet_mdio_bb_data, | ||
700 | sizeof(struct fs_mii_bb_platform_info)); | ||
701 | if (ret) | ||
702 | goto unreg; | ||
703 | } | ||
704 | |||
705 | of_node_put(phy); | ||
706 | of_node_put(mdio); | ||
659 | 707 | ||
660 | ret = platform_device_add_data(fs_enet_dev, &fs_enet_data, | 708 | ret = platform_device_add_data(fs_enet_dev, &fs_enet_data, |
661 | sizeof(struct | 709 | sizeof(struct |
662 | fs_platform_info)); | 710 | fs_platform_info)); |
663 | if (ret) | 711 | if (ret) |
664 | goto unreg; | 712 | goto unreg; |
665 | } | 713 | } |
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 723972bb5bd9..3ee03a9a98fa 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -341,7 +341,7 @@ static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase, | |||
341 | u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); | 341 | u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); |
342 | if (id == PCI_CAP_ID_HT) { | 342 | if (id == PCI_CAP_ID_HT) { |
343 | id = readb(devbase + pos + 3); | 343 | id = readb(devbase + pos + 3); |
344 | if (id == 0x80) | 344 | if (id == HT_CAPTYPE_IRQ) |
345 | break; | 345 | break; |
346 | } | 346 | } |
347 | } | 347 | } |
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig new file mode 100644 index 000000000000..a725e80befa8 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/Kconfig | |||
@@ -0,0 +1,30 @@ | |||
1 | # | ||
2 | # QE Communication options | ||
3 | # | ||
4 | |||
5 | menu "QE Options" | ||
6 | depends on QUICC_ENGINE | ||
7 | |||
8 | config UCC_SLOW | ||
9 | bool "UCC Slow Protocols Support" | ||
10 | default n | ||
11 | select UCC | ||
12 | help | ||
13 | This option provides qe_lib support to UCC slow | ||
14 | protocols: UART, BISYNC, QMC | ||
15 | |||
16 | config UCC_FAST | ||
17 | bool "UCC Fast Protocols Support" | ||
18 | default n | ||
19 | select UCC | ||
20 | select UCC_SLOW | ||
21 | help | ||
22 | This option provides qe_lib support to UCC fast | ||
23 | protocols: HDLC, Ethernet, ATM, transparent | ||
24 | |||
25 | config UCC | ||
26 | bool | ||
27 | default y if UCC_FAST || UCC_SLOW | ||
28 | |||
29 | endmenu | ||
30 | |||
diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/sysdev/qe_lib/Makefile new file mode 100644 index 000000000000..874fe1a5b1cf --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the linux ppc-specific parts of QE | ||
3 | # | ||
4 | obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_ic.o qe_io.o | ||
5 | |||
6 | obj-$(CONFIG_UCC) += ucc.o | ||
7 | obj-$(CONFIG_UCC_SLOW) += ucc_slow.o | ||
8 | obj-$(CONFIG_UCC_FAST) += ucc_fast.o | ||
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c new file mode 100644 index 000000000000..2bae632d3ad7 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/qe.c | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Authors: Shlomi Gridish <gridish@freescale.com> | ||
5 | * Li Yang <leoli@freescale.com> | ||
6 | * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net) | ||
7 | * | ||
8 | * Description: | ||
9 | * General Purpose functions for the global management of the | ||
10 | * QUICC Engine (QE). | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/param.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/mm.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/bootmem.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/page.h> | ||
30 | #include <asm/pgtable.h> | ||
31 | #include <asm/immap_qe.h> | ||
32 | #include <asm/qe.h> | ||
33 | #include <asm/prom.h> | ||
34 | #include <asm/rheap.h> | ||
35 | |||
36 | static void qe_snums_init(void); | ||
37 | static void qe_muram_init(void); | ||
38 | static int qe_sdma_init(void); | ||
39 | |||
40 | static DEFINE_SPINLOCK(qe_lock); | ||
41 | |||
42 | /* QE snum state */ | ||
43 | enum qe_snum_state { | ||
44 | QE_SNUM_STATE_USED, | ||
45 | QE_SNUM_STATE_FREE | ||
46 | }; | ||
47 | |||
48 | /* QE snum */ | ||
49 | struct qe_snum { | ||
50 | u8 num; | ||
51 | enum qe_snum_state state; | ||
52 | }; | ||
53 | |||
54 | /* We allocate this here because it is used almost exclusively for | ||
55 | * the communication processor devices. | ||
56 | */ | ||
57 | struct qe_immap *qe_immr = NULL; | ||
58 | EXPORT_SYMBOL(qe_immr); | ||
59 | |||
60 | static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */ | ||
61 | |||
62 | static phys_addr_t qebase = -1; | ||
63 | |||
64 | phys_addr_t get_qe_base(void) | ||
65 | { | ||
66 | struct device_node *qe; | ||
67 | |||
68 | if (qebase != -1) | ||
69 | return qebase; | ||
70 | |||
71 | qe = of_find_node_by_type(NULL, "qe"); | ||
72 | if (qe) { | ||
73 | unsigned int size; | ||
74 | const void *prop = get_property(qe, "reg", &size); | ||
75 | qebase = of_translate_address(qe, prop); | ||
76 | of_node_put(qe); | ||
77 | }; | ||
78 | |||
79 | return qebase; | ||
80 | } | ||
81 | |||
82 | EXPORT_SYMBOL(get_qe_base); | ||
83 | |||
84 | void qe_reset(void) | ||
85 | { | ||
86 | if (qe_immr == NULL) | ||
87 | qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE); | ||
88 | |||
89 | qe_snums_init(); | ||
90 | |||
91 | qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, | ||
92 | QE_CR_PROTOCOL_UNSPECIFIED, 0); | ||
93 | |||
94 | /* Reclaim the MURAM memory for our use. */ | ||
95 | qe_muram_init(); | ||
96 | |||
97 | if (qe_sdma_init()) | ||
98 | panic("sdma init failed!"); | ||
99 | } | ||
100 | |||
101 | int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input) | ||
102 | { | ||
103 | unsigned long flags; | ||
104 | u8 mcn_shift = 0, dev_shift = 0; | ||
105 | |||
106 | spin_lock_irqsave(&qe_lock, flags); | ||
107 | if (cmd == QE_RESET) { | ||
108 | out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG)); | ||
109 | } else { | ||
110 | if (cmd == QE_ASSIGN_PAGE) { | ||
111 | /* Here device is the SNUM, not sub-block */ | ||
112 | dev_shift = QE_CR_SNUM_SHIFT; | ||
113 | } else if (cmd == QE_ASSIGN_RISC) { | ||
114 | /* Here device is the SNUM, and mcnProtocol is | ||
115 | * e_QeCmdRiscAssignment value */ | ||
116 | dev_shift = QE_CR_SNUM_SHIFT; | ||
117 | mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT; | ||
118 | } else { | ||
119 | if (device == QE_CR_SUBBLOCK_USB) | ||
120 | mcn_shift = QE_CR_MCN_USB_SHIFT; | ||
121 | else | ||
122 | mcn_shift = QE_CR_MCN_NORMAL_SHIFT; | ||
123 | } | ||
124 | |||
125 | out_be32(&qe_immr->cp.cecdr, | ||
126 | immrbar_virt_to_phys((void *)cmd_input)); | ||
127 | out_be32(&qe_immr->cp.cecr, | ||
128 | (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32) | ||
129 | mcn_protocol << mcn_shift)); | ||
130 | } | ||
131 | |||
132 | /* wait for the QE_CR_FLG to clear */ | ||
133 | while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG) | ||
134 | cpu_relax(); | ||
135 | spin_unlock_irqrestore(&qe_lock, flags); | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | EXPORT_SYMBOL(qe_issue_cmd); | ||
140 | |||
141 | /* Set a baud rate generator. This needs lots of work. There are | ||
142 | * 16 BRGs, which can be connected to the QE channels or output | ||
143 | * as clocks. The BRGs are in two different block of internal | ||
144 | * memory mapped space. | ||
145 | * The baud rate clock is the system clock divided by something. | ||
146 | * It was set up long ago during the initial boot phase and is | ||
147 | * is given to us. | ||
148 | * Baud rate clocks are zero-based in the driver code (as that maps | ||
149 | * to port numbers). Documentation uses 1-based numbering. | ||
150 | */ | ||
151 | static unsigned int brg_clk = 0; | ||
152 | |||
153 | unsigned int get_brg_clk(void) | ||
154 | { | ||
155 | struct device_node *qe; | ||
156 | if (brg_clk) | ||
157 | return brg_clk; | ||
158 | |||
159 | qe = of_find_node_by_type(NULL, "qe"); | ||
160 | if (qe) { | ||
161 | unsigned int size; | ||
162 | const u32 *prop = get_property(qe, "brg-frequency", &size); | ||
163 | brg_clk = *prop; | ||
164 | of_node_put(qe); | ||
165 | }; | ||
166 | return brg_clk; | ||
167 | } | ||
168 | |||
169 | /* This function is used by UARTS, or anything else that uses a 16x | ||
170 | * oversampled clock. | ||
171 | */ | ||
172 | void qe_setbrg(u32 brg, u32 rate) | ||
173 | { | ||
174 | volatile u32 *bp; | ||
175 | u32 divisor, tempval; | ||
176 | int div16 = 0; | ||
177 | |||
178 | bp = &qe_immr->brg.brgc1; | ||
179 | bp += brg; | ||
180 | |||
181 | divisor = (get_brg_clk() / rate); | ||
182 | if (divisor > QE_BRGC_DIVISOR_MAX + 1) { | ||
183 | div16 = 1; | ||
184 | divisor /= 16; | ||
185 | } | ||
186 | |||
187 | tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; | ||
188 | if (div16) | ||
189 | tempval |= QE_BRGC_DIV16; | ||
190 | |||
191 | out_be32(bp, tempval); | ||
192 | } | ||
193 | |||
194 | /* Initialize SNUMs (thread serial numbers) according to | ||
195 | * QE Module Control chapter, SNUM table | ||
196 | */ | ||
197 | static void qe_snums_init(void) | ||
198 | { | ||
199 | int i; | ||
200 | static const u8 snum_init[] = { | ||
201 | 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D, | ||
202 | 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89, | ||
203 | 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9, | ||
204 | 0xD8, 0xD9, 0xE8, 0xE9, | ||
205 | }; | ||
206 | |||
207 | for (i = 0; i < QE_NUM_OF_SNUM; i++) { | ||
208 | snums[i].num = snum_init[i]; | ||
209 | snums[i].state = QE_SNUM_STATE_FREE; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | int qe_get_snum(void) | ||
214 | { | ||
215 | unsigned long flags; | ||
216 | int snum = -EBUSY; | ||
217 | int i; | ||
218 | |||
219 | spin_lock_irqsave(&qe_lock, flags); | ||
220 | for (i = 0; i < QE_NUM_OF_SNUM; i++) { | ||
221 | if (snums[i].state == QE_SNUM_STATE_FREE) { | ||
222 | snums[i].state = QE_SNUM_STATE_USED; | ||
223 | snum = snums[i].num; | ||
224 | break; | ||
225 | } | ||
226 | } | ||
227 | spin_unlock_irqrestore(&qe_lock, flags); | ||
228 | |||
229 | return snum; | ||
230 | } | ||
231 | EXPORT_SYMBOL(qe_get_snum); | ||
232 | |||
233 | void qe_put_snum(u8 snum) | ||
234 | { | ||
235 | int i; | ||
236 | |||
237 | for (i = 0; i < QE_NUM_OF_SNUM; i++) { | ||
238 | if (snums[i].num == snum) { | ||
239 | snums[i].state = QE_SNUM_STATE_FREE; | ||
240 | break; | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | EXPORT_SYMBOL(qe_put_snum); | ||
245 | |||
246 | static int qe_sdma_init(void) | ||
247 | { | ||
248 | struct sdma *sdma = &qe_immr->sdma; | ||
249 | u32 sdma_buf_offset; | ||
250 | |||
251 | if (!sdma) | ||
252 | return -ENODEV; | ||
253 | |||
254 | /* allocate 2 internal temporary buffers (512 bytes size each) for | ||
255 | * the SDMA */ | ||
256 | sdma_buf_offset = qe_muram_alloc(512 * 2, 64); | ||
257 | if (IS_MURAM_ERR(sdma_buf_offset)) | ||
258 | return -ENOMEM; | ||
259 | |||
260 | out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK); | ||
261 | out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | (0x1 >> | ||
262 | QE_SDMR_CEN_SHIFT))); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * muram_alloc / muram_free bits. | ||
269 | */ | ||
270 | static DEFINE_SPINLOCK(qe_muram_lock); | ||
271 | |||
272 | /* 16 blocks should be enough to satisfy all requests | ||
273 | * until the memory subsystem goes up... */ | ||
274 | static rh_block_t qe_boot_muram_rh_block[16]; | ||
275 | static rh_info_t qe_muram_info; | ||
276 | |||
277 | static void qe_muram_init(void) | ||
278 | { | ||
279 | struct device_node *np; | ||
280 | u32 address; | ||
281 | u64 size; | ||
282 | unsigned int flags; | ||
283 | |||
284 | /* initialize the info header */ | ||
285 | rh_init(&qe_muram_info, 1, | ||
286 | sizeof(qe_boot_muram_rh_block) / | ||
287 | sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block); | ||
288 | |||
289 | /* Attach the usable muram area */ | ||
290 | /* XXX: This is a subset of the available muram. It | ||
291 | * varies with the processor and the microcode patches activated. | ||
292 | */ | ||
293 | if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) { | ||
294 | address = *of_get_address(np, 0, &size, &flags); | ||
295 | of_node_put(np); | ||
296 | rh_attach_region(&qe_muram_info, | ||
297 | (void *)address, (int)size); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | /* This function returns an index into the MURAM area. | ||
302 | */ | ||
303 | u32 qe_muram_alloc(u32 size, u32 align) | ||
304 | { | ||
305 | void *start; | ||
306 | unsigned long flags; | ||
307 | |||
308 | spin_lock_irqsave(&qe_muram_lock, flags); | ||
309 | start = rh_alloc_align(&qe_muram_info, size, align, "QE"); | ||
310 | spin_unlock_irqrestore(&qe_muram_lock, flags); | ||
311 | |||
312 | return (u32) start; | ||
313 | } | ||
314 | EXPORT_SYMBOL(qe_muram_alloc); | ||
315 | |||
316 | int qe_muram_free(u32 offset) | ||
317 | { | ||
318 | int ret; | ||
319 | unsigned long flags; | ||
320 | |||
321 | spin_lock_irqsave(&qe_muram_lock, flags); | ||
322 | ret = rh_free(&qe_muram_info, (void *)offset); | ||
323 | spin_unlock_irqrestore(&qe_muram_lock, flags); | ||
324 | |||
325 | return ret; | ||
326 | } | ||
327 | EXPORT_SYMBOL(qe_muram_free); | ||
328 | |||
329 | /* not sure if this is ever needed */ | ||
330 | u32 qe_muram_alloc_fixed(u32 offset, u32 size) | ||
331 | { | ||
332 | void *start; | ||
333 | unsigned long flags; | ||
334 | |||
335 | spin_lock_irqsave(&qe_muram_lock, flags); | ||
336 | start = rh_alloc_fixed(&qe_muram_info, (void *)offset, size, "commproc"); | ||
337 | spin_unlock_irqrestore(&qe_muram_lock, flags); | ||
338 | |||
339 | return (u32) start; | ||
340 | } | ||
341 | EXPORT_SYMBOL(qe_muram_alloc_fixed); | ||
342 | |||
343 | void qe_muram_dump(void) | ||
344 | { | ||
345 | rh_dump(&qe_muram_info); | ||
346 | } | ||
347 | EXPORT_SYMBOL(qe_muram_dump); | ||
348 | |||
349 | void *qe_muram_addr(u32 offset) | ||
350 | { | ||
351 | return (void *)&qe_immr->muram[offset]; | ||
352 | } | ||
353 | EXPORT_SYMBOL(qe_muram_addr); | ||
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c new file mode 100644 index 000000000000..c229d07d4957 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c | |||
@@ -0,0 +1,555 @@ | |||
1 | /* | ||
2 | * arch/powerpc/sysdev/qe_lib/qe_ic.c | ||
3 | * | ||
4 | * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. | ||
5 | * | ||
6 | * Author: Li Yang <leoli@freescale.com> | ||
7 | * Based on code from Shlomi Gridish <gridish@freescale.com> | ||
8 | * | ||
9 | * QUICC ENGINE Interrupt Controller | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/reboot.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/stddef.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/signal.h> | ||
25 | #include <linux/sysdev.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/bootmem.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | #include <asm/irq.h> | ||
30 | #include <asm/io.h> | ||
31 | #include <asm/prom.h> | ||
32 | #include <asm/qe_ic.h> | ||
33 | |||
34 | #include "qe_ic.h" | ||
35 | |||
36 | static DEFINE_SPINLOCK(qe_ic_lock); | ||
37 | |||
38 | static struct qe_ic_info qe_ic_info[] = { | ||
39 | [1] = { | ||
40 | .mask = 0x00008000, | ||
41 | .mask_reg = QEIC_CIMR, | ||
42 | .pri_code = 0, | ||
43 | .pri_reg = QEIC_CIPWCC, | ||
44 | }, | ||
45 | [2] = { | ||
46 | .mask = 0x00004000, | ||
47 | .mask_reg = QEIC_CIMR, | ||
48 | .pri_code = 1, | ||
49 | .pri_reg = QEIC_CIPWCC, | ||
50 | }, | ||
51 | [3] = { | ||
52 | .mask = 0x00002000, | ||
53 | .mask_reg = QEIC_CIMR, | ||
54 | .pri_code = 2, | ||
55 | .pri_reg = QEIC_CIPWCC, | ||
56 | }, | ||
57 | [10] = { | ||
58 | .mask = 0x00000040, | ||
59 | .mask_reg = QEIC_CIMR, | ||
60 | .pri_code = 1, | ||
61 | .pri_reg = QEIC_CIPZCC, | ||
62 | }, | ||
63 | [11] = { | ||
64 | .mask = 0x00000020, | ||
65 | .mask_reg = QEIC_CIMR, | ||
66 | .pri_code = 2, | ||
67 | .pri_reg = QEIC_CIPZCC, | ||
68 | }, | ||
69 | [12] = { | ||
70 | .mask = 0x00000010, | ||
71 | .mask_reg = QEIC_CIMR, | ||
72 | .pri_code = 3, | ||
73 | .pri_reg = QEIC_CIPZCC, | ||
74 | }, | ||
75 | [13] = { | ||
76 | .mask = 0x00000008, | ||
77 | .mask_reg = QEIC_CIMR, | ||
78 | .pri_code = 4, | ||
79 | .pri_reg = QEIC_CIPZCC, | ||
80 | }, | ||
81 | [14] = { | ||
82 | .mask = 0x00000004, | ||
83 | .mask_reg = QEIC_CIMR, | ||
84 | .pri_code = 5, | ||
85 | .pri_reg = QEIC_CIPZCC, | ||
86 | }, | ||
87 | [15] = { | ||
88 | .mask = 0x00000002, | ||
89 | .mask_reg = QEIC_CIMR, | ||
90 | .pri_code = 6, | ||
91 | .pri_reg = QEIC_CIPZCC, | ||
92 | }, | ||
93 | [20] = { | ||
94 | .mask = 0x10000000, | ||
95 | .mask_reg = QEIC_CRIMR, | ||
96 | .pri_code = 3, | ||
97 | .pri_reg = QEIC_CIPRTA, | ||
98 | }, | ||
99 | [25] = { | ||
100 | .mask = 0x00800000, | ||
101 | .mask_reg = QEIC_CRIMR, | ||
102 | .pri_code = 0, | ||
103 | .pri_reg = QEIC_CIPRTB, | ||
104 | }, | ||
105 | [26] = { | ||
106 | .mask = 0x00400000, | ||
107 | .mask_reg = QEIC_CRIMR, | ||
108 | .pri_code = 1, | ||
109 | .pri_reg = QEIC_CIPRTB, | ||
110 | }, | ||
111 | [27] = { | ||
112 | .mask = 0x00200000, | ||
113 | .mask_reg = QEIC_CRIMR, | ||
114 | .pri_code = 2, | ||
115 | .pri_reg = QEIC_CIPRTB, | ||
116 | }, | ||
117 | [28] = { | ||
118 | .mask = 0x00100000, | ||
119 | .mask_reg = QEIC_CRIMR, | ||
120 | .pri_code = 3, | ||
121 | .pri_reg = QEIC_CIPRTB, | ||
122 | }, | ||
123 | [32] = { | ||
124 | .mask = 0x80000000, | ||
125 | .mask_reg = QEIC_CIMR, | ||
126 | .pri_code = 0, | ||
127 | .pri_reg = QEIC_CIPXCC, | ||
128 | }, | ||
129 | [33] = { | ||
130 | .mask = 0x40000000, | ||
131 | .mask_reg = QEIC_CIMR, | ||
132 | .pri_code = 1, | ||
133 | .pri_reg = QEIC_CIPXCC, | ||
134 | }, | ||
135 | [34] = { | ||
136 | .mask = 0x20000000, | ||
137 | .mask_reg = QEIC_CIMR, | ||
138 | .pri_code = 2, | ||
139 | .pri_reg = QEIC_CIPXCC, | ||
140 | }, | ||
141 | [35] = { | ||
142 | .mask = 0x10000000, | ||
143 | .mask_reg = QEIC_CIMR, | ||
144 | .pri_code = 3, | ||
145 | .pri_reg = QEIC_CIPXCC, | ||
146 | }, | ||
147 | [36] = { | ||
148 | .mask = 0x08000000, | ||
149 | .mask_reg = QEIC_CIMR, | ||
150 | .pri_code = 4, | ||
151 | .pri_reg = QEIC_CIPXCC, | ||
152 | }, | ||
153 | [40] = { | ||
154 | .mask = 0x00800000, | ||
155 | .mask_reg = QEIC_CIMR, | ||
156 | .pri_code = 0, | ||
157 | .pri_reg = QEIC_CIPYCC, | ||
158 | }, | ||
159 | [41] = { | ||
160 | .mask = 0x00400000, | ||
161 | .mask_reg = QEIC_CIMR, | ||
162 | .pri_code = 1, | ||
163 | .pri_reg = QEIC_CIPYCC, | ||
164 | }, | ||
165 | [42] = { | ||
166 | .mask = 0x00200000, | ||
167 | .mask_reg = QEIC_CIMR, | ||
168 | .pri_code = 2, | ||
169 | .pri_reg = QEIC_CIPYCC, | ||
170 | }, | ||
171 | [43] = { | ||
172 | .mask = 0x00100000, | ||
173 | .mask_reg = QEIC_CIMR, | ||
174 | .pri_code = 3, | ||
175 | .pri_reg = QEIC_CIPYCC, | ||
176 | }, | ||
177 | }; | ||
178 | |||
179 | static inline u32 qe_ic_read(volatile __be32 __iomem * base, unsigned int reg) | ||
180 | { | ||
181 | return in_be32(base + (reg >> 2)); | ||
182 | } | ||
183 | |||
184 | static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg, | ||
185 | u32 value) | ||
186 | { | ||
187 | out_be32(base + (reg >> 2), value); | ||
188 | } | ||
189 | |||
190 | static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) | ||
191 | { | ||
192 | return irq_desc[virq].chip_data; | ||
193 | } | ||
194 | |||
195 | #define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) | ||
196 | |||
197 | static void qe_ic_unmask_irq(unsigned int virq) | ||
198 | { | ||
199 | struct qe_ic *qe_ic = qe_ic_from_irq(virq); | ||
200 | unsigned int src = virq_to_hw(virq); | ||
201 | unsigned long flags; | ||
202 | u32 temp; | ||
203 | |||
204 | spin_lock_irqsave(&qe_ic_lock, flags); | ||
205 | |||
206 | temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); | ||
207 | qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, | ||
208 | temp | qe_ic_info[src].mask); | ||
209 | |||
210 | spin_unlock_irqrestore(&qe_ic_lock, flags); | ||
211 | } | ||
212 | |||
213 | static void qe_ic_mask_irq(unsigned int virq) | ||
214 | { | ||
215 | struct qe_ic *qe_ic = qe_ic_from_irq(virq); | ||
216 | unsigned int src = virq_to_hw(virq); | ||
217 | unsigned long flags; | ||
218 | u32 temp; | ||
219 | |||
220 | spin_lock_irqsave(&qe_ic_lock, flags); | ||
221 | |||
222 | temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); | ||
223 | qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, | ||
224 | temp & ~qe_ic_info[src].mask); | ||
225 | |||
226 | spin_unlock_irqrestore(&qe_ic_lock, flags); | ||
227 | } | ||
228 | |||
229 | static void qe_ic_mask_irq_and_ack(unsigned int virq) | ||
230 | { | ||
231 | struct qe_ic *qe_ic = qe_ic_from_irq(virq); | ||
232 | unsigned int src = virq_to_hw(virq); | ||
233 | unsigned long flags; | ||
234 | u32 temp; | ||
235 | |||
236 | spin_lock_irqsave(&qe_ic_lock, flags); | ||
237 | |||
238 | temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg); | ||
239 | qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg, | ||
240 | temp & ~qe_ic_info[src].mask); | ||
241 | |||
242 | /* There is nothing to do for ack here, ack is handled in ISR */ | ||
243 | |||
244 | spin_unlock_irqrestore(&qe_ic_lock, flags); | ||
245 | } | ||
246 | |||
247 | static struct irq_chip qe_ic_irq_chip = { | ||
248 | .typename = " QEIC ", | ||
249 | .unmask = qe_ic_unmask_irq, | ||
250 | .mask = qe_ic_mask_irq, | ||
251 | .mask_ack = qe_ic_mask_irq_and_ack, | ||
252 | }; | ||
253 | |||
254 | static int qe_ic_host_match(struct irq_host *h, struct device_node *node) | ||
255 | { | ||
256 | struct qe_ic *qe_ic = h->host_data; | ||
257 | |||
258 | /* Exact match, unless qe_ic node is NULL */ | ||
259 | return qe_ic->of_node == NULL || qe_ic->of_node == node; | ||
260 | } | ||
261 | |||
262 | static int qe_ic_host_map(struct irq_host *h, unsigned int virq, | ||
263 | irq_hw_number_t hw) | ||
264 | { | ||
265 | struct qe_ic *qe_ic = h->host_data; | ||
266 | struct irq_chip *chip; | ||
267 | |||
268 | if (qe_ic_info[hw].mask == 0) { | ||
269 | printk(KERN_ERR "Can't map reserved IRQ \n"); | ||
270 | return -EINVAL; | ||
271 | } | ||
272 | /* Default chip */ | ||
273 | chip = &qe_ic->hc_irq; | ||
274 | |||
275 | set_irq_chip_data(virq, qe_ic); | ||
276 | get_irq_desc(virq)->status |= IRQ_LEVEL; | ||
277 | |||
278 | set_irq_chip_and_handler(virq, chip, handle_level_irq); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct, | ||
284 | u32 * intspec, unsigned int intsize, | ||
285 | irq_hw_number_t * out_hwirq, | ||
286 | unsigned int *out_flags) | ||
287 | { | ||
288 | *out_hwirq = intspec[0]; | ||
289 | if (intsize > 1) | ||
290 | *out_flags = intspec[1]; | ||
291 | else | ||
292 | *out_flags = IRQ_TYPE_NONE; | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static struct irq_host_ops qe_ic_host_ops = { | ||
297 | .match = qe_ic_host_match, | ||
298 | .map = qe_ic_host_map, | ||
299 | .xlate = qe_ic_host_xlate, | ||
300 | }; | ||
301 | |||
302 | /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ | ||
303 | unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic, struct pt_regs *regs) | ||
304 | { | ||
305 | int irq; | ||
306 | |||
307 | BUG_ON(qe_ic == NULL); | ||
308 | |||
309 | /* get the interrupt source vector. */ | ||
310 | irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26; | ||
311 | |||
312 | if (irq == 0) | ||
313 | return NO_IRQ; | ||
314 | |||
315 | return irq_linear_revmap(qe_ic->irqhost, irq); | ||
316 | } | ||
317 | |||
318 | /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ | ||
319 | unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic, struct pt_regs *regs) | ||
320 | { | ||
321 | int irq; | ||
322 | |||
323 | BUG_ON(qe_ic == NULL); | ||
324 | |||
325 | /* get the interrupt source vector. */ | ||
326 | irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26; | ||
327 | |||
328 | if (irq == 0) | ||
329 | return NO_IRQ; | ||
330 | |||
331 | return irq_linear_revmap(qe_ic->irqhost, irq); | ||
332 | } | ||
333 | |||
334 | /* FIXME: We mask all the QE Low interrupts while handling. We should | ||
335 | * let other interrupt come in, but BAD interrupts are generated */ | ||
336 | void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc, | ||
337 | struct pt_regs *regs) | ||
338 | { | ||
339 | struct qe_ic *qe_ic = desc->handler_data; | ||
340 | struct irq_chip *chip = irq_desc[irq].chip; | ||
341 | |||
342 | unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic, regs); | ||
343 | |||
344 | chip->mask_ack(irq); | ||
345 | if (cascade_irq != NO_IRQ) | ||
346 | generic_handle_irq(cascade_irq, regs); | ||
347 | chip->unmask(irq); | ||
348 | } | ||
349 | |||
350 | /* FIXME: We mask all the QE High interrupts while handling. We should | ||
351 | * let other interrupt come in, but BAD interrupts are generated */ | ||
352 | void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc, | ||
353 | struct pt_regs *regs) | ||
354 | { | ||
355 | struct qe_ic *qe_ic = desc->handler_data; | ||
356 | struct irq_chip *chip = irq_desc[irq].chip; | ||
357 | |||
358 | unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic, regs); | ||
359 | |||
360 | chip->mask_ack(irq); | ||
361 | if (cascade_irq != NO_IRQ) | ||
362 | generic_handle_irq(cascade_irq, regs); | ||
363 | chip->unmask(irq); | ||
364 | } | ||
365 | |||
366 | void __init qe_ic_init(struct device_node *node, unsigned int flags) | ||
367 | { | ||
368 | struct qe_ic *qe_ic; | ||
369 | struct resource res; | ||
370 | u32 temp = 0, ret, high_active = 0; | ||
371 | |||
372 | qe_ic = alloc_bootmem(sizeof(struct qe_ic)); | ||
373 | if (qe_ic == NULL) | ||
374 | return; | ||
375 | |||
376 | memset(qe_ic, 0, sizeof(struct qe_ic)); | ||
377 | qe_ic->of_node = node ? of_node_get(node) : NULL; | ||
378 | |||
379 | qe_ic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR, | ||
380 | NR_QE_IC_INTS, &qe_ic_host_ops, 0); | ||
381 | if (qe_ic->irqhost == NULL) { | ||
382 | of_node_put(node); | ||
383 | return; | ||
384 | } | ||
385 | |||
386 | ret = of_address_to_resource(node, 0, &res); | ||
387 | if (ret) | ||
388 | return; | ||
389 | |||
390 | qe_ic->regs = ioremap(res.start, res.end - res.start + 1); | ||
391 | |||
392 | qe_ic->irqhost->host_data = qe_ic; | ||
393 | qe_ic->hc_irq = qe_ic_irq_chip; | ||
394 | |||
395 | qe_ic->virq_high = irq_of_parse_and_map(node, 0); | ||
396 | qe_ic->virq_low = irq_of_parse_and_map(node, 1); | ||
397 | |||
398 | if (qe_ic->virq_low == NO_IRQ) { | ||
399 | printk(KERN_ERR "Failed to map QE_IC low IRQ\n"); | ||
400 | return; | ||
401 | } | ||
402 | |||
403 | /* default priority scheme is grouped. If spread mode is */ | ||
404 | /* required, configure cicr accordingly. */ | ||
405 | if (flags & QE_IC_SPREADMODE_GRP_W) | ||
406 | temp |= CICR_GWCC; | ||
407 | if (flags & QE_IC_SPREADMODE_GRP_X) | ||
408 | temp |= CICR_GXCC; | ||
409 | if (flags & QE_IC_SPREADMODE_GRP_Y) | ||
410 | temp |= CICR_GYCC; | ||
411 | if (flags & QE_IC_SPREADMODE_GRP_Z) | ||
412 | temp |= CICR_GZCC; | ||
413 | if (flags & QE_IC_SPREADMODE_GRP_RISCA) | ||
414 | temp |= CICR_GRTA; | ||
415 | if (flags & QE_IC_SPREADMODE_GRP_RISCB) | ||
416 | temp |= CICR_GRTB; | ||
417 | |||
418 | /* choose destination signal for highest priority interrupt */ | ||
419 | if (flags & QE_IC_HIGH_SIGNAL) { | ||
420 | temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT); | ||
421 | high_active = 1; | ||
422 | } | ||
423 | |||
424 | qe_ic_write(qe_ic->regs, QEIC_CICR, temp); | ||
425 | |||
426 | set_irq_data(qe_ic->virq_low, qe_ic); | ||
427 | set_irq_chained_handler(qe_ic->virq_low, qe_ic_cascade_low); | ||
428 | |||
429 | if (qe_ic->virq_high != NO_IRQ) { | ||
430 | set_irq_data(qe_ic->virq_high, qe_ic); | ||
431 | set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high); | ||
432 | } | ||
433 | |||
434 | printk("QEIC (%d IRQ sources) at %p\n", NR_QE_IC_INTS, qe_ic->regs); | ||
435 | } | ||
436 | |||
437 | void qe_ic_set_highest_priority(unsigned int virq, int high) | ||
438 | { | ||
439 | struct qe_ic *qe_ic = qe_ic_from_irq(virq); | ||
440 | unsigned int src = virq_to_hw(virq); | ||
441 | u32 temp = 0; | ||
442 | |||
443 | temp = qe_ic_read(qe_ic->regs, QEIC_CICR); | ||
444 | |||
445 | temp &= ~CICR_HP_MASK; | ||
446 | temp |= src << CICR_HP_SHIFT; | ||
447 | |||
448 | temp &= ~CICR_HPIT_MASK; | ||
449 | temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT; | ||
450 | |||
451 | qe_ic_write(qe_ic->regs, QEIC_CICR, temp); | ||
452 | } | ||
453 | |||
454 | /* Set Priority level within its group, from 1 to 8 */ | ||
455 | int qe_ic_set_priority(unsigned int virq, unsigned int priority) | ||
456 | { | ||
457 | struct qe_ic *qe_ic = qe_ic_from_irq(virq); | ||
458 | unsigned int src = virq_to_hw(virq); | ||
459 | u32 temp; | ||
460 | |||
461 | if (priority > 8 || priority == 0) | ||
462 | return -EINVAL; | ||
463 | if (src > 127) | ||
464 | return -EINVAL; | ||
465 | if (qe_ic_info[src].pri_reg == 0) | ||
466 | return -EINVAL; | ||
467 | |||
468 | temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg); | ||
469 | |||
470 | if (priority < 4) { | ||
471 | temp &= ~(0x7 << (32 - priority * 3)); | ||
472 | temp |= qe_ic_info[src].pri_code << (32 - priority * 3); | ||
473 | } else { | ||
474 | temp &= ~(0x7 << (24 - priority * 3)); | ||
475 | temp |= qe_ic_info[src].pri_code << (24 - priority * 3); | ||
476 | } | ||
477 | |||
478 | qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp); | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* Set a QE priority to use high irq, only priority 1~2 can use high irq */ | ||
484 | int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high) | ||
485 | { | ||
486 | struct qe_ic *qe_ic = qe_ic_from_irq(virq); | ||
487 | unsigned int src = virq_to_hw(virq); | ||
488 | u32 temp, control_reg = QEIC_CICNR, shift = 0; | ||
489 | |||
490 | if (priority > 2 || priority == 0) | ||
491 | return -EINVAL; | ||
492 | |||
493 | switch (qe_ic_info[src].pri_reg) { | ||
494 | case QEIC_CIPZCC: | ||
495 | shift = CICNR_ZCC1T_SHIFT; | ||
496 | break; | ||
497 | case QEIC_CIPWCC: | ||
498 | shift = CICNR_WCC1T_SHIFT; | ||
499 | break; | ||
500 | case QEIC_CIPYCC: | ||
501 | shift = CICNR_YCC1T_SHIFT; | ||
502 | break; | ||
503 | case QEIC_CIPXCC: | ||
504 | shift = CICNR_XCC1T_SHIFT; | ||
505 | break; | ||
506 | case QEIC_CIPRTA: | ||
507 | shift = CRICR_RTA1T_SHIFT; | ||
508 | control_reg = QEIC_CRICR; | ||
509 | break; | ||
510 | case QEIC_CIPRTB: | ||
511 | shift = CRICR_RTB1T_SHIFT; | ||
512 | control_reg = QEIC_CRICR; | ||
513 | break; | ||
514 | default: | ||
515 | return -EINVAL; | ||
516 | } | ||
517 | |||
518 | shift += (2 - priority) * 2; | ||
519 | temp = qe_ic_read(qe_ic->regs, control_reg); | ||
520 | temp &= ~(SIGNAL_MASK << shift); | ||
521 | temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift; | ||
522 | qe_ic_write(qe_ic->regs, control_reg, temp); | ||
523 | |||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static struct sysdev_class qe_ic_sysclass = { | ||
528 | set_kset_name("qe_ic"), | ||
529 | }; | ||
530 | |||
531 | static struct sys_device device_qe_ic = { | ||
532 | .id = 0, | ||
533 | .cls = &qe_ic_sysclass, | ||
534 | }; | ||
535 | |||
536 | static int __init init_qe_ic_sysfs(void) | ||
537 | { | ||
538 | int rc; | ||
539 | |||
540 | printk(KERN_DEBUG "Registering qe_ic with sysfs...\n"); | ||
541 | |||
542 | rc = sysdev_class_register(&qe_ic_sysclass); | ||
543 | if (rc) { | ||
544 | printk(KERN_ERR "Failed registering qe_ic sys class\n"); | ||
545 | return -ENODEV; | ||
546 | } | ||
547 | rc = sysdev_register(&device_qe_ic); | ||
548 | if (rc) { | ||
549 | printk(KERN_ERR "Failed registering qe_ic sys device\n"); | ||
550 | return -ENODEV; | ||
551 | } | ||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | subsys_initcall(init_qe_ic_sysfs); | ||
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h new file mode 100644 index 000000000000..9a631adb189d --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * arch/powerpc/sysdev/qe_lib/qe_ic.h | ||
3 | * | ||
4 | * QUICC ENGINE Interrupt Controller Header | ||
5 | * | ||
6 | * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. | ||
7 | * | ||
8 | * Author: Li Yang <leoli@freescale.com> | ||
9 | * Based on code from Shlomi Gridish <gridish@freescale.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | #ifndef _POWERPC_SYSDEV_QE_IC_H | ||
17 | #define _POWERPC_SYSDEV_QE_IC_H | ||
18 | |||
19 | #include <asm/qe_ic.h> | ||
20 | |||
21 | #define NR_QE_IC_INTS 64 | ||
22 | |||
23 | /* QE IC registers offset */ | ||
24 | #define QEIC_CICR 0x00 | ||
25 | #define QEIC_CIVEC 0x04 | ||
26 | #define QEIC_CRIPNR 0x08 | ||
27 | #define QEIC_CIPNR 0x0c | ||
28 | #define QEIC_CIPXCC 0x10 | ||
29 | #define QEIC_CIPYCC 0x14 | ||
30 | #define QEIC_CIPWCC 0x18 | ||
31 | #define QEIC_CIPZCC 0x1c | ||
32 | #define QEIC_CIMR 0x20 | ||
33 | #define QEIC_CRIMR 0x24 | ||
34 | #define QEIC_CICNR 0x28 | ||
35 | #define QEIC_CIPRTA 0x30 | ||
36 | #define QEIC_CIPRTB 0x34 | ||
37 | #define QEIC_CRICR 0x3c | ||
38 | #define QEIC_CHIVEC 0x60 | ||
39 | |||
40 | /* Interrupt priority registers */ | ||
41 | #define CIPCC_SHIFT_PRI0 29 | ||
42 | #define CIPCC_SHIFT_PRI1 26 | ||
43 | #define CIPCC_SHIFT_PRI2 23 | ||
44 | #define CIPCC_SHIFT_PRI3 20 | ||
45 | #define CIPCC_SHIFT_PRI4 13 | ||
46 | #define CIPCC_SHIFT_PRI5 10 | ||
47 | #define CIPCC_SHIFT_PRI6 7 | ||
48 | #define CIPCC_SHIFT_PRI7 4 | ||
49 | |||
50 | /* CICR priority modes */ | ||
51 | #define CICR_GWCC 0x00040000 | ||
52 | #define CICR_GXCC 0x00020000 | ||
53 | #define CICR_GYCC 0x00010000 | ||
54 | #define CICR_GZCC 0x00080000 | ||
55 | #define CICR_GRTA 0x00200000 | ||
56 | #define CICR_GRTB 0x00400000 | ||
57 | #define CICR_HPIT_SHIFT 8 | ||
58 | #define CICR_HPIT_MASK 0x00000300 | ||
59 | #define CICR_HP_SHIFT 24 | ||
60 | #define CICR_HP_MASK 0x3f000000 | ||
61 | |||
62 | /* CICNR */ | ||
63 | #define CICNR_WCC1T_SHIFT 20 | ||
64 | #define CICNR_ZCC1T_SHIFT 28 | ||
65 | #define CICNR_YCC1T_SHIFT 12 | ||
66 | #define CICNR_XCC1T_SHIFT 4 | ||
67 | |||
68 | /* CRICR */ | ||
69 | #define CRICR_RTA1T_SHIFT 20 | ||
70 | #define CRICR_RTB1T_SHIFT 28 | ||
71 | |||
72 | /* Signal indicator */ | ||
73 | #define SIGNAL_MASK 3 | ||
74 | #define SIGNAL_HIGH 2 | ||
75 | #define SIGNAL_LOW 0 | ||
76 | |||
77 | struct qe_ic { | ||
78 | /* Control registers offset */ | ||
79 | volatile u32 __iomem *regs; | ||
80 | |||
81 | /* The remapper for this QEIC */ | ||
82 | struct irq_host *irqhost; | ||
83 | |||
84 | /* The "linux" controller struct */ | ||
85 | struct irq_chip hc_irq; | ||
86 | |||
87 | /* The device node of the interrupt controller */ | ||
88 | struct device_node *of_node; | ||
89 | |||
90 | /* VIRQ numbers of QE high/low irqs */ | ||
91 | unsigned int virq_high; | ||
92 | unsigned int virq_low; | ||
93 | }; | ||
94 | |||
95 | /* | ||
96 | * QE interrupt controller internal structure | ||
97 | */ | ||
98 | struct qe_ic_info { | ||
99 | u32 mask; /* location of this source at the QIMR register. */ | ||
100 | u32 mask_reg; /* Mask register offset */ | ||
101 | u8 pri_code; /* for grouped interrupts sources - the interrupt | ||
102 | code as appears at the group priority register */ | ||
103 | u32 pri_reg; /* Group priority register offset */ | ||
104 | }; | ||
105 | |||
106 | #endif /* _POWERPC_SYSDEV_QE_IC_H */ | ||
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c new file mode 100644 index 000000000000..aea435970389 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/qe_io.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * arch/powerpc/sysdev/qe_lib/qe_io.c | ||
3 | * | ||
4 | * QE Parallel I/O ports configuration routines | ||
5 | * | ||
6 | * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. | ||
7 | * | ||
8 | * Author: Li Yang <LeoLi@freescale.com> | ||
9 | * Based on code from Shlomi Gridish <gridish@freescale.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/stddef.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/ioport.h> | ||
24 | |||
25 | #include <asm/io.h> | ||
26 | #include <asm/prom.h> | ||
27 | #include <sysdev/fsl_soc.h> | ||
28 | |||
29 | #undef DEBUG | ||
30 | |||
31 | #define NUM_OF_PINS 32 | ||
32 | |||
33 | struct port_regs { | ||
34 | __be32 cpodr; /* Open drain register */ | ||
35 | __be32 cpdata; /* Data register */ | ||
36 | __be32 cpdir1; /* Direction register */ | ||
37 | __be32 cpdir2; /* Direction register */ | ||
38 | __be32 cppar1; /* Pin assignment register */ | ||
39 | __be32 cppar2; /* Pin assignment register */ | ||
40 | }; | ||
41 | |||
42 | static struct port_regs *par_io = NULL; | ||
43 | static int num_par_io_ports = 0; | ||
44 | |||
45 | int par_io_init(struct device_node *np) | ||
46 | { | ||
47 | struct resource res; | ||
48 | int ret; | ||
49 | const u32 *num_ports; | ||
50 | |||
51 | /* Map Parallel I/O ports registers */ | ||
52 | ret = of_address_to_resource(np, 0, &res); | ||
53 | if (ret) | ||
54 | return ret; | ||
55 | par_io = ioremap(res.start, res.end - res.start + 1); | ||
56 | |||
57 | num_ports = get_property(np, "num-ports", NULL); | ||
58 | if (num_ports) | ||
59 | num_par_io_ports = *num_ports; | ||
60 | |||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain, | ||
65 | int assignment, int has_irq) | ||
66 | { | ||
67 | u32 pin_mask1bit, pin_mask2bits, new_mask2bits, tmp_val; | ||
68 | |||
69 | if (!par_io) | ||
70 | return -1; | ||
71 | |||
72 | /* calculate pin location for single and 2 bits information */ | ||
73 | pin_mask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1))); | ||
74 | |||
75 | /* Set open drain, if required */ | ||
76 | tmp_val = in_be32(&par_io[port].cpodr); | ||
77 | if (open_drain) | ||
78 | out_be32(&par_io[port].cpodr, pin_mask1bit | tmp_val); | ||
79 | else | ||
80 | out_be32(&par_io[port].cpodr, ~pin_mask1bit & tmp_val); | ||
81 | |||
82 | /* define direction */ | ||
83 | tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? | ||
84 | in_be32(&par_io[port].cpdir2) : | ||
85 | in_be32(&par_io[port].cpdir1); | ||
86 | |||
87 | /* get all bits mask for 2 bit per port */ | ||
88 | pin_mask2bits = (u32) (0x3 << (NUM_OF_PINS - | ||
89 | (pin % (NUM_OF_PINS / 2) + 1) * 2)); | ||
90 | |||
91 | /* Get the final mask we need for the right definition */ | ||
92 | new_mask2bits = (u32) (dir << (NUM_OF_PINS - | ||
93 | (pin % (NUM_OF_PINS / 2) + 1) * 2)); | ||
94 | |||
95 | /* clear and set 2 bits mask */ | ||
96 | if (pin > (NUM_OF_PINS / 2) - 1) { | ||
97 | out_be32(&par_io[port].cpdir2, | ||
98 | ~pin_mask2bits & tmp_val); | ||
99 | tmp_val &= ~pin_mask2bits; | ||
100 | out_be32(&par_io[port].cpdir2, new_mask2bits | tmp_val); | ||
101 | } else { | ||
102 | out_be32(&par_io[port].cpdir1, | ||
103 | ~pin_mask2bits & tmp_val); | ||
104 | tmp_val &= ~pin_mask2bits; | ||
105 | out_be32(&par_io[port].cpdir1, new_mask2bits | tmp_val); | ||
106 | } | ||
107 | /* define pin assignment */ | ||
108 | tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ? | ||
109 | in_be32(&par_io[port].cppar2) : | ||
110 | in_be32(&par_io[port].cppar1); | ||
111 | |||
112 | new_mask2bits = (u32) (assignment << (NUM_OF_PINS - | ||
113 | (pin % (NUM_OF_PINS / 2) + 1) * 2)); | ||
114 | /* clear and set 2 bits mask */ | ||
115 | if (pin > (NUM_OF_PINS / 2) - 1) { | ||
116 | out_be32(&par_io[port].cppar2, | ||
117 | ~pin_mask2bits & tmp_val); | ||
118 | tmp_val &= ~pin_mask2bits; | ||
119 | out_be32(&par_io[port].cppar2, new_mask2bits | tmp_val); | ||
120 | } else { | ||
121 | out_be32(&par_io[port].cppar1, | ||
122 | ~pin_mask2bits & tmp_val); | ||
123 | tmp_val &= ~pin_mask2bits; | ||
124 | out_be32(&par_io[port].cppar1, new_mask2bits | tmp_val); | ||
125 | } | ||
126 | |||
127 | return 0; | ||
128 | } | ||
129 | EXPORT_SYMBOL(par_io_config_pin); | ||
130 | |||
131 | int par_io_data_set(u8 port, u8 pin, u8 val) | ||
132 | { | ||
133 | u32 pin_mask, tmp_val; | ||
134 | |||
135 | if (port >= num_par_io_ports) | ||
136 | return -EINVAL; | ||
137 | if (pin >= NUM_OF_PINS) | ||
138 | return -EINVAL; | ||
139 | /* calculate pin location */ | ||
140 | pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - pin)); | ||
141 | |||
142 | tmp_val = in_be32(&par_io[port].cpdata); | ||
143 | |||
144 | if (val == 0) /* clear */ | ||
145 | out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val); | ||
146 | else /* set */ | ||
147 | out_be32(&par_io[port].cpdata, pin_mask | tmp_val); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | EXPORT_SYMBOL(par_io_data_set); | ||
152 | |||
153 | int par_io_of_config(struct device_node *np) | ||
154 | { | ||
155 | struct device_node *pio; | ||
156 | const phandle *ph; | ||
157 | int pio_map_len; | ||
158 | const unsigned int *pio_map; | ||
159 | |||
160 | if (par_io == NULL) { | ||
161 | printk(KERN_ERR "par_io not initialized \n"); | ||
162 | return -1; | ||
163 | } | ||
164 | |||
165 | ph = get_property(np, "pio-handle", NULL); | ||
166 | if (ph == 0) { | ||
167 | printk(KERN_ERR "pio-handle not available \n"); | ||
168 | return -1; | ||
169 | } | ||
170 | |||
171 | pio = of_find_node_by_phandle(*ph); | ||
172 | |||
173 | pio_map = get_property(pio, "pio-map", &pio_map_len); | ||
174 | if (pio_map == NULL) { | ||
175 | printk(KERN_ERR "pio-map is not set! \n"); | ||
176 | return -1; | ||
177 | } | ||
178 | pio_map_len /= sizeof(unsigned int); | ||
179 | if ((pio_map_len % 6) != 0) { | ||
180 | printk(KERN_ERR "pio-map format wrong! \n"); | ||
181 | return -1; | ||
182 | } | ||
183 | |||
184 | while (pio_map_len > 0) { | ||
185 | par_io_config_pin((u8) pio_map[0], (u8) pio_map[1], | ||
186 | (int) pio_map[2], (int) pio_map[3], | ||
187 | (int) pio_map[4], (int) pio_map[5]); | ||
188 | pio_map += 6; | ||
189 | pio_map_len -= 6; | ||
190 | } | ||
191 | of_node_put(pio); | ||
192 | return 0; | ||
193 | } | ||
194 | EXPORT_SYMBOL(par_io_of_config); | ||
195 | |||
196 | #ifdef DEBUG | ||
197 | static void dump_par_io(void) | ||
198 | { | ||
199 | int i; | ||
200 | |||
201 | printk(KERN_INFO "PAR IO registars:\n"); | ||
202 | printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io); | ||
203 | for (i = 0; i < num_par_io_ports; i++) { | ||
204 | printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val - 0x%08x\n", | ||
205 | i, (u32) & par_io[i].cpodr, | ||
206 | in_be32(&par_io[i].cpodr)); | ||
207 | printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val - 0x%08x\n", | ||
208 | i, (u32) & par_io[i].cpdata, | ||
209 | in_be32(&par_io[i].cpdata)); | ||
210 | printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val - 0x%08x\n", | ||
211 | i, (u32) & par_io[i].cpdir1, | ||
212 | in_be32(&par_io[i].cpdir1)); | ||
213 | printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val - 0x%08x\n", | ||
214 | i, (u32) & par_io[i].cpdir2, | ||
215 | in_be32(&par_io[i].cpdir2)); | ||
216 | printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val - 0x%08x\n", | ||
217 | i, (u32) & par_io[i].cppar1, | ||
218 | in_be32(&par_io[i].cppar1)); | ||
219 | printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val - 0x%08x\n", | ||
220 | i, (u32) & par_io[i].cppar2, | ||
221 | in_be32(&par_io[i].cppar2)); | ||
222 | } | ||
223 | |||
224 | } | ||
225 | EXPORT_SYMBOL(dump_par_io); | ||
226 | #endif /* DEBUG */ | ||
diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c new file mode 100644 index 000000000000..916c9e5df57f --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/ucc.c | |||
@@ -0,0 +1,251 @@ | |||
1 | /* | ||
2 | * arch/powerpc/sysdev/qe_lib/ucc.c | ||
3 | * | ||
4 | * QE UCC API Set - UCC specific routines implementations. | ||
5 | * | ||
6 | * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. | ||
7 | * | ||
8 | * Authors: Shlomi Gridish <gridish@freescale.com> | ||
9 | * Li Yang <leoli@freescale.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/stddef.h> | ||
21 | |||
22 | #include <asm/irq.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <asm/immap_qe.h> | ||
25 | #include <asm/qe.h> | ||
26 | #include <asm/ucc.h> | ||
27 | |||
28 | static DEFINE_SPINLOCK(ucc_lock); | ||
29 | |||
30 | int ucc_set_qe_mux_mii_mng(int ucc_num) | ||
31 | { | ||
32 | unsigned long flags; | ||
33 | |||
34 | spin_lock_irqsave(&ucc_lock, flags); | ||
35 | out_be32(&qe_immr->qmx.cmxgcr, | ||
36 | ((in_be32(&qe_immr->qmx.cmxgcr) & | ||
37 | ~QE_CMXGCR_MII_ENET_MNG) | | ||
38 | (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT))); | ||
39 | spin_unlock_irqrestore(&ucc_lock, flags); | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | int ucc_set_type(int ucc_num, struct ucc_common *regs, | ||
45 | enum ucc_speed_type speed) | ||
46 | { | ||
47 | u8 guemr = 0; | ||
48 | |||
49 | /* check if the UCC number is in range. */ | ||
50 | if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) | ||
51 | return -EINVAL; | ||
52 | |||
53 | guemr = regs->guemr; | ||
54 | guemr &= ~(UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX); | ||
55 | switch (speed) { | ||
56 | case UCC_SPEED_TYPE_SLOW: | ||
57 | guemr |= (UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX); | ||
58 | break; | ||
59 | case UCC_SPEED_TYPE_FAST: | ||
60 | guemr |= (UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX); | ||
61 | break; | ||
62 | default: | ||
63 | return -EINVAL; | ||
64 | } | ||
65 | regs->guemr = guemr; | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | int ucc_init_guemr(struct ucc_common *regs) | ||
71 | { | ||
72 | u8 guemr = 0; | ||
73 | |||
74 | if (!regs) | ||
75 | return -EINVAL; | ||
76 | |||
77 | /* Set bit 3 (which is reserved in the GUEMR register) to 1 */ | ||
78 | guemr = UCC_GUEMR_SET_RESERVED3; | ||
79 | |||
80 | regs->guemr = guemr; | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static void get_cmxucr_reg(int ucc_num, volatile u32 ** p_cmxucr, u8 * reg_num, | ||
86 | u8 * shift) | ||
87 | { | ||
88 | switch (ucc_num) { | ||
89 | case 0: *p_cmxucr = &(qe_immr->qmx.cmxucr1); | ||
90 | *reg_num = 1; | ||
91 | *shift = 16; | ||
92 | break; | ||
93 | case 2: *p_cmxucr = &(qe_immr->qmx.cmxucr1); | ||
94 | *reg_num = 1; | ||
95 | *shift = 0; | ||
96 | break; | ||
97 | case 4: *p_cmxucr = &(qe_immr->qmx.cmxucr2); | ||
98 | *reg_num = 2; | ||
99 | *shift = 16; | ||
100 | break; | ||
101 | case 6: *p_cmxucr = &(qe_immr->qmx.cmxucr2); | ||
102 | *reg_num = 2; | ||
103 | *shift = 0; | ||
104 | break; | ||
105 | case 1: *p_cmxucr = &(qe_immr->qmx.cmxucr3); | ||
106 | *reg_num = 3; | ||
107 | *shift = 16; | ||
108 | break; | ||
109 | case 3: *p_cmxucr = &(qe_immr->qmx.cmxucr3); | ||
110 | *reg_num = 3; | ||
111 | *shift = 0; | ||
112 | break; | ||
113 | case 5: *p_cmxucr = &(qe_immr->qmx.cmxucr4); | ||
114 | *reg_num = 4; | ||
115 | *shift = 16; | ||
116 | break; | ||
117 | case 7: *p_cmxucr = &(qe_immr->qmx.cmxucr4); | ||
118 | *reg_num = 4; | ||
119 | *shift = 0; | ||
120 | break; | ||
121 | default: | ||
122 | break; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask) | ||
127 | { | ||
128 | volatile u32 *p_cmxucr; | ||
129 | u8 reg_num; | ||
130 | u8 shift; | ||
131 | |||
132 | /* check if the UCC number is in range. */ | ||
133 | if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) | ||
134 | return -EINVAL; | ||
135 | |||
136 | get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); | ||
137 | |||
138 | if (set) | ||
139 | out_be32(p_cmxucr, in_be32(p_cmxucr) | (mask << shift)); | ||
140 | else | ||
141 | out_be32(p_cmxucr, in_be32(p_cmxucr) & ~(mask << shift)); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode) | ||
147 | { | ||
148 | volatile u32 *p_cmxucr; | ||
149 | u8 reg_num; | ||
150 | u8 shift; | ||
151 | u32 clock_bits; | ||
152 | u32 clock_mask; | ||
153 | int source = -1; | ||
154 | |||
155 | /* check if the UCC number is in range. */ | ||
156 | if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) | ||
157 | return -EINVAL; | ||
158 | |||
159 | if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) { | ||
160 | printk(KERN_ERR | ||
161 | "ucc_set_qe_mux_rxtx: bad comm mode type passed."); | ||
162 | return -EINVAL; | ||
163 | } | ||
164 | |||
165 | get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); | ||
166 | |||
167 | switch (reg_num) { | ||
168 | case 1: | ||
169 | switch (clock) { | ||
170 | case QE_BRG1: source = 1; break; | ||
171 | case QE_BRG2: source = 2; break; | ||
172 | case QE_BRG7: source = 3; break; | ||
173 | case QE_BRG8: source = 4; break; | ||
174 | case QE_CLK9: source = 5; break; | ||
175 | case QE_CLK10: source = 6; break; | ||
176 | case QE_CLK11: source = 7; break; | ||
177 | case QE_CLK12: source = 8; break; | ||
178 | case QE_CLK15: source = 9; break; | ||
179 | case QE_CLK16: source = 10; break; | ||
180 | default: source = -1; break; | ||
181 | } | ||
182 | break; | ||
183 | case 2: | ||
184 | switch (clock) { | ||
185 | case QE_BRG5: source = 1; break; | ||
186 | case QE_BRG6: source = 2; break; | ||
187 | case QE_BRG7: source = 3; break; | ||
188 | case QE_BRG8: source = 4; break; | ||
189 | case QE_CLK13: source = 5; break; | ||
190 | case QE_CLK14: source = 6; break; | ||
191 | case QE_CLK19: source = 7; break; | ||
192 | case QE_CLK20: source = 8; break; | ||
193 | case QE_CLK15: source = 9; break; | ||
194 | case QE_CLK16: source = 10; break; | ||
195 | default: source = -1; break; | ||
196 | } | ||
197 | break; | ||
198 | case 3: | ||
199 | switch (clock) { | ||
200 | case QE_BRG9: source = 1; break; | ||
201 | case QE_BRG10: source = 2; break; | ||
202 | case QE_BRG15: source = 3; break; | ||
203 | case QE_BRG16: source = 4; break; | ||
204 | case QE_CLK3: source = 5; break; | ||
205 | case QE_CLK4: source = 6; break; | ||
206 | case QE_CLK17: source = 7; break; | ||
207 | case QE_CLK18: source = 8; break; | ||
208 | case QE_CLK7: source = 9; break; | ||
209 | case QE_CLK8: source = 10; break; | ||
210 | default: source = -1; break; | ||
211 | } | ||
212 | break; | ||
213 | case 4: | ||
214 | switch (clock) { | ||
215 | case QE_BRG13: source = 1; break; | ||
216 | case QE_BRG14: source = 2; break; | ||
217 | case QE_BRG15: source = 3; break; | ||
218 | case QE_BRG16: source = 4; break; | ||
219 | case QE_CLK5: source = 5; break; | ||
220 | case QE_CLK6: source = 6; break; | ||
221 | case QE_CLK21: source = 7; break; | ||
222 | case QE_CLK22: source = 8; break; | ||
223 | case QE_CLK7: source = 9; break; | ||
224 | case QE_CLK8: source = 10; break; | ||
225 | default: source = -1; break; | ||
226 | } | ||
227 | break; | ||
228 | default: | ||
229 | source = -1; | ||
230 | break; | ||
231 | } | ||
232 | |||
233 | if (source == -1) { | ||
234 | printk(KERN_ERR | ||
235 | "ucc_set_qe_mux_rxtx: Bad combination of clock and UCC."); | ||
236 | return -ENOENT; | ||
237 | } | ||
238 | |||
239 | clock_bits = (u32) source; | ||
240 | clock_mask = QE_CMXUCR_TX_CLK_SRC_MASK; | ||
241 | if (mode == COMM_DIR_RX) { | ||
242 | clock_bits <<= 4; /* Rx field is 4 bits to left of Tx field */ | ||
243 | clock_mask <<= 4; /* Rx field is 4 bits to left of Tx field */ | ||
244 | } | ||
245 | clock_bits <<= shift; | ||
246 | clock_mask <<= shift; | ||
247 | |||
248 | out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clock_mask) | clock_bits); | ||
249 | |||
250 | return 0; | ||
251 | } | ||
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c new file mode 100644 index 000000000000..c2be7348fcbd --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c | |||
@@ -0,0 +1,396 @@ | |||
1 | /* | ||
2 | * arch/powerpc/sysdev/qe_lib/ucc_fast.c | ||
3 | * | ||
4 | * QE UCC Fast API Set - UCC Fast specific routines implementations. | ||
5 | * | ||
6 | * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. | ||
7 | * | ||
8 | * Authors: Shlomi Gridish <gridish@freescale.com> | ||
9 | * Li Yang <leoli@freescale.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/stddef.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include <asm/immap_qe.h> | ||
25 | #include <asm/qe.h> | ||
26 | |||
27 | #include <asm/ucc.h> | ||
28 | #include <asm/ucc_fast.h> | ||
29 | |||
30 | #define uccf_printk(level, format, arg...) \ | ||
31 | printk(level format "\n", ## arg) | ||
32 | |||
33 | #define uccf_dbg(format, arg...) \ | ||
34 | uccf_printk(KERN_DEBUG , format , ## arg) | ||
35 | #define uccf_err(format, arg...) \ | ||
36 | uccf_printk(KERN_ERR , format , ## arg) | ||
37 | #define uccf_info(format, arg...) \ | ||
38 | uccf_printk(KERN_INFO , format , ## arg) | ||
39 | #define uccf_warn(format, arg...) \ | ||
40 | uccf_printk(KERN_WARNING , format , ## arg) | ||
41 | |||
42 | #ifdef UCCF_VERBOSE_DEBUG | ||
43 | #define uccf_vdbg uccf_dbg | ||
44 | #else | ||
45 | #define uccf_vdbg(fmt, args...) do { } while (0) | ||
46 | #endif /* UCCF_VERBOSE_DEBUG */ | ||
47 | |||
48 | void ucc_fast_dump_regs(struct ucc_fast_private * uccf) | ||
49 | { | ||
50 | uccf_info("UCC%d Fast registers:", uccf->uf_info->ucc_num); | ||
51 | uccf_info("Base address: 0x%08x", (u32) uccf->uf_regs); | ||
52 | |||
53 | uccf_info("gumr : addr - 0x%08x, val - 0x%08x", | ||
54 | (u32) & uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr)); | ||
55 | uccf_info("upsmr : addr - 0x%08x, val - 0x%08x", | ||
56 | (u32) & uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr)); | ||
57 | uccf_info("utodr : addr - 0x%08x, val - 0x%04x", | ||
58 | (u32) & uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr)); | ||
59 | uccf_info("udsr : addr - 0x%08x, val - 0x%04x", | ||
60 | (u32) & uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr)); | ||
61 | uccf_info("ucce : addr - 0x%08x, val - 0x%08x", | ||
62 | (u32) & uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce)); | ||
63 | uccf_info("uccm : addr - 0x%08x, val - 0x%08x", | ||
64 | (u32) & uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm)); | ||
65 | uccf_info("uccs : addr - 0x%08x, val - 0x%02x", | ||
66 | (u32) & uccf->uf_regs->uccs, uccf->uf_regs->uccs); | ||
67 | uccf_info("urfb : addr - 0x%08x, val - 0x%08x", | ||
68 | (u32) & uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb)); | ||
69 | uccf_info("urfs : addr - 0x%08x, val - 0x%04x", | ||
70 | (u32) & uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs)); | ||
71 | uccf_info("urfet : addr - 0x%08x, val - 0x%04x", | ||
72 | (u32) & uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet)); | ||
73 | uccf_info("urfset: addr - 0x%08x, val - 0x%04x", | ||
74 | (u32) & uccf->uf_regs->urfset, | ||
75 | in_be16(&uccf->uf_regs->urfset)); | ||
76 | uccf_info("utfb : addr - 0x%08x, val - 0x%08x", | ||
77 | (u32) & uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb)); | ||
78 | uccf_info("utfs : addr - 0x%08x, val - 0x%04x", | ||
79 | (u32) & uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs)); | ||
80 | uccf_info("utfet : addr - 0x%08x, val - 0x%04x", | ||
81 | (u32) & uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet)); | ||
82 | uccf_info("utftt : addr - 0x%08x, val - 0x%04x", | ||
83 | (u32) & uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt)); | ||
84 | uccf_info("utpt : addr - 0x%08x, val - 0x%04x", | ||
85 | (u32) & uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt)); | ||
86 | uccf_info("urtry : addr - 0x%08x, val - 0x%08x", | ||
87 | (u32) & uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry)); | ||
88 | uccf_info("guemr : addr - 0x%08x, val - 0x%02x", | ||
89 | (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr); | ||
90 | } | ||
91 | |||
92 | u32 ucc_fast_get_qe_cr_subblock(int uccf_num) | ||
93 | { | ||
94 | switch (uccf_num) { | ||
95 | case 0: return QE_CR_SUBBLOCK_UCCFAST1; | ||
96 | case 1: return QE_CR_SUBBLOCK_UCCFAST2; | ||
97 | case 2: return QE_CR_SUBBLOCK_UCCFAST3; | ||
98 | case 3: return QE_CR_SUBBLOCK_UCCFAST4; | ||
99 | case 4: return QE_CR_SUBBLOCK_UCCFAST5; | ||
100 | case 5: return QE_CR_SUBBLOCK_UCCFAST6; | ||
101 | case 6: return QE_CR_SUBBLOCK_UCCFAST7; | ||
102 | case 7: return QE_CR_SUBBLOCK_UCCFAST8; | ||
103 | default: return QE_CR_SUBBLOCK_INVALID; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf) | ||
108 | { | ||
109 | out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD); | ||
110 | } | ||
111 | |||
112 | void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode) | ||
113 | { | ||
114 | struct ucc_fast *uf_regs; | ||
115 | u32 gumr; | ||
116 | |||
117 | uf_regs = uccf->uf_regs; | ||
118 | |||
119 | /* Enable reception and/or transmission on this UCC. */ | ||
120 | gumr = in_be32(&uf_regs->gumr); | ||
121 | if (mode & COMM_DIR_TX) { | ||
122 | gumr |= UCC_FAST_GUMR_ENT; | ||
123 | uccf->enabled_tx = 1; | ||
124 | } | ||
125 | if (mode & COMM_DIR_RX) { | ||
126 | gumr |= UCC_FAST_GUMR_ENR; | ||
127 | uccf->enabled_rx = 1; | ||
128 | } | ||
129 | out_be32(&uf_regs->gumr, gumr); | ||
130 | } | ||
131 | |||
132 | void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode) | ||
133 | { | ||
134 | struct ucc_fast *uf_regs; | ||
135 | u32 gumr; | ||
136 | |||
137 | uf_regs = uccf->uf_regs; | ||
138 | |||
139 | /* Disable reception and/or transmission on this UCC. */ | ||
140 | gumr = in_be32(&uf_regs->gumr); | ||
141 | if (mode & COMM_DIR_TX) { | ||
142 | gumr &= ~UCC_FAST_GUMR_ENT; | ||
143 | uccf->enabled_tx = 0; | ||
144 | } | ||
145 | if (mode & COMM_DIR_RX) { | ||
146 | gumr &= ~UCC_FAST_GUMR_ENR; | ||
147 | uccf->enabled_rx = 0; | ||
148 | } | ||
149 | out_be32(&uf_regs->gumr, gumr); | ||
150 | } | ||
151 | |||
152 | int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret) | ||
153 | { | ||
154 | struct ucc_fast_private *uccf; | ||
155 | struct ucc_fast *uf_regs; | ||
156 | u32 gumr = 0; | ||
157 | int ret; | ||
158 | |||
159 | uccf_vdbg("%s: IN", __FUNCTION__); | ||
160 | |||
161 | if (!uf_info) | ||
162 | return -EINVAL; | ||
163 | |||
164 | /* check if the UCC port number is in range. */ | ||
165 | if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) { | ||
166 | uccf_err("ucc_fast_init: Illagal UCC number!"); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | /* Check that 'max_rx_buf_length' is properly aligned (4). */ | ||
171 | if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) { | ||
172 | uccf_err("ucc_fast_init: max_rx_buf_length not aligned."); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | /* Validate Virtual Fifo register values */ | ||
177 | if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) { | ||
178 | uccf_err | ||
179 | ("ucc_fast_init: Virtual Fifo register urfs too small."); | ||
180 | return -EINVAL; | ||
181 | } | ||
182 | |||
183 | if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { | ||
184 | uccf_err | ||
185 | ("ucc_fast_init: Virtual Fifo register urfs not aligned."); | ||
186 | return -EINVAL; | ||
187 | } | ||
188 | |||
189 | if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { | ||
190 | uccf_err | ||
191 | ("ucc_fast_init: Virtual Fifo register urfet not aligned."); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { | ||
196 | uccf_err | ||
197 | ("ucc_fast_init: Virtual Fifo register urfset not aligned."); | ||
198 | return -EINVAL; | ||
199 | } | ||
200 | |||
201 | if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { | ||
202 | uccf_err | ||
203 | ("ucc_fast_init: Virtual Fifo register utfs not aligned."); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { | ||
208 | uccf_err | ||
209 | ("ucc_fast_init: Virtual Fifo register utfet not aligned."); | ||
210 | return -EINVAL; | ||
211 | } | ||
212 | |||
213 | if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) { | ||
214 | uccf_err | ||
215 | ("ucc_fast_init: Virtual Fifo register utftt not aligned."); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | uccf = (struct ucc_fast_private *) | ||
220 | kmalloc(sizeof(struct ucc_fast_private), GFP_KERNEL); | ||
221 | if (!uccf) { | ||
222 | uccf_err | ||
223 | ("ucc_fast_init: No memory for UCC slow data structure!"); | ||
224 | return -ENOMEM; | ||
225 | } | ||
226 | memset(uccf, 0, sizeof(struct ucc_fast_private)); | ||
227 | |||
228 | /* Fill fast UCC structure */ | ||
229 | uccf->uf_info = uf_info; | ||
230 | /* Set the PHY base address */ | ||
231 | uccf->uf_regs = | ||
232 | (struct ucc_fast *) ioremap(uf_info->regs, sizeof(struct ucc_fast)); | ||
233 | if (uccf->uf_regs == NULL) { | ||
234 | uccf_err | ||
235 | ("ucc_fast_init: No memory map for UCC slow controller!"); | ||
236 | return -ENOMEM; | ||
237 | } | ||
238 | |||
239 | uccf->enabled_tx = 0; | ||
240 | uccf->enabled_rx = 0; | ||
241 | uccf->stopped_tx = 0; | ||
242 | uccf->stopped_rx = 0; | ||
243 | uf_regs = uccf->uf_regs; | ||
244 | uccf->p_ucce = (u32 *) & (uf_regs->ucce); | ||
245 | uccf->p_uccm = (u32 *) & (uf_regs->uccm); | ||
246 | #ifdef STATISTICS | ||
247 | uccf->tx_frames = 0; | ||
248 | uccf->rx_frames = 0; | ||
249 | uccf->rx_discarded = 0; | ||
250 | #endif /* STATISTICS */ | ||
251 | |||
252 | /* Init Guemr register */ | ||
253 | if ((ret = ucc_init_guemr((struct ucc_common *) (uf_regs)))) { | ||
254 | uccf_err("ucc_fast_init: Could not init the guemr register."); | ||
255 | ucc_fast_free(uccf); | ||
256 | return ret; | ||
257 | } | ||
258 | |||
259 | /* Set UCC to fast type */ | ||
260 | if ((ret = ucc_set_type(uf_info->ucc_num, | ||
261 | (struct ucc_common *) (uf_regs), | ||
262 | UCC_SPEED_TYPE_FAST))) { | ||
263 | uccf_err("ucc_fast_init: Could not set type to fast."); | ||
264 | ucc_fast_free(uccf); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | uccf->mrblr = uf_info->max_rx_buf_length; | ||
269 | |||
270 | /* Set GUMR */ | ||
271 | /* For more details see the hardware spec. */ | ||
272 | /* gumr starts as zero. */ | ||
273 | if (uf_info->tci) | ||
274 | gumr |= UCC_FAST_GUMR_TCI; | ||
275 | gumr |= uf_info->ttx_trx; | ||
276 | if (uf_info->cdp) | ||
277 | gumr |= UCC_FAST_GUMR_CDP; | ||
278 | if (uf_info->ctsp) | ||
279 | gumr |= UCC_FAST_GUMR_CTSP; | ||
280 | if (uf_info->cds) | ||
281 | gumr |= UCC_FAST_GUMR_CDS; | ||
282 | if (uf_info->ctss) | ||
283 | gumr |= UCC_FAST_GUMR_CTSS; | ||
284 | if (uf_info->txsy) | ||
285 | gumr |= UCC_FAST_GUMR_TXSY; | ||
286 | if (uf_info->rsyn) | ||
287 | gumr |= UCC_FAST_GUMR_RSYN; | ||
288 | gumr |= uf_info->synl; | ||
289 | if (uf_info->rtsm) | ||
290 | gumr |= UCC_FAST_GUMR_RTSM; | ||
291 | gumr |= uf_info->renc; | ||
292 | if (uf_info->revd) | ||
293 | gumr |= UCC_FAST_GUMR_REVD; | ||
294 | gumr |= uf_info->tenc; | ||
295 | gumr |= uf_info->tcrc; | ||
296 | gumr |= uf_info->mode; | ||
297 | out_be32(&uf_regs->gumr, gumr); | ||
298 | |||
299 | /* Allocate memory for Tx Virtual Fifo */ | ||
300 | uccf->ucc_fast_tx_virtual_fifo_base_offset = | ||
301 | qe_muram_alloc(uf_info->utfs, UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); | ||
302 | if (IS_MURAM_ERR(uccf->ucc_fast_tx_virtual_fifo_base_offset)) { | ||
303 | uccf_err | ||
304 | ("ucc_fast_init: Can not allocate MURAM memory for " | ||
305 | "struct ucc_fastx_virtual_fifo_base_offset."); | ||
306 | uccf->ucc_fast_tx_virtual_fifo_base_offset = 0; | ||
307 | ucc_fast_free(uccf); | ||
308 | return -ENOMEM; | ||
309 | } | ||
310 | |||
311 | /* Allocate memory for Rx Virtual Fifo */ | ||
312 | uccf->ucc_fast_rx_virtual_fifo_base_offset = | ||
313 | qe_muram_alloc(uf_info->urfs + | ||
314 | (u32) | ||
315 | UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR, | ||
316 | UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); | ||
317 | if (IS_MURAM_ERR(uccf->ucc_fast_rx_virtual_fifo_base_offset)) { | ||
318 | uccf_err | ||
319 | ("ucc_fast_init: Can not allocate MURAM memory for " | ||
320 | "ucc_fast_rx_virtual_fifo_base_offset."); | ||
321 | uccf->ucc_fast_rx_virtual_fifo_base_offset = 0; | ||
322 | ucc_fast_free(uccf); | ||
323 | return -ENOMEM; | ||
324 | } | ||
325 | |||
326 | /* Set Virtual Fifo registers */ | ||
327 | out_be16(&uf_regs->urfs, uf_info->urfs); | ||
328 | out_be16(&uf_regs->urfet, uf_info->urfet); | ||
329 | out_be16(&uf_regs->urfset, uf_info->urfset); | ||
330 | out_be16(&uf_regs->utfs, uf_info->utfs); | ||
331 | out_be16(&uf_regs->utfet, uf_info->utfet); | ||
332 | out_be16(&uf_regs->utftt, uf_info->utftt); | ||
333 | /* utfb, urfb are offsets from MURAM base */ | ||
334 | out_be32(&uf_regs->utfb, uccf->ucc_fast_tx_virtual_fifo_base_offset); | ||
335 | out_be32(&uf_regs->urfb, uccf->ucc_fast_rx_virtual_fifo_base_offset); | ||
336 | |||
337 | /* Mux clocking */ | ||
338 | /* Grant Support */ | ||
339 | ucc_set_qe_mux_grant(uf_info->ucc_num, uf_info->grant_support); | ||
340 | /* Breakpoint Support */ | ||
341 | ucc_set_qe_mux_bkpt(uf_info->ucc_num, uf_info->brkpt_support); | ||
342 | /* Set Tsa or NMSI mode. */ | ||
343 | ucc_set_qe_mux_tsa(uf_info->ucc_num, uf_info->tsa); | ||
344 | /* If NMSI (not Tsa), set Tx and Rx clock. */ | ||
345 | if (!uf_info->tsa) { | ||
346 | /* Rx clock routing */ | ||
347 | if (uf_info->rx_clock != QE_CLK_NONE) { | ||
348 | if (ucc_set_qe_mux_rxtx | ||
349 | (uf_info->ucc_num, uf_info->rx_clock, | ||
350 | COMM_DIR_RX)) { | ||
351 | uccf_err | ||
352 | ("ucc_fast_init: Illegal value for parameter 'RxClock'."); | ||
353 | ucc_fast_free(uccf); | ||
354 | return -EINVAL; | ||
355 | } | ||
356 | } | ||
357 | /* Tx clock routing */ | ||
358 | if (uf_info->tx_clock != QE_CLK_NONE) { | ||
359 | if (ucc_set_qe_mux_rxtx | ||
360 | (uf_info->ucc_num, uf_info->tx_clock, | ||
361 | COMM_DIR_TX)) { | ||
362 | uccf_err | ||
363 | ("ucc_fast_init: Illegal value for parameter 'TxClock'."); | ||
364 | ucc_fast_free(uccf); | ||
365 | return -EINVAL; | ||
366 | } | ||
367 | } | ||
368 | } | ||
369 | |||
370 | /* Set interrupt mask register at UCC level. */ | ||
371 | out_be32(&uf_regs->uccm, uf_info->uccm_mask); | ||
372 | |||
373 | /* First, clear anything pending at UCC level, | ||
374 | * otherwise, old garbage may come through | ||
375 | * as soon as the dam is opened | ||
376 | * Writing '1' clears | ||
377 | */ | ||
378 | out_be32(&uf_regs->ucce, 0xffffffff); | ||
379 | |||
380 | *uccf_ret = uccf; | ||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | void ucc_fast_free(struct ucc_fast_private * uccf) | ||
385 | { | ||
386 | if (!uccf) | ||
387 | return; | ||
388 | |||
389 | if (uccf->ucc_fast_tx_virtual_fifo_base_offset) | ||
390 | qe_muram_free(uccf->ucc_fast_tx_virtual_fifo_base_offset); | ||
391 | |||
392 | if (uccf->ucc_fast_rx_virtual_fifo_base_offset) | ||
393 | qe_muram_free(uccf->ucc_fast_rx_virtual_fifo_base_offset); | ||
394 | |||
395 | kfree(uccf); | ||
396 | } | ||
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c new file mode 100644 index 000000000000..1fb88ef7cf06 --- /dev/null +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved. | ||
3 | * | ||
4 | * Authors: Shlomi Gridish <gridish@freescale.com> | ||
5 | * Li Yang <leoli@freescale.com> | ||
6 | * | ||
7 | * Description: | ||
8 | * QE UCC Slow API Set - UCC Slow specific routines implementations. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/errno.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/stddef.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | |||
22 | #include <asm/irq.h> | ||
23 | #include <asm/io.h> | ||
24 | #include <asm/immap_qe.h> | ||
25 | #include <asm/qe.h> | ||
26 | |||
27 | #include <asm/ucc.h> | ||
28 | #include <asm/ucc_slow.h> | ||
29 | |||
30 | #define uccs_printk(level, format, arg...) \ | ||
31 | printk(level format "\n", ## arg) | ||
32 | |||
33 | #define uccs_dbg(format, arg...) \ | ||
34 | uccs_printk(KERN_DEBUG , format , ## arg) | ||
35 | #define uccs_err(format, arg...) \ | ||
36 | uccs_printk(KERN_ERR , format , ## arg) | ||
37 | #define uccs_info(format, arg...) \ | ||
38 | uccs_printk(KERN_INFO , format , ## arg) | ||
39 | #define uccs_warn(format, arg...) \ | ||
40 | uccs_printk(KERN_WARNING , format , ## arg) | ||
41 | |||
42 | #ifdef UCCS_VERBOSE_DEBUG | ||
43 | #define uccs_vdbg uccs_dbg | ||
44 | #else | ||
45 | #define uccs_vdbg(fmt, args...) do { } while (0) | ||
46 | #endif /* UCCS_VERBOSE_DEBUG */ | ||
47 | |||
48 | u32 ucc_slow_get_qe_cr_subblock(int uccs_num) | ||
49 | { | ||
50 | switch (uccs_num) { | ||
51 | case 0: return QE_CR_SUBBLOCK_UCCSLOW1; | ||
52 | case 1: return QE_CR_SUBBLOCK_UCCSLOW2; | ||
53 | case 2: return QE_CR_SUBBLOCK_UCCSLOW3; | ||
54 | case 3: return QE_CR_SUBBLOCK_UCCSLOW4; | ||
55 | case 4: return QE_CR_SUBBLOCK_UCCSLOW5; | ||
56 | case 5: return QE_CR_SUBBLOCK_UCCSLOW6; | ||
57 | case 6: return QE_CR_SUBBLOCK_UCCSLOW7; | ||
58 | case 7: return QE_CR_SUBBLOCK_UCCSLOW8; | ||
59 | default: return QE_CR_SUBBLOCK_INVALID; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs) | ||
64 | { | ||
65 | out_be16(&uccs->us_regs->utodr, UCC_SLOW_TOD); | ||
66 | } | ||
67 | |||
68 | void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs) | ||
69 | { | ||
70 | struct ucc_slow_info *us_info = uccs->us_info; | ||
71 | u32 id; | ||
72 | |||
73 | id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); | ||
74 | qe_issue_cmd(QE_GRACEFUL_STOP_TX, id, | ||
75 | QE_CR_PROTOCOL_UNSPECIFIED, 0); | ||
76 | } | ||
77 | |||
78 | void ucc_slow_stop_tx(struct ucc_slow_private * uccs) | ||
79 | { | ||
80 | struct ucc_slow_info *us_info = uccs->us_info; | ||
81 | u32 id; | ||
82 | |||
83 | id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); | ||
84 | qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); | ||
85 | } | ||
86 | |||
87 | void ucc_slow_restart_tx(struct ucc_slow_private * uccs) | ||
88 | { | ||
89 | struct ucc_slow_info *us_info = uccs->us_info; | ||
90 | u32 id; | ||
91 | |||
92 | id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); | ||
93 | qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); | ||
94 | } | ||
95 | |||
96 | void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) | ||
97 | { | ||
98 | struct ucc_slow *us_regs; | ||
99 | u32 gumr_l; | ||
100 | |||
101 | us_regs = uccs->us_regs; | ||
102 | |||
103 | /* Enable reception and/or transmission on this UCC. */ | ||
104 | gumr_l = in_be32(&us_regs->gumr_l); | ||
105 | if (mode & COMM_DIR_TX) { | ||
106 | gumr_l |= UCC_SLOW_GUMR_L_ENT; | ||
107 | uccs->enabled_tx = 1; | ||
108 | } | ||
109 | if (mode & COMM_DIR_RX) { | ||
110 | gumr_l |= UCC_SLOW_GUMR_L_ENR; | ||
111 | uccs->enabled_rx = 1; | ||
112 | } | ||
113 | out_be32(&us_regs->gumr_l, gumr_l); | ||
114 | } | ||
115 | |||
116 | void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) | ||
117 | { | ||
118 | struct ucc_slow *us_regs; | ||
119 | u32 gumr_l; | ||
120 | |||
121 | us_regs = uccs->us_regs; | ||
122 | |||
123 | /* Disable reception and/or transmission on this UCC. */ | ||
124 | gumr_l = in_be32(&us_regs->gumr_l); | ||
125 | if (mode & COMM_DIR_TX) { | ||
126 | gumr_l &= ~UCC_SLOW_GUMR_L_ENT; | ||
127 | uccs->enabled_tx = 0; | ||
128 | } | ||
129 | if (mode & COMM_DIR_RX) { | ||
130 | gumr_l &= ~UCC_SLOW_GUMR_L_ENR; | ||
131 | uccs->enabled_rx = 0; | ||
132 | } | ||
133 | out_be32(&us_regs->gumr_l, gumr_l); | ||
134 | } | ||
135 | |||
136 | int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret) | ||
137 | { | ||
138 | u32 i; | ||
139 | struct ucc_slow *us_regs; | ||
140 | u32 gumr; | ||
141 | u8 function_code = 0; | ||
142 | u8 *bd; | ||
143 | struct ucc_slow_private *uccs; | ||
144 | u32 id; | ||
145 | u32 command; | ||
146 | int ret; | ||
147 | |||
148 | uccs_vdbg("%s: IN", __FUNCTION__); | ||
149 | |||
150 | if (!us_info) | ||
151 | return -EINVAL; | ||
152 | |||
153 | /* check if the UCC port number is in range. */ | ||
154 | if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) { | ||
155 | uccs_err("ucc_slow_init: Illagal UCC number!"); | ||
156 | return -EINVAL; | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * Set mrblr | ||
161 | * Check that 'max_rx_buf_length' is properly aligned (4), unless | ||
162 | * rfw is 1, meaning that QE accepts one byte at a time, unlike normal | ||
163 | * case when QE accepts 32 bits at a time. | ||
164 | */ | ||
165 | if ((!us_info->rfw) && | ||
166 | (us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) { | ||
167 | uccs_err("max_rx_buf_length not aligned."); | ||
168 | return -EINVAL; | ||
169 | } | ||
170 | |||
171 | uccs = (struct ucc_slow_private *) | ||
172 | kmalloc(sizeof(struct ucc_slow_private), GFP_KERNEL); | ||
173 | if (!uccs) { | ||
174 | uccs_err | ||
175 | ("ucc_slow_init: No memory for UCC slow data structure!"); | ||
176 | return -ENOMEM; | ||
177 | } | ||
178 | memset(uccs, 0, sizeof(struct ucc_slow_private)); | ||
179 | |||
180 | /* Fill slow UCC structure */ | ||
181 | uccs->us_info = us_info; | ||
182 | uccs->saved_uccm = 0; | ||
183 | uccs->p_rx_frame = 0; | ||
184 | uccs->us_regs = us_info->us_regs; | ||
185 | us_regs = uccs->us_regs; | ||
186 | uccs->p_ucce = (u16 *) & (us_regs->ucce); | ||
187 | uccs->p_uccm = (u16 *) & (us_regs->uccm); | ||
188 | #ifdef STATISTICS | ||
189 | uccs->rx_frames = 0; | ||
190 | uccs->tx_frames = 0; | ||
191 | uccs->rx_discarded = 0; | ||
192 | #endif /* STATISTICS */ | ||
193 | |||
194 | /* Get PRAM base */ | ||
195 | uccs->us_pram_offset = qe_muram_alloc(UCC_SLOW_PRAM_SIZE, | ||
196 | ALIGNMENT_OF_UCC_SLOW_PRAM); | ||
197 | if (IS_MURAM_ERR(uccs->us_pram_offset)) { | ||
198 | uccs_err | ||
199 | ("ucc_slow_init: Can not allocate MURAM memory " | ||
200 | "for Slow UCC."); | ||
201 | ucc_slow_free(uccs); | ||
202 | return -ENOMEM; | ||
203 | } | ||
204 | id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); | ||
205 | qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, QE_CR_PROTOCOL_UNSPECIFIED, | ||
206 | (u32) uccs->us_pram_offset); | ||
207 | |||
208 | uccs->us_pram = qe_muram_addr(uccs->us_pram_offset); | ||
209 | |||
210 | /* Init Guemr register */ | ||
211 | if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->us_regs)))) { | ||
212 | uccs_err("ucc_slow_init: Could not init the guemr register."); | ||
213 | ucc_slow_free(uccs); | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | /* Set UCC to slow type */ | ||
218 | if ((ret = ucc_set_type(us_info->ucc_num, | ||
219 | (struct ucc_common *) (us_info->us_regs), | ||
220 | UCC_SPEED_TYPE_SLOW))) { | ||
221 | uccs_err("ucc_slow_init: Could not init the guemr register."); | ||
222 | ucc_slow_free(uccs); | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | out_be16(&uccs->us_pram->mrblr, us_info->max_rx_buf_length); | ||
227 | |||
228 | INIT_LIST_HEAD(&uccs->confQ); | ||
229 | |||
230 | /* Allocate BDs. */ | ||
231 | uccs->rx_base_offset = | ||
232 | qe_muram_alloc(us_info->rx_bd_ring_len * sizeof(struct qe_bd), | ||
233 | QE_ALIGNMENT_OF_BD); | ||
234 | if (IS_MURAM_ERR(uccs->rx_base_offset)) { | ||
235 | uccs_err("ucc_slow_init: No memory for Rx BD's."); | ||
236 | uccs->rx_base_offset = 0; | ||
237 | ucc_slow_free(uccs); | ||
238 | return -ENOMEM; | ||
239 | } | ||
240 | |||
241 | uccs->tx_base_offset = | ||
242 | qe_muram_alloc(us_info->tx_bd_ring_len * sizeof(struct qe_bd), | ||
243 | QE_ALIGNMENT_OF_BD); | ||
244 | if (IS_MURAM_ERR(uccs->tx_base_offset)) { | ||
245 | uccs_err("ucc_slow_init: No memory for Tx BD's."); | ||
246 | uccs->tx_base_offset = 0; | ||
247 | ucc_slow_free(uccs); | ||
248 | return -ENOMEM; | ||
249 | } | ||
250 | |||
251 | /* Init Tx bds */ | ||
252 | bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset); | ||
253 | for (i = 0; i < us_info->tx_bd_ring_len; i++) { | ||
254 | /* clear bd buffer */ | ||
255 | out_be32(&(((struct qe_bd *)bd)->buf), 0); | ||
256 | /* set bd status and length */ | ||
257 | out_be32((u32*)bd, 0); | ||
258 | bd += sizeof(struct qe_bd); | ||
259 | } | ||
260 | bd -= sizeof(struct qe_bd); | ||
261 | /* set bd status and length */ | ||
262 | out_be32((u32*)bd, T_W); /* for last BD set Wrap bit */ | ||
263 | |||
264 | /* Init Rx bds */ | ||
265 | bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset); | ||
266 | for (i = 0; i < us_info->rx_bd_ring_len; i++) { | ||
267 | /* set bd status and length */ | ||
268 | out_be32((u32*)bd, 0); | ||
269 | /* clear bd buffer */ | ||
270 | out_be32(&(((struct qe_bd *)bd)->buf), 0); | ||
271 | bd += sizeof(struct qe_bd); | ||
272 | } | ||
273 | bd -= sizeof(struct qe_bd); | ||
274 | /* set bd status and length */ | ||
275 | out_be32((u32*)bd, R_W); /* for last BD set Wrap bit */ | ||
276 | |||
277 | /* Set GUMR (For more details see the hardware spec.). */ | ||
278 | /* gumr_h */ | ||
279 | gumr = 0; | ||
280 | gumr |= us_info->tcrc; | ||
281 | if (us_info->cdp) | ||
282 | gumr |= UCC_SLOW_GUMR_H_CDP; | ||
283 | if (us_info->ctsp) | ||
284 | gumr |= UCC_SLOW_GUMR_H_CTSP; | ||
285 | if (us_info->cds) | ||
286 | gumr |= UCC_SLOW_GUMR_H_CDS; | ||
287 | if (us_info->ctss) | ||
288 | gumr |= UCC_SLOW_GUMR_H_CTSS; | ||
289 | if (us_info->tfl) | ||
290 | gumr |= UCC_SLOW_GUMR_H_TFL; | ||
291 | if (us_info->rfw) | ||
292 | gumr |= UCC_SLOW_GUMR_H_RFW; | ||
293 | if (us_info->txsy) | ||
294 | gumr |= UCC_SLOW_GUMR_H_TXSY; | ||
295 | if (us_info->rtsm) | ||
296 | gumr |= UCC_SLOW_GUMR_H_RTSM; | ||
297 | out_be32(&us_regs->gumr_h, gumr); | ||
298 | |||
299 | /* gumr_l */ | ||
300 | gumr = 0; | ||
301 | if (us_info->tci) | ||
302 | gumr |= UCC_SLOW_GUMR_L_TCI; | ||
303 | if (us_info->rinv) | ||
304 | gumr |= UCC_SLOW_GUMR_L_RINV; | ||
305 | if (us_info->tinv) | ||
306 | gumr |= UCC_SLOW_GUMR_L_TINV; | ||
307 | if (us_info->tend) | ||
308 | gumr |= UCC_SLOW_GUMR_L_TEND; | ||
309 | gumr |= us_info->tdcr; | ||
310 | gumr |= us_info->rdcr; | ||
311 | gumr |= us_info->tenc; | ||
312 | gumr |= us_info->renc; | ||
313 | gumr |= us_info->diag; | ||
314 | gumr |= us_info->mode; | ||
315 | out_be32(&us_regs->gumr_l, gumr); | ||
316 | |||
317 | /* Function code registers */ | ||
318 | /* function_code has initial value 0 */ | ||
319 | |||
320 | /* if the data is in cachable memory, the 'global' */ | ||
321 | /* in the function code should be set. */ | ||
322 | function_code |= us_info->data_mem_part; | ||
323 | function_code |= QE_BMR_BYTE_ORDER_BO_MOT; /* Required for QE */ | ||
324 | uccs->us_pram->tfcr = function_code; | ||
325 | uccs->us_pram->rfcr = function_code; | ||
326 | |||
327 | /* rbase, tbase are offsets from MURAM base */ | ||
328 | out_be16(&uccs->us_pram->rbase, uccs->us_pram_offset); | ||
329 | out_be16(&uccs->us_pram->tbase, uccs->us_pram_offset); | ||
330 | |||
331 | /* Mux clocking */ | ||
332 | /* Grant Support */ | ||
333 | ucc_set_qe_mux_grant(us_info->ucc_num, us_info->grant_support); | ||
334 | /* Breakpoint Support */ | ||
335 | ucc_set_qe_mux_bkpt(us_info->ucc_num, us_info->brkpt_support); | ||
336 | /* Set Tsa or NMSI mode. */ | ||
337 | ucc_set_qe_mux_tsa(us_info->ucc_num, us_info->tsa); | ||
338 | /* If NMSI (not Tsa), set Tx and Rx clock. */ | ||
339 | if (!us_info->tsa) { | ||
340 | /* Rx clock routing */ | ||
341 | if (ucc_set_qe_mux_rxtx | ||
342 | (us_info->ucc_num, us_info->rx_clock, COMM_DIR_RX)) { | ||
343 | uccs_err | ||
344 | ("ucc_slow_init: Illegal value for parameter" | ||
345 | " 'RxClock'."); | ||
346 | ucc_slow_free(uccs); | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | /* Tx clock routing */ | ||
350 | if (ucc_set_qe_mux_rxtx(us_info->ucc_num, | ||
351 | us_info->tx_clock, COMM_DIR_TX)) { | ||
352 | uccs_err | ||
353 | ("ucc_slow_init: Illegal value for parameter " | ||
354 | "'TxClock'."); | ||
355 | ucc_slow_free(uccs); | ||
356 | return -EINVAL; | ||
357 | } | ||
358 | } | ||
359 | |||
360 | /* | ||
361 | * INTERRUPTS | ||
362 | */ | ||
363 | /* Set interrupt mask register at UCC level. */ | ||
364 | out_be16(&us_regs->uccm, us_info->uccm_mask); | ||
365 | |||
366 | /* First, clear anything pending at UCC level, */ | ||
367 | /* otherwise, old garbage may come through */ | ||
368 | /* as soon as the dam is opened. */ | ||
369 | |||
370 | /* Writing '1' clears */ | ||
371 | out_be16(&us_regs->ucce, 0xffff); | ||
372 | |||
373 | /* Issue QE Init command */ | ||
374 | if (us_info->init_tx && us_info->init_rx) | ||
375 | command = QE_INIT_TX_RX; | ||
376 | else if (us_info->init_tx) | ||
377 | command = QE_INIT_TX; | ||
378 | else | ||
379 | command = QE_INIT_RX; /* We know at least one is TRUE */ | ||
380 | id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); | ||
381 | qe_issue_cmd(command, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); | ||
382 | |||
383 | *uccs_ret = uccs; | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | void ucc_slow_free(struct ucc_slow_private * uccs) | ||
388 | { | ||
389 | if (!uccs) | ||
390 | return; | ||
391 | |||
392 | if (uccs->rx_base_offset) | ||
393 | qe_muram_free(uccs->rx_base_offset); | ||
394 | |||
395 | if (uccs->tx_base_offset) | ||
396 | qe_muram_free(uccs->tx_base_offset); | ||
397 | |||
398 | if (uccs->us_pram) { | ||
399 | qe_muram_free(uccs->us_pram_offset); | ||
400 | uccs->us_pram = NULL; | ||
401 | } | ||
402 | |||
403 | kfree(uccs); | ||
404 | } | ||
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index 8adad1444a51..708236f34746 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c | |||
@@ -2,6 +2,8 @@ | |||
2 | * Routines providing a simple monitor for use on the PowerMac. | 2 | * Routines providing a simple monitor for use on the PowerMac. |
3 | * | 3 | * |
4 | * Copyright (C) 1996-2005 Paul Mackerras. | 4 | * Copyright (C) 1996-2005 Paul Mackerras. |
5 | * Copyright (C) 2001 PPC64 Team, IBM Corp | ||
6 | * Copyrignt (C) 2006 Michael Ellerman, IBM Corp | ||
5 | * | 7 | * |
6 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License | 9 | * modify it under the terms of the GNU General Public License |
@@ -503,7 +505,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi) | |||
503 | 505 | ||
504 | mtmsr(msr); /* restore interrupt enable */ | 506 | mtmsr(msr); /* restore interrupt enable */ |
505 | 507 | ||
506 | return cmd != 'X'; | 508 | return cmd != 'X' && cmd != EOF; |
507 | } | 509 | } |
508 | 510 | ||
509 | int xmon(struct pt_regs *excp) | 511 | int xmon(struct pt_regs *excp) |
@@ -2597,3 +2599,34 @@ static int __init setup_xmon_sysrq(void) | |||
2597 | } | 2599 | } |
2598 | __initcall(setup_xmon_sysrq); | 2600 | __initcall(setup_xmon_sysrq); |
2599 | #endif /* CONFIG_MAGIC_SYSRQ */ | 2601 | #endif /* CONFIG_MAGIC_SYSRQ */ |
2602 | |||
2603 | int __initdata xmon_early, xmon_off; | ||
2604 | |||
2605 | static int __init early_parse_xmon(char *p) | ||
2606 | { | ||
2607 | if (!p || strncmp(p, "early", 5) == 0) { | ||
2608 | /* just "xmon" is equivalent to "xmon=early" */ | ||
2609 | xmon_init(1); | ||
2610 | xmon_early = 1; | ||
2611 | } else if (strncmp(p, "on", 2) == 0) | ||
2612 | xmon_init(1); | ||
2613 | else if (strncmp(p, "off", 3) == 0) | ||
2614 | xmon_off = 1; | ||
2615 | else if (strncmp(p, "nobt", 4) == 0) | ||
2616 | xmon_no_auto_backtrace = 1; | ||
2617 | else | ||
2618 | return 1; | ||
2619 | |||
2620 | return 0; | ||
2621 | } | ||
2622 | early_param("xmon", early_parse_xmon); | ||
2623 | |||
2624 | void __init xmon_setup(void) | ||
2625 | { | ||
2626 | #ifdef CONFIG_XMON_DEFAULT | ||
2627 | if (!xmon_off) | ||
2628 | xmon_init(1); | ||
2629 | #endif | ||
2630 | if (xmon_early) | ||
2631 | debugger(NULL); | ||
2632 | } | ||
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c index 2dd51f364ea2..0612a33bb896 100644 --- a/arch/x86_64/kernel/i8259.c +++ b/arch/x86_64/kernel/i8259.c | |||
@@ -43,17 +43,10 @@ | |||
43 | BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ | 43 | BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ |
44 | BI(x,c) BI(x,d) BI(x,e) BI(x,f) | 44 | BI(x,c) BI(x,d) BI(x,e) BI(x,f) |
45 | 45 | ||
46 | #define BUILD_15_IRQS(x) \ | ||
47 | BI(x,0) BI(x,1) BI(x,2) BI(x,3) \ | ||
48 | BI(x,4) BI(x,5) BI(x,6) BI(x,7) \ | ||
49 | BI(x,8) BI(x,9) BI(x,a) BI(x,b) \ | ||
50 | BI(x,c) BI(x,d) BI(x,e) | ||
51 | |||
52 | /* | 46 | /* |
53 | * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: | 47 | * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts: |
54 | * (these are usually mapped to vectors 0x20-0x2f) | 48 | * (these are usually mapped to vectors 0x20-0x2f) |
55 | */ | 49 | */ |
56 | BUILD_16_IRQS(0x0) | ||
57 | 50 | ||
58 | /* | 51 | /* |
59 | * The IO-APIC gives us many more interrupt sources. Most of these | 52 | * The IO-APIC gives us many more interrupt sources. Most of these |
@@ -65,17 +58,12 @@ BUILD_16_IRQS(0x0) | |||
65 | * | 58 | * |
66 | * (these are usually mapped into the 0x30-0xff vector range) | 59 | * (these are usually mapped into the 0x30-0xff vector range) |
67 | */ | 60 | */ |
68 | BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) | 61 | BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3) |
69 | BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) | 62 | BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7) |
70 | BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) | 63 | BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb) |
71 | BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) | 64 | BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf) |
72 | |||
73 | #ifdef CONFIG_PCI_MSI | ||
74 | BUILD_15_IRQS(0xe) | ||
75 | #endif | ||
76 | 65 | ||
77 | #undef BUILD_16_IRQS | 66 | #undef BUILD_16_IRQS |
78 | #undef BUILD_15_IRQS | ||
79 | #undef BI | 67 | #undef BI |
80 | 68 | ||
81 | 69 | ||
@@ -88,29 +76,15 @@ BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) | |||
88 | IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ | 76 | IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ |
89 | IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) | 77 | IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f) |
90 | 78 | ||
91 | #define IRQLIST_15(x) \ | ||
92 | IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \ | ||
93 | IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \ | ||
94 | IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \ | ||
95 | IRQ(x,c), IRQ(x,d), IRQ(x,e) | ||
96 | |||
97 | void (*interrupt[NR_IRQS])(void) = { | 79 | void (*interrupt[NR_IRQS])(void) = { |
98 | IRQLIST_16(0x0), | 80 | IRQLIST_16(0x2), IRQLIST_16(0x3), |
99 | |||
100 | IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3), | ||
101 | IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7), | 81 | IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7), |
102 | IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb), | 82 | IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb), |
103 | IRQLIST_16(0xc), IRQLIST_16(0xd) | 83 | IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf) |
104 | |||
105 | #ifdef CONFIG_PCI_MSI | ||
106 | , IRQLIST_15(0xe) | ||
107 | #endif | ||
108 | |||
109 | }; | 84 | }; |
110 | 85 | ||
111 | #undef IRQ | 86 | #undef IRQ |
112 | #undef IRQLIST_16 | 87 | #undef IRQLIST_16 |
113 | #undef IRQLIST_14 | ||
114 | 88 | ||
115 | /* | 89 | /* |
116 | * This is the 'legacy' 8259A Programmable Interrupt Controller, | 90 | * This is the 'legacy' 8259A Programmable Interrupt Controller, |
@@ -121,42 +95,15 @@ void (*interrupt[NR_IRQS])(void) = { | |||
121 | * moves to arch independent land | 95 | * moves to arch independent land |
122 | */ | 96 | */ |
123 | 97 | ||
124 | DEFINE_SPINLOCK(i8259A_lock); | ||
125 | |||
126 | static int i8259A_auto_eoi; | 98 | static int i8259A_auto_eoi; |
127 | 99 | DEFINE_SPINLOCK(i8259A_lock); | |
128 | static void end_8259A_irq (unsigned int irq) | ||
129 | { | ||
130 | if (irq > 256) { | ||
131 | char var; | ||
132 | printk("return %p stack %p ti %p\n", __builtin_return_address(0), &var, task_thread_info(current)); | ||
133 | |||
134 | BUG(); | ||
135 | } | ||
136 | |||
137 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) && | ||
138 | irq_desc[irq].action) | ||
139 | enable_8259A_irq(irq); | ||
140 | } | ||
141 | |||
142 | #define shutdown_8259A_irq disable_8259A_irq | ||
143 | |||
144 | static void mask_and_ack_8259A(unsigned int); | 100 | static void mask_and_ack_8259A(unsigned int); |
145 | 101 | ||
146 | static unsigned int startup_8259A_irq(unsigned int irq) | 102 | static struct irq_chip i8259A_chip = { |
147 | { | 103 | .name = "XT-PIC", |
148 | enable_8259A_irq(irq); | 104 | .mask = disable_8259A_irq, |
149 | return 0; /* never anything pending */ | 105 | .unmask = enable_8259A_irq, |
150 | } | 106 | .mask_ack = mask_and_ack_8259A, |
151 | |||
152 | static struct hw_interrupt_type i8259A_irq_type = { | ||
153 | .typename = "XT-PIC", | ||
154 | .startup = startup_8259A_irq, | ||
155 | .shutdown = shutdown_8259A_irq, | ||
156 | .enable = enable_8259A_irq, | ||
157 | .disable = disable_8259A_irq, | ||
158 | .ack = mask_and_ack_8259A, | ||
159 | .end = end_8259A_irq, | ||
160 | }; | 107 | }; |
161 | 108 | ||
162 | /* | 109 | /* |
@@ -231,7 +178,7 @@ void make_8259A_irq(unsigned int irq) | |||
231 | { | 178 | { |
232 | disable_irq_nosync(irq); | 179 | disable_irq_nosync(irq); |
233 | io_apic_irqs &= ~(1<<irq); | 180 | io_apic_irqs &= ~(1<<irq); |
234 | irq_desc[irq].chip = &i8259A_irq_type; | 181 | set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq); |
235 | enable_irq(irq); | 182 | enable_irq(irq); |
236 | } | 183 | } |
237 | 184 | ||
@@ -367,9 +314,9 @@ void init_8259A(int auto_eoi) | |||
367 | * in AEOI mode we just have to mask the interrupt | 314 | * in AEOI mode we just have to mask the interrupt |
368 | * when acking. | 315 | * when acking. |
369 | */ | 316 | */ |
370 | i8259A_irq_type.ack = disable_8259A_irq; | 317 | i8259A_chip.mask_ack = disable_8259A_irq; |
371 | else | 318 | else |
372 | i8259A_irq_type.ack = mask_and_ack_8259A; | 319 | i8259A_chip.mask_ack = mask_and_ack_8259A; |
373 | 320 | ||
374 | udelay(100); /* wait for 8259A to initialize */ | 321 | udelay(100); /* wait for 8259A to initialize */ |
375 | 322 | ||
@@ -447,6 +394,26 @@ device_initcall(i8259A_init_sysfs); | |||
447 | */ | 394 | */ |
448 | 395 | ||
449 | static struct irqaction irq2 = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL}; | 396 | static struct irqaction irq2 = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL}; |
397 | DEFINE_PER_CPU(vector_irq_t, vector_irq) = { | ||
398 | [0 ... FIRST_EXTERNAL_VECTOR - 1] = -1, | ||
399 | [FIRST_EXTERNAL_VECTOR + 0] = 0, | ||
400 | [FIRST_EXTERNAL_VECTOR + 1] = 1, | ||
401 | [FIRST_EXTERNAL_VECTOR + 2] = 2, | ||
402 | [FIRST_EXTERNAL_VECTOR + 3] = 3, | ||
403 | [FIRST_EXTERNAL_VECTOR + 4] = 4, | ||
404 | [FIRST_EXTERNAL_VECTOR + 5] = 5, | ||
405 | [FIRST_EXTERNAL_VECTOR + 6] = 6, | ||
406 | [FIRST_EXTERNAL_VECTOR + 7] = 7, | ||
407 | [FIRST_EXTERNAL_VECTOR + 8] = 8, | ||
408 | [FIRST_EXTERNAL_VECTOR + 9] = 9, | ||
409 | [FIRST_EXTERNAL_VECTOR + 10] = 10, | ||
410 | [FIRST_EXTERNAL_VECTOR + 11] = 11, | ||
411 | [FIRST_EXTERNAL_VECTOR + 12] = 12, | ||
412 | [FIRST_EXTERNAL_VECTOR + 13] = 13, | ||
413 | [FIRST_EXTERNAL_VECTOR + 14] = 14, | ||
414 | [FIRST_EXTERNAL_VECTOR + 15] = 15, | ||
415 | [FIRST_EXTERNAL_VECTOR + 16 ... NR_VECTORS - 1] = -1 | ||
416 | }; | ||
450 | 417 | ||
451 | void __init init_ISA_irqs (void) | 418 | void __init init_ISA_irqs (void) |
452 | { | 419 | { |
@@ -464,12 +431,13 @@ void __init init_ISA_irqs (void) | |||
464 | /* | 431 | /* |
465 | * 16 old-style INTA-cycle interrupts: | 432 | * 16 old-style INTA-cycle interrupts: |
466 | */ | 433 | */ |
467 | irq_desc[i].chip = &i8259A_irq_type; | 434 | set_irq_chip_and_handler(i, &i8259A_chip, |
435 | handle_level_irq); | ||
468 | } else { | 436 | } else { |
469 | /* | 437 | /* |
470 | * 'high' PCI IRQs filled in on demand | 438 | * 'high' PCI IRQs filled in on demand |
471 | */ | 439 | */ |
472 | irq_desc[i].chip = &no_irq_type; | 440 | irq_desc[i].chip = &no_irq_chip; |
473 | } | 441 | } |
474 | } | 442 | } |
475 | } | 443 | } |
@@ -543,8 +511,6 @@ void __init init_IRQ(void) | |||
543 | */ | 511 | */ |
544 | for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) { | 512 | for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) { |
545 | int vector = FIRST_EXTERNAL_VECTOR + i; | 513 | int vector = FIRST_EXTERNAL_VECTOR + i; |
546 | if (i >= NR_IRQS) | ||
547 | break; | ||
548 | if (vector != IA32_SYSCALL_VECTOR) | 514 | if (vector != IA32_SYSCALL_VECTOR) |
549 | set_intr_gate(vector, interrupt[i]); | 515 | set_intr_gate(vector, interrupt[i]); |
550 | } | 516 | } |
@@ -554,7 +520,7 @@ void __init init_IRQ(void) | |||
554 | * IRQ0 must be given a fixed assignment and initialized, | 520 | * IRQ0 must be given a fixed assignment and initialized, |
555 | * because it's used before the IO-APIC is set up. | 521 | * because it's used before the IO-APIC is set up. |
556 | */ | 522 | */ |
557 | set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]); | 523 | __get_cpu_var(vector_irq)[FIRST_DEVICE_VECTOR] = 0; |
558 | 524 | ||
559 | /* | 525 | /* |
560 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper | 526 | * The reschedule interrupt is a CPU-to-CPU reschedule-helper |
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c index 0491019d4c8d..91728d9d3472 100644 --- a/arch/x86_64/kernel/io_apic.c +++ b/arch/x86_64/kernel/io_apic.c | |||
@@ -26,9 +26,12 @@ | |||
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/sched.h> | 27 | #include <linux/sched.h> |
28 | #include <linux/smp_lock.h> | 28 | #include <linux/smp_lock.h> |
29 | #include <linux/pci.h> | ||
29 | #include <linux/mc146818rtc.h> | 30 | #include <linux/mc146818rtc.h> |
30 | #include <linux/acpi.h> | 31 | #include <linux/acpi.h> |
31 | #include <linux/sysdev.h> | 32 | #include <linux/sysdev.h> |
33 | #include <linux/msi.h> | ||
34 | #include <linux/htirq.h> | ||
32 | #ifdef CONFIG_ACPI | 35 | #ifdef CONFIG_ACPI |
33 | #include <acpi/acpi_bus.h> | 36 | #include <acpi/acpi_bus.h> |
34 | #endif | 37 | #endif |
@@ -41,6 +44,10 @@ | |||
41 | #include <asm/acpi.h> | 44 | #include <asm/acpi.h> |
42 | #include <asm/dma.h> | 45 | #include <asm/dma.h> |
43 | #include <asm/nmi.h> | 46 | #include <asm/nmi.h> |
47 | #include <asm/msidef.h> | ||
48 | #include <asm/hypertransport.h> | ||
49 | |||
50 | static int assign_irq_vector(int irq, cpumask_t mask); | ||
44 | 51 | ||
45 | #define __apicdebuginit __init | 52 | #define __apicdebuginit __init |
46 | 53 | ||
@@ -81,14 +88,6 @@ static struct irq_pin_list { | |||
81 | short apic, pin, next; | 88 | short apic, pin, next; |
82 | } irq_2_pin[PIN_MAP_SIZE]; | 89 | } irq_2_pin[PIN_MAP_SIZE]; |
83 | 90 | ||
84 | int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1}; | ||
85 | #ifdef CONFIG_PCI_MSI | ||
86 | #define vector_to_irq(vector) \ | ||
87 | (platform_legacy_irq(vector) ? vector : vector_irq[vector]) | ||
88 | #else | ||
89 | #define vector_to_irq(vector) (vector) | ||
90 | #endif | ||
91 | |||
92 | #define __DO_ACTION(R, ACTION, FINAL) \ | 91 | #define __DO_ACTION(R, ACTION, FINAL) \ |
93 | \ | 92 | \ |
94 | { \ | 93 | { \ |
@@ -139,11 +138,35 @@ static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) | |||
139 | } | 138 | } |
140 | 139 | ||
141 | #ifdef CONFIG_SMP | 140 | #ifdef CONFIG_SMP |
141 | static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) | ||
142 | { | ||
143 | int apic, pin; | ||
144 | struct irq_pin_list *entry = irq_2_pin + irq; | ||
145 | |||
146 | BUG_ON(irq >= NR_IRQS); | ||
147 | for (;;) { | ||
148 | unsigned int reg; | ||
149 | apic = entry->apic; | ||
150 | pin = entry->pin; | ||
151 | if (pin == -1) | ||
152 | break; | ||
153 | io_apic_write(apic, 0x11 + pin*2, dest); | ||
154 | reg = io_apic_read(apic, 0x10 + pin*2); | ||
155 | reg &= ~0x000000ff; | ||
156 | reg |= vector; | ||
157 | io_apic_modify(apic, reg); | ||
158 | if (!entry->next) | ||
159 | break; | ||
160 | entry = irq_2_pin + entry->next; | ||
161 | } | ||
162 | } | ||
163 | |||
142 | static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) | 164 | static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) |
143 | { | 165 | { |
144 | unsigned long flags; | 166 | unsigned long flags; |
145 | unsigned int dest; | 167 | unsigned int dest; |
146 | cpumask_t tmp; | 168 | cpumask_t tmp; |
169 | int vector; | ||
147 | 170 | ||
148 | cpus_and(tmp, mask, cpu_online_map); | 171 | cpus_and(tmp, mask, cpu_online_map); |
149 | if (cpus_empty(tmp)) | 172 | if (cpus_empty(tmp)) |
@@ -151,7 +174,13 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) | |||
151 | 174 | ||
152 | cpus_and(mask, tmp, CPU_MASK_ALL); | 175 | cpus_and(mask, tmp, CPU_MASK_ALL); |
153 | 176 | ||
154 | dest = cpu_mask_to_apicid(mask); | 177 | vector = assign_irq_vector(irq, mask); |
178 | if (vector < 0) | ||
179 | return; | ||
180 | |||
181 | cpus_clear(tmp); | ||
182 | cpu_set(vector >> 8, tmp); | ||
183 | dest = cpu_mask_to_apicid(tmp); | ||
155 | 184 | ||
156 | /* | 185 | /* |
157 | * Only the high 8 bits are valid. | 186 | * Only the high 8 bits are valid. |
@@ -159,14 +188,12 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) | |||
159 | dest = SET_APIC_LOGICAL_ID(dest); | 188 | dest = SET_APIC_LOGICAL_ID(dest); |
160 | 189 | ||
161 | spin_lock_irqsave(&ioapic_lock, flags); | 190 | spin_lock_irqsave(&ioapic_lock, flags); |
162 | __DO_ACTION(1, = dest, ) | 191 | __target_IO_APIC_irq(irq, dest, vector & 0xff); |
163 | set_irq_info(irq, mask); | 192 | set_native_irq_info(irq, mask); |
164 | spin_unlock_irqrestore(&ioapic_lock, flags); | 193 | spin_unlock_irqrestore(&ioapic_lock, flags); |
165 | } | 194 | } |
166 | #endif | 195 | #endif |
167 | 196 | ||
168 | static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF }; | ||
169 | |||
170 | /* | 197 | /* |
171 | * The common case is 1:1 IRQ<->pin mappings. Sometimes there are | 198 | * The common case is 1:1 IRQ<->pin mappings. Sometimes there are |
172 | * shared ISA-space IRQs, so we have to support them. We are super | 199 | * shared ISA-space IRQs, so we have to support them. We are super |
@@ -492,64 +519,6 @@ static inline int irq_trigger(int idx) | |||
492 | return MPBIOS_trigger(idx); | 519 | return MPBIOS_trigger(idx); |
493 | } | 520 | } |
494 | 521 | ||
495 | static int next_irq = 16; | ||
496 | |||
497 | /* | ||
498 | * gsi_irq_sharing -- Name overload! "irq" can be either a legacy IRQ | ||
499 | * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number | ||
500 | * from ACPI, which can reach 800 in large boxen. | ||
501 | * | ||
502 | * Compact the sparse GSI space into a sequential IRQ series and reuse | ||
503 | * vectors if possible. | ||
504 | */ | ||
505 | int gsi_irq_sharing(int gsi) | ||
506 | { | ||
507 | int i, tries, vector; | ||
508 | |||
509 | BUG_ON(gsi >= NR_IRQ_VECTORS); | ||
510 | |||
511 | if (platform_legacy_irq(gsi)) | ||
512 | return gsi; | ||
513 | |||
514 | if (gsi_2_irq[gsi] != 0xFF) | ||
515 | return (int)gsi_2_irq[gsi]; | ||
516 | |||
517 | tries = NR_IRQS; | ||
518 | try_again: | ||
519 | vector = assign_irq_vector(gsi); | ||
520 | |||
521 | /* | ||
522 | * Sharing vectors means sharing IRQs, so scan irq_vectors for previous | ||
523 | * use of vector and if found, return that IRQ. However, we never want | ||
524 | * to share legacy IRQs, which usually have a different trigger mode | ||
525 | * than PCI. | ||
526 | */ | ||
527 | for (i = 0; i < NR_IRQS; i++) | ||
528 | if (IO_APIC_VECTOR(i) == vector) | ||
529 | break; | ||
530 | if (platform_legacy_irq(i)) { | ||
531 | if (--tries >= 0) { | ||
532 | IO_APIC_VECTOR(i) = 0; | ||
533 | goto try_again; | ||
534 | } | ||
535 | panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi); | ||
536 | } | ||
537 | if (i < NR_IRQS) { | ||
538 | gsi_2_irq[gsi] = i; | ||
539 | printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n", | ||
540 | gsi, vector, i); | ||
541 | return i; | ||
542 | } | ||
543 | |||
544 | i = next_irq++; | ||
545 | BUG_ON(i >= NR_IRQS); | ||
546 | gsi_2_irq[gsi] = i; | ||
547 | IO_APIC_VECTOR(i) = vector; | ||
548 | printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n", | ||
549 | gsi, vector, i); | ||
550 | return i; | ||
551 | } | ||
552 | |||
553 | static int pin_2_irq(int idx, int apic, int pin) | 522 | static int pin_2_irq(int idx, int apic, int pin) |
554 | { | 523 | { |
555 | int irq, i; | 524 | int irq, i; |
@@ -571,7 +540,6 @@ static int pin_2_irq(int idx, int apic, int pin) | |||
571 | while (i < apic) | 540 | while (i < apic) |
572 | irq += nr_ioapic_registers[i++]; | 541 | irq += nr_ioapic_registers[i++]; |
573 | irq += pin; | 542 | irq += pin; |
574 | irq = gsi_irq_sharing(irq); | ||
575 | } | 543 | } |
576 | BUG_ON(irq >= NR_IRQS); | 544 | BUG_ON(irq >= NR_IRQS); |
577 | return irq; | 545 | return irq; |
@@ -595,46 +563,83 @@ static inline int IO_APIC_irq_trigger(int irq) | |||
595 | } | 563 | } |
596 | 564 | ||
597 | /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ | 565 | /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */ |
598 | u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 }; | 566 | unsigned int irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_EXTERNAL_VECTOR, 0 }; |
599 | 567 | ||
600 | int assign_irq_vector(int irq) | 568 | static int __assign_irq_vector(int irq, cpumask_t mask) |
601 | { | 569 | { |
602 | static int current_vector = FIRST_DEVICE_VECTOR, offset = 0; | 570 | /* |
603 | unsigned long flags; | 571 | * NOTE! The local APIC isn't very good at handling |
604 | int vector; | 572 | * multiple interrupts at the same interrupt level. |
605 | 573 | * As the interrupt level is determined by taking the | |
606 | BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS); | 574 | * vector number and shifting that right by 4, we |
607 | 575 | * want to spread these out a bit so that they don't | |
608 | spin_lock_irqsave(&vector_lock, flags); | 576 | * all fall in the same interrupt level. |
609 | 577 | * | |
610 | if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) { | 578 | * Also, we've got to be careful not to trash gate |
611 | spin_unlock_irqrestore(&vector_lock, flags); | 579 | * 0x80, because int 0x80 is hm, kind of importantish. ;) |
612 | return IO_APIC_VECTOR(irq); | 580 | */ |
581 | static struct { | ||
582 | int vector; | ||
583 | int offset; | ||
584 | } pos[NR_CPUS] = { [ 0 ... NR_CPUS - 1] = {FIRST_DEVICE_VECTOR, 0} }; | ||
585 | int old_vector = -1; | ||
586 | int cpu; | ||
587 | |||
588 | BUG_ON((unsigned)irq >= NR_IRQ_VECTORS); | ||
589 | |||
590 | if (IO_APIC_VECTOR(irq) > 0) | ||
591 | old_vector = IO_APIC_VECTOR(irq); | ||
592 | if ((old_vector > 0) && cpu_isset(old_vector >> 8, mask)) { | ||
593 | return old_vector; | ||
613 | } | 594 | } |
595 | |||
596 | for_each_cpu_mask(cpu, mask) { | ||
597 | int vector, offset; | ||
598 | vector = pos[cpu].vector; | ||
599 | offset = pos[cpu].offset; | ||
614 | next: | 600 | next: |
615 | current_vector += 8; | 601 | vector += 8; |
616 | if (current_vector == IA32_SYSCALL_VECTOR) | 602 | if (vector >= FIRST_SYSTEM_VECTOR) { |
617 | goto next; | 603 | /* If we run out of vectors on large boxen, must share them. */ |
618 | 604 | offset = (offset + 1) % 8; | |
619 | if (current_vector >= FIRST_SYSTEM_VECTOR) { | 605 | vector = FIRST_DEVICE_VECTOR + offset; |
620 | /* If we run out of vectors on large boxen, must share them. */ | 606 | } |
621 | offset = (offset + 1) % 8; | 607 | if (unlikely(pos[cpu].vector == vector)) |
622 | current_vector = FIRST_DEVICE_VECTOR + offset; | 608 | continue; |
609 | if (vector == IA32_SYSCALL_VECTOR) | ||
610 | goto next; | ||
611 | if (per_cpu(vector_irq, cpu)[vector] != -1) | ||
612 | goto next; | ||
613 | /* Found one! */ | ||
614 | pos[cpu].vector = vector; | ||
615 | pos[cpu].offset = offset; | ||
616 | if (old_vector >= 0) { | ||
617 | int old_cpu = old_vector >> 8; | ||
618 | old_vector &= 0xff; | ||
619 | per_cpu(vector_irq, old_cpu)[old_vector] = -1; | ||
620 | } | ||
621 | per_cpu(vector_irq, cpu)[vector] = irq; | ||
622 | vector |= cpu << 8; | ||
623 | IO_APIC_VECTOR(irq) = vector; | ||
624 | return vector; | ||
623 | } | 625 | } |
626 | return -ENOSPC; | ||
627 | } | ||
624 | 628 | ||
625 | vector = current_vector; | 629 | static int assign_irq_vector(int irq, cpumask_t mask) |
626 | vector_irq[vector] = irq; | 630 | { |
627 | if (irq != AUTO_ASSIGN) | 631 | int vector; |
628 | IO_APIC_VECTOR(irq) = vector; | 632 | unsigned long flags; |
629 | 633 | ||
634 | spin_lock_irqsave(&vector_lock, flags); | ||
635 | vector = __assign_irq_vector(irq, mask); | ||
630 | spin_unlock_irqrestore(&vector_lock, flags); | 636 | spin_unlock_irqrestore(&vector_lock, flags); |
631 | |||
632 | return vector; | 637 | return vector; |
633 | } | 638 | } |
634 | 639 | ||
635 | extern void (*interrupt[NR_IRQS])(void); | 640 | extern void (*interrupt[NR_IRQS])(void); |
636 | static struct hw_interrupt_type ioapic_level_type; | 641 | |
637 | static struct hw_interrupt_type ioapic_edge_type; | 642 | static struct irq_chip ioapic_chip; |
638 | 643 | ||
639 | #define IOAPIC_AUTO -1 | 644 | #define IOAPIC_AUTO -1 |
640 | #define IOAPIC_EDGE 0 | 645 | #define IOAPIC_EDGE 0 |
@@ -642,16 +647,13 @@ static struct hw_interrupt_type ioapic_edge_type; | |||
642 | 647 | ||
643 | static void ioapic_register_intr(int irq, int vector, unsigned long trigger) | 648 | static void ioapic_register_intr(int irq, int vector, unsigned long trigger) |
644 | { | 649 | { |
645 | unsigned idx; | ||
646 | |||
647 | idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq; | ||
648 | |||
649 | if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || | 650 | if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || |
650 | trigger == IOAPIC_LEVEL) | 651 | trigger == IOAPIC_LEVEL) |
651 | irq_desc[idx].chip = &ioapic_level_type; | 652 | set_irq_chip_and_handler(irq, &ioapic_chip, |
653 | handle_fasteoi_irq); | ||
652 | else | 654 | else |
653 | irq_desc[idx].chip = &ioapic_edge_type; | 655 | set_irq_chip_and_handler(irq, &ioapic_chip, |
654 | set_intr_gate(vector, interrupt[idx]); | 656 | handle_edge_irq); |
655 | } | 657 | } |
656 | 658 | ||
657 | static void __init setup_IO_APIC_irqs(void) | 659 | static void __init setup_IO_APIC_irqs(void) |
@@ -701,8 +703,15 @@ static void __init setup_IO_APIC_irqs(void) | |||
701 | continue; | 703 | continue; |
702 | 704 | ||
703 | if (IO_APIC_IRQ(irq)) { | 705 | if (IO_APIC_IRQ(irq)) { |
704 | vector = assign_irq_vector(irq); | 706 | cpumask_t mask; |
705 | entry.vector = vector; | 707 | vector = assign_irq_vector(irq, TARGET_CPUS); |
708 | if (vector < 0) | ||
709 | continue; | ||
710 | |||
711 | cpus_clear(mask); | ||
712 | cpu_set(vector >> 8, mask); | ||
713 | entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); | ||
714 | entry.vector = vector & 0xff; | ||
706 | 715 | ||
707 | ioapic_register_intr(irq, vector, IOAPIC_AUTO); | 716 | ioapic_register_intr(irq, vector, IOAPIC_AUTO); |
708 | if (!apic && (irq < 16)) | 717 | if (!apic && (irq < 16)) |
@@ -752,7 +761,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in | |||
752 | * The timer IRQ doesn't have to know that behind the | 761 | * The timer IRQ doesn't have to know that behind the |
753 | * scene we have a 8259A-master in AEOI mode ... | 762 | * scene we have a 8259A-master in AEOI mode ... |
754 | */ | 763 | */ |
755 | irq_desc[0].chip = &ioapic_edge_type; | 764 | set_irq_chip_and_handler(0, &ioapic_chip, handle_edge_irq); |
756 | 765 | ||
757 | /* | 766 | /* |
758 | * Add it to the IO-APIC irq-routing table: | 767 | * Add it to the IO-APIC irq-routing table: |
@@ -868,17 +877,12 @@ void __apicdebuginit print_IO_APIC(void) | |||
868 | ); | 877 | ); |
869 | } | 878 | } |
870 | } | 879 | } |
871 | if (use_pci_vector()) | ||
872 | printk(KERN_INFO "Using vector-based indexing\n"); | ||
873 | printk(KERN_DEBUG "IRQ to pin mappings:\n"); | 880 | printk(KERN_DEBUG "IRQ to pin mappings:\n"); |
874 | for (i = 0; i < NR_IRQS; i++) { | 881 | for (i = 0; i < NR_IRQS; i++) { |
875 | struct irq_pin_list *entry = irq_2_pin + i; | 882 | struct irq_pin_list *entry = irq_2_pin + i; |
876 | if (entry->pin < 0) | 883 | if (entry->pin < 0) |
877 | continue; | 884 | continue; |
878 | if (use_pci_vector() && !platform_legacy_irq(i)) | 885 | printk(KERN_DEBUG "IRQ%d ", i); |
879 | printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i)); | ||
880 | else | ||
881 | printk(KERN_DEBUG "IRQ%d ", i); | ||
882 | for (;;) { | 886 | for (;;) { |
883 | printk("-> %d:%d", entry->apic, entry->pin); | 887 | printk("-> %d:%d", entry->apic, entry->pin); |
884 | if (!entry->next) | 888 | if (!entry->next) |
@@ -1185,7 +1189,7 @@ static int __init timer_irq_works(void) | |||
1185 | * an edge even if it isn't on the 8259A... | 1189 | * an edge even if it isn't on the 8259A... |
1186 | */ | 1190 | */ |
1187 | 1191 | ||
1188 | static unsigned int startup_edge_ioapic_irq(unsigned int irq) | 1192 | static unsigned int startup_ioapic_irq(unsigned int irq) |
1189 | { | 1193 | { |
1190 | int was_pending = 0; | 1194 | int was_pending = 0; |
1191 | unsigned long flags; | 1195 | unsigned long flags; |
@@ -1202,107 +1206,16 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq) | |||
1202 | return was_pending; | 1206 | return was_pending; |
1203 | } | 1207 | } |
1204 | 1208 | ||
1205 | /* | 1209 | static int ioapic_retrigger_irq(unsigned int irq) |
1206 | * Once we have recorded IRQ_PENDING already, we can mask the | ||
1207 | * interrupt for real. This prevents IRQ storms from unhandled | ||
1208 | * devices. | ||
1209 | */ | ||
1210 | static void ack_edge_ioapic_irq(unsigned int irq) | ||
1211 | { | ||
1212 | move_irq(irq); | ||
1213 | if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED)) | ||
1214 | == (IRQ_PENDING | IRQ_DISABLED)) | ||
1215 | mask_IO_APIC_irq(irq); | ||
1216 | ack_APIC_irq(); | ||
1217 | } | ||
1218 | |||
1219 | /* | ||
1220 | * Level triggered interrupts can just be masked, | ||
1221 | * and shutting down and starting up the interrupt | ||
1222 | * is the same as enabling and disabling them -- except | ||
1223 | * with a startup need to return a "was pending" value. | ||
1224 | * | ||
1225 | * Level triggered interrupts are special because we | ||
1226 | * do not touch any IO-APIC register while handling | ||
1227 | * them. We ack the APIC in the end-IRQ handler, not | ||
1228 | * in the start-IRQ-handler. Protection against reentrance | ||
1229 | * from the same interrupt is still provided, both by the | ||
1230 | * generic IRQ layer and by the fact that an unacked local | ||
1231 | * APIC does not accept IRQs. | ||
1232 | */ | ||
1233 | static unsigned int startup_level_ioapic_irq (unsigned int irq) | ||
1234 | { | ||
1235 | unmask_IO_APIC_irq(irq); | ||
1236 | |||
1237 | return 0; /* don't check for pending */ | ||
1238 | } | ||
1239 | |||
1240 | static void end_level_ioapic_irq (unsigned int irq) | ||
1241 | { | ||
1242 | move_irq(irq); | ||
1243 | ack_APIC_irq(); | ||
1244 | } | ||
1245 | |||
1246 | #ifdef CONFIG_PCI_MSI | ||
1247 | static unsigned int startup_edge_ioapic_vector(unsigned int vector) | ||
1248 | { | ||
1249 | int irq = vector_to_irq(vector); | ||
1250 | |||
1251 | return startup_edge_ioapic_irq(irq); | ||
1252 | } | ||
1253 | |||
1254 | static void ack_edge_ioapic_vector(unsigned int vector) | ||
1255 | { | ||
1256 | int irq = vector_to_irq(vector); | ||
1257 | |||
1258 | move_native_irq(vector); | ||
1259 | ack_edge_ioapic_irq(irq); | ||
1260 | } | ||
1261 | |||
1262 | static unsigned int startup_level_ioapic_vector (unsigned int vector) | ||
1263 | { | 1210 | { |
1264 | int irq = vector_to_irq(vector); | 1211 | cpumask_t mask; |
1212 | unsigned vector; | ||
1265 | 1213 | ||
1266 | return startup_level_ioapic_irq (irq); | 1214 | vector = irq_vector[irq]; |
1267 | } | 1215 | cpus_clear(mask); |
1268 | 1216 | cpu_set(vector >> 8, mask); | |
1269 | static void end_level_ioapic_vector (unsigned int vector) | ||
1270 | { | ||
1271 | int irq = vector_to_irq(vector); | ||
1272 | |||
1273 | move_native_irq(vector); | ||
1274 | end_level_ioapic_irq(irq); | ||
1275 | } | ||
1276 | |||
1277 | static void mask_IO_APIC_vector (unsigned int vector) | ||
1278 | { | ||
1279 | int irq = vector_to_irq(vector); | ||
1280 | |||
1281 | mask_IO_APIC_irq(irq); | ||
1282 | } | ||
1283 | 1217 | ||
1284 | static void unmask_IO_APIC_vector (unsigned int vector) | 1218 | send_IPI_mask(mask, vector & 0xff); |
1285 | { | ||
1286 | int irq = vector_to_irq(vector); | ||
1287 | |||
1288 | unmask_IO_APIC_irq(irq); | ||
1289 | } | ||
1290 | |||
1291 | #ifdef CONFIG_SMP | ||
1292 | static void set_ioapic_affinity_vector (unsigned int vector, | ||
1293 | cpumask_t cpu_mask) | ||
1294 | { | ||
1295 | int irq = vector_to_irq(vector); | ||
1296 | |||
1297 | set_native_irq_info(vector, cpu_mask); | ||
1298 | set_ioapic_affinity_irq(irq, cpu_mask); | ||
1299 | } | ||
1300 | #endif // CONFIG_SMP | ||
1301 | #endif // CONFIG_PCI_MSI | ||
1302 | |||
1303 | static int ioapic_retrigger(unsigned int irq) | ||
1304 | { | ||
1305 | send_IPI_self(IO_APIC_VECTOR(irq)); | ||
1306 | 1219 | ||
1307 | return 1; | 1220 | return 1; |
1308 | } | 1221 | } |
@@ -1316,32 +1229,47 @@ static int ioapic_retrigger(unsigned int irq) | |||
1316 | * races. | 1229 | * races. |
1317 | */ | 1230 | */ |
1318 | 1231 | ||
1319 | static struct hw_interrupt_type ioapic_edge_type __read_mostly = { | 1232 | static void ack_apic_edge(unsigned int irq) |
1320 | .typename = "IO-APIC-edge", | 1233 | { |
1321 | .startup = startup_edge_ioapic, | 1234 | move_native_irq(irq); |
1322 | .shutdown = shutdown_edge_ioapic, | 1235 | ack_APIC_irq(); |
1323 | .enable = enable_edge_ioapic, | 1236 | } |
1324 | .disable = disable_edge_ioapic, | 1237 | |
1325 | .ack = ack_edge_ioapic, | 1238 | static void ack_apic_level(unsigned int irq) |
1326 | .end = end_edge_ioapic, | 1239 | { |
1327 | #ifdef CONFIG_SMP | 1240 | int do_unmask_irq = 0; |
1328 | .set_affinity = set_ioapic_affinity, | 1241 | |
1242 | #if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE) | ||
1243 | /* If we are moving the irq we need to mask it */ | ||
1244 | if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) { | ||
1245 | do_unmask_irq = 1; | ||
1246 | mask_IO_APIC_irq(irq); | ||
1247 | } | ||
1329 | #endif | 1248 | #endif |
1330 | .retrigger = ioapic_retrigger, | ||
1331 | }; | ||
1332 | 1249 | ||
1333 | static struct hw_interrupt_type ioapic_level_type __read_mostly = { | 1250 | /* |
1334 | .typename = "IO-APIC-level", | 1251 | * We must acknowledge the irq before we move it or the acknowledge will |
1335 | .startup = startup_level_ioapic, | 1252 | * not propogate properly. |
1336 | .shutdown = shutdown_level_ioapic, | 1253 | */ |
1337 | .enable = enable_level_ioapic, | 1254 | ack_APIC_irq(); |
1338 | .disable = disable_level_ioapic, | 1255 | |
1339 | .ack = mask_and_ack_level_ioapic, | 1256 | /* Now we can move and renable the irq */ |
1340 | .end = end_level_ioapic, | 1257 | move_masked_irq(irq); |
1258 | if (unlikely(do_unmask_irq)) | ||
1259 | unmask_IO_APIC_irq(irq); | ||
1260 | } | ||
1261 | |||
1262 | static struct irq_chip ioapic_chip __read_mostly = { | ||
1263 | .name = "IO-APIC", | ||
1264 | .startup = startup_ioapic_irq, | ||
1265 | .mask = mask_IO_APIC_irq, | ||
1266 | .unmask = unmask_IO_APIC_irq, | ||
1267 | .ack = ack_apic_edge, | ||
1268 | .eoi = ack_apic_level, | ||
1341 | #ifdef CONFIG_SMP | 1269 | #ifdef CONFIG_SMP |
1342 | .set_affinity = set_ioapic_affinity, | 1270 | .set_affinity = set_ioapic_affinity_irq, |
1343 | #endif | 1271 | #endif |
1344 | .retrigger = ioapic_retrigger, | 1272 | .retrigger = ioapic_retrigger_irq, |
1345 | }; | 1273 | }; |
1346 | 1274 | ||
1347 | static inline void init_IO_APIC_traps(void) | 1275 | static inline void init_IO_APIC_traps(void) |
@@ -1361,11 +1289,6 @@ static inline void init_IO_APIC_traps(void) | |||
1361 | */ | 1289 | */ |
1362 | for (irq = 0; irq < NR_IRQS ; irq++) { | 1290 | for (irq = 0; irq < NR_IRQS ; irq++) { |
1363 | int tmp = irq; | 1291 | int tmp = irq; |
1364 | if (use_pci_vector()) { | ||
1365 | if (!platform_legacy_irq(tmp)) | ||
1366 | if ((tmp = vector_to_irq(tmp)) == -1) | ||
1367 | continue; | ||
1368 | } | ||
1369 | if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { | 1292 | if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) { |
1370 | /* | 1293 | /* |
1371 | * Hmm.. We don't have an entry for this, | 1294 | * Hmm.. We don't have an entry for this, |
@@ -1376,7 +1299,7 @@ static inline void init_IO_APIC_traps(void) | |||
1376 | make_8259A_irq(irq); | 1299 | make_8259A_irq(irq); |
1377 | else | 1300 | else |
1378 | /* Strange. Oh, well.. */ | 1301 | /* Strange. Oh, well.. */ |
1379 | irq_desc[irq].chip = &no_irq_type; | 1302 | irq_desc[irq].chip = &no_irq_chip; |
1380 | } | 1303 | } |
1381 | } | 1304 | } |
1382 | } | 1305 | } |
@@ -1495,8 +1418,6 @@ static inline void unlock_ExtINT_logic(void) | |||
1495 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1418 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1496 | } | 1419 | } |
1497 | 1420 | ||
1498 | int timer_uses_ioapic_pin_0; | ||
1499 | |||
1500 | /* | 1421 | /* |
1501 | * This code may look a bit paranoid, but it's supposed to cooperate with | 1422 | * This code may look a bit paranoid, but it's supposed to cooperate with |
1502 | * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ | 1423 | * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ |
@@ -1514,8 +1435,7 @@ static inline void check_timer(void) | |||
1514 | * get/set the timer IRQ vector: | 1435 | * get/set the timer IRQ vector: |
1515 | */ | 1436 | */ |
1516 | disable_8259A_irq(0); | 1437 | disable_8259A_irq(0); |
1517 | vector = assign_irq_vector(0); | 1438 | vector = assign_irq_vector(0, TARGET_CPUS); |
1518 | set_intr_gate(vector, interrupt[0]); | ||
1519 | 1439 | ||
1520 | /* | 1440 | /* |
1521 | * Subtle, code in do_timer_interrupt() expects an AEOI | 1441 | * Subtle, code in do_timer_interrupt() expects an AEOI |
@@ -1534,9 +1454,6 @@ static inline void check_timer(void) | |||
1534 | pin2 = ioapic_i8259.pin; | 1454 | pin2 = ioapic_i8259.pin; |
1535 | apic2 = ioapic_i8259.apic; | 1455 | apic2 = ioapic_i8259.apic; |
1536 | 1456 | ||
1537 | if (pin1 == 0) | ||
1538 | timer_uses_ioapic_pin_0 = 1; | ||
1539 | |||
1540 | apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", | 1457 | apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", |
1541 | vector, apic1, pin1, apic2, pin2); | 1458 | vector, apic1, pin1, apic2, pin2); |
1542 | 1459 | ||
@@ -1740,6 +1657,253 @@ static int __init ioapic_init_sysfs(void) | |||
1740 | 1657 | ||
1741 | device_initcall(ioapic_init_sysfs); | 1658 | device_initcall(ioapic_init_sysfs); |
1742 | 1659 | ||
1660 | /* | ||
1661 | * Dynamic irq allocate and deallocation | ||
1662 | */ | ||
1663 | int create_irq(void) | ||
1664 | { | ||
1665 | /* Allocate an unused irq */ | ||
1666 | int irq; | ||
1667 | int new; | ||
1668 | int vector = 0; | ||
1669 | unsigned long flags; | ||
1670 | |||
1671 | irq = -ENOSPC; | ||
1672 | spin_lock_irqsave(&vector_lock, flags); | ||
1673 | for (new = (NR_IRQS - 1); new >= 0; new--) { | ||
1674 | if (platform_legacy_irq(new)) | ||
1675 | continue; | ||
1676 | if (irq_vector[new] != 0) | ||
1677 | continue; | ||
1678 | vector = __assign_irq_vector(new, TARGET_CPUS); | ||
1679 | if (likely(vector > 0)) | ||
1680 | irq = new; | ||
1681 | break; | ||
1682 | } | ||
1683 | spin_unlock_irqrestore(&vector_lock, flags); | ||
1684 | |||
1685 | if (irq >= 0) { | ||
1686 | dynamic_irq_init(irq); | ||
1687 | } | ||
1688 | return irq; | ||
1689 | } | ||
1690 | |||
1691 | void destroy_irq(unsigned int irq) | ||
1692 | { | ||
1693 | unsigned long flags; | ||
1694 | |||
1695 | dynamic_irq_cleanup(irq); | ||
1696 | |||
1697 | spin_lock_irqsave(&vector_lock, flags); | ||
1698 | irq_vector[irq] = 0; | ||
1699 | spin_unlock_irqrestore(&vector_lock, flags); | ||
1700 | } | ||
1701 | |||
1702 | /* | ||
1703 | * MSI mesage composition | ||
1704 | */ | ||
1705 | #ifdef CONFIG_PCI_MSI | ||
1706 | static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg) | ||
1707 | { | ||
1708 | int vector; | ||
1709 | unsigned dest; | ||
1710 | |||
1711 | vector = assign_irq_vector(irq, TARGET_CPUS); | ||
1712 | if (vector >= 0) { | ||
1713 | cpumask_t tmp; | ||
1714 | |||
1715 | cpus_clear(tmp); | ||
1716 | cpu_set(vector >> 8, tmp); | ||
1717 | dest = cpu_mask_to_apicid(tmp); | ||
1718 | |||
1719 | msg->address_hi = MSI_ADDR_BASE_HI; | ||
1720 | msg->address_lo = | ||
1721 | MSI_ADDR_BASE_LO | | ||
1722 | ((INT_DEST_MODE == 0) ? | ||
1723 | MSI_ADDR_DEST_MODE_PHYSICAL: | ||
1724 | MSI_ADDR_DEST_MODE_LOGICAL) | | ||
1725 | ((INT_DELIVERY_MODE != dest_LowestPrio) ? | ||
1726 | MSI_ADDR_REDIRECTION_CPU: | ||
1727 | MSI_ADDR_REDIRECTION_LOWPRI) | | ||
1728 | MSI_ADDR_DEST_ID(dest); | ||
1729 | |||
1730 | msg->data = | ||
1731 | MSI_DATA_TRIGGER_EDGE | | ||
1732 | MSI_DATA_LEVEL_ASSERT | | ||
1733 | ((INT_DELIVERY_MODE != dest_LowestPrio) ? | ||
1734 | MSI_DATA_DELIVERY_FIXED: | ||
1735 | MSI_DATA_DELIVERY_LOWPRI) | | ||
1736 | MSI_DATA_VECTOR(vector); | ||
1737 | } | ||
1738 | return vector; | ||
1739 | } | ||
1740 | |||
1741 | #ifdef CONFIG_SMP | ||
1742 | static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) | ||
1743 | { | ||
1744 | struct msi_msg msg; | ||
1745 | unsigned int dest; | ||
1746 | cpumask_t tmp; | ||
1747 | int vector; | ||
1748 | |||
1749 | cpus_and(tmp, mask, cpu_online_map); | ||
1750 | if (cpus_empty(tmp)) | ||
1751 | tmp = TARGET_CPUS; | ||
1752 | |||
1753 | cpus_and(mask, tmp, CPU_MASK_ALL); | ||
1754 | |||
1755 | vector = assign_irq_vector(irq, mask); | ||
1756 | if (vector < 0) | ||
1757 | return; | ||
1758 | |||
1759 | cpus_clear(tmp); | ||
1760 | cpu_set(vector >> 8, tmp); | ||
1761 | dest = cpu_mask_to_apicid(tmp); | ||
1762 | |||
1763 | read_msi_msg(irq, &msg); | ||
1764 | |||
1765 | msg.data &= ~MSI_DATA_VECTOR_MASK; | ||
1766 | msg.data |= MSI_DATA_VECTOR(vector); | ||
1767 | msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; | ||
1768 | msg.address_lo |= MSI_ADDR_DEST_ID(dest); | ||
1769 | |||
1770 | write_msi_msg(irq, &msg); | ||
1771 | set_native_irq_info(irq, mask); | ||
1772 | } | ||
1773 | #endif /* CONFIG_SMP */ | ||
1774 | |||
1775 | /* | ||
1776 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices, | ||
1777 | * which implement the MSI or MSI-X Capability Structure. | ||
1778 | */ | ||
1779 | static struct irq_chip msi_chip = { | ||
1780 | .name = "PCI-MSI", | ||
1781 | .unmask = unmask_msi_irq, | ||
1782 | .mask = mask_msi_irq, | ||
1783 | .ack = ack_apic_edge, | ||
1784 | #ifdef CONFIG_SMP | ||
1785 | .set_affinity = set_msi_irq_affinity, | ||
1786 | #endif | ||
1787 | .retrigger = ioapic_retrigger_irq, | ||
1788 | }; | ||
1789 | |||
1790 | int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev) | ||
1791 | { | ||
1792 | struct msi_msg msg; | ||
1793 | int ret; | ||
1794 | ret = msi_compose_msg(dev, irq, &msg); | ||
1795 | if (ret < 0) | ||
1796 | return ret; | ||
1797 | |||
1798 | write_msi_msg(irq, &msg); | ||
1799 | |||
1800 | set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq); | ||
1801 | |||
1802 | return 0; | ||
1803 | } | ||
1804 | |||
1805 | void arch_teardown_msi_irq(unsigned int irq) | ||
1806 | { | ||
1807 | return; | ||
1808 | } | ||
1809 | |||
1810 | #endif /* CONFIG_PCI_MSI */ | ||
1811 | |||
1812 | /* | ||
1813 | * Hypertransport interrupt support | ||
1814 | */ | ||
1815 | #ifdef CONFIG_HT_IRQ | ||
1816 | |||
1817 | #ifdef CONFIG_SMP | ||
1818 | |||
1819 | static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) | ||
1820 | { | ||
1821 | u32 low, high; | ||
1822 | low = read_ht_irq_low(irq); | ||
1823 | high = read_ht_irq_high(irq); | ||
1824 | |||
1825 | low &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK); | ||
1826 | high &= ~(HT_IRQ_HIGH_DEST_ID_MASK); | ||
1827 | |||
1828 | low |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest); | ||
1829 | high |= HT_IRQ_HIGH_DEST_ID(dest); | ||
1830 | |||
1831 | write_ht_irq_low(irq, low); | ||
1832 | write_ht_irq_high(irq, high); | ||
1833 | } | ||
1834 | |||
1835 | static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) | ||
1836 | { | ||
1837 | unsigned int dest; | ||
1838 | cpumask_t tmp; | ||
1839 | int vector; | ||
1840 | |||
1841 | cpus_and(tmp, mask, cpu_online_map); | ||
1842 | if (cpus_empty(tmp)) | ||
1843 | tmp = TARGET_CPUS; | ||
1844 | |||
1845 | cpus_and(mask, tmp, CPU_MASK_ALL); | ||
1846 | |||
1847 | vector = assign_irq_vector(irq, mask); | ||
1848 | if (vector < 0) | ||
1849 | return; | ||
1850 | |||
1851 | cpus_clear(tmp); | ||
1852 | cpu_set(vector >> 8, tmp); | ||
1853 | dest = cpu_mask_to_apicid(tmp); | ||
1854 | |||
1855 | target_ht_irq(irq, dest, vector & 0xff); | ||
1856 | set_native_irq_info(irq, mask); | ||
1857 | } | ||
1858 | #endif | ||
1859 | |||
1860 | static struct hw_interrupt_type ht_irq_chip = { | ||
1861 | .name = "PCI-HT", | ||
1862 | .mask = mask_ht_irq, | ||
1863 | .unmask = unmask_ht_irq, | ||
1864 | .ack = ack_apic_edge, | ||
1865 | #ifdef CONFIG_SMP | ||
1866 | .set_affinity = set_ht_irq_affinity, | ||
1867 | #endif | ||
1868 | .retrigger = ioapic_retrigger_irq, | ||
1869 | }; | ||
1870 | |||
1871 | int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) | ||
1872 | { | ||
1873 | int vector; | ||
1874 | |||
1875 | vector = assign_irq_vector(irq, TARGET_CPUS); | ||
1876 | if (vector >= 0) { | ||
1877 | u32 low, high; | ||
1878 | unsigned dest; | ||
1879 | cpumask_t tmp; | ||
1880 | |||
1881 | cpus_clear(tmp); | ||
1882 | cpu_set(vector >> 8, tmp); | ||
1883 | dest = cpu_mask_to_apicid(tmp); | ||
1884 | |||
1885 | high = HT_IRQ_HIGH_DEST_ID(dest); | ||
1886 | |||
1887 | low = HT_IRQ_LOW_BASE | | ||
1888 | HT_IRQ_LOW_DEST_ID(dest) | | ||
1889 | HT_IRQ_LOW_VECTOR(vector) | | ||
1890 | ((INT_DEST_MODE == 0) ? | ||
1891 | HT_IRQ_LOW_DM_PHYSICAL : | ||
1892 | HT_IRQ_LOW_DM_LOGICAL) | | ||
1893 | HT_IRQ_LOW_RQEOI_EDGE | | ||
1894 | ((INT_DELIVERY_MODE != dest_LowestPrio) ? | ||
1895 | HT_IRQ_LOW_MT_FIXED : | ||
1896 | HT_IRQ_LOW_MT_ARBITRATED); | ||
1897 | |||
1898 | write_ht_irq_low(irq, low); | ||
1899 | write_ht_irq_high(irq, high); | ||
1900 | |||
1901 | set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq); | ||
1902 | } | ||
1903 | return vector; | ||
1904 | } | ||
1905 | #endif /* CONFIG_HT_IRQ */ | ||
1906 | |||
1743 | /* -------------------------------------------------------------------------- | 1907 | /* -------------------------------------------------------------------------- |
1744 | ACPI-based IOAPIC Configuration | 1908 | ACPI-based IOAPIC Configuration |
1745 | -------------------------------------------------------------------------- */ | 1909 | -------------------------------------------------------------------------- */ |
@@ -1765,6 +1929,8 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p | |||
1765 | { | 1929 | { |
1766 | struct IO_APIC_route_entry entry; | 1930 | struct IO_APIC_route_entry entry; |
1767 | unsigned long flags; | 1931 | unsigned long flags; |
1932 | int vector; | ||
1933 | cpumask_t mask; | ||
1768 | 1934 | ||
1769 | if (!IO_APIC_IRQ(irq)) { | 1935 | if (!IO_APIC_IRQ(irq)) { |
1770 | apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", | 1936 | apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", |
@@ -1773,6 +1939,20 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p | |||
1773 | } | 1939 | } |
1774 | 1940 | ||
1775 | /* | 1941 | /* |
1942 | * IRQs < 16 are already in the irq_2_pin[] map | ||
1943 | */ | ||
1944 | if (irq >= 16) | ||
1945 | add_pin_to_irq(irq, ioapic, pin); | ||
1946 | |||
1947 | |||
1948 | vector = assign_irq_vector(irq, TARGET_CPUS); | ||
1949 | if (vector < 0) | ||
1950 | return vector; | ||
1951 | |||
1952 | cpus_clear(mask); | ||
1953 | cpu_set(vector >> 8, mask); | ||
1954 | |||
1955 | /* | ||
1776 | * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. | 1956 | * Generate a PCI IRQ routing entry and program the IOAPIC accordingly. |
1777 | * Note that we mask (disable) IRQs now -- these get enabled when the | 1957 | * Note that we mask (disable) IRQs now -- these get enabled when the |
1778 | * corresponding device driver registers for this IRQ. | 1958 | * corresponding device driver registers for this IRQ. |
@@ -1782,19 +1962,11 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p | |||
1782 | 1962 | ||
1783 | entry.delivery_mode = INT_DELIVERY_MODE; | 1963 | entry.delivery_mode = INT_DELIVERY_MODE; |
1784 | entry.dest_mode = INT_DEST_MODE; | 1964 | entry.dest_mode = INT_DEST_MODE; |
1785 | entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS); | 1965 | entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask); |
1786 | entry.trigger = triggering; | 1966 | entry.trigger = triggering; |
1787 | entry.polarity = polarity; | 1967 | entry.polarity = polarity; |
1788 | entry.mask = 1; /* Disabled (masked) */ | 1968 | entry.mask = 1; /* Disabled (masked) */ |
1789 | 1969 | entry.vector = vector & 0xff; | |
1790 | irq = gsi_irq_sharing(irq); | ||
1791 | /* | ||
1792 | * IRQs < 16 are already in the irq_2_pin[] map | ||
1793 | */ | ||
1794 | if (irq >= 16) | ||
1795 | add_pin_to_irq(irq, ioapic, pin); | ||
1796 | |||
1797 | entry.vector = assign_irq_vector(irq); | ||
1798 | 1970 | ||
1799 | apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " | 1971 | apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> " |
1800 | "IRQ %d Mode:%i Active:%i)\n", ioapic, | 1972 | "IRQ %d Mode:%i Active:%i)\n", ioapic, |
@@ -1809,7 +1981,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p | |||
1809 | ioapic_write_entry(ioapic, pin, entry); | 1981 | ioapic_write_entry(ioapic, pin, entry); |
1810 | 1982 | ||
1811 | spin_lock_irqsave(&ioapic_lock, flags); | 1983 | spin_lock_irqsave(&ioapic_lock, flags); |
1812 | set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS); | 1984 | set_native_irq_info(irq, TARGET_CPUS); |
1813 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1985 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1814 | 1986 | ||
1815 | return 0; | 1987 | return 0; |
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index b3677e6ccc6e..506f27c85ca5 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c | |||
@@ -74,7 +74,8 @@ int show_interrupts(struct seq_file *p, void *v) | |||
74 | for_each_online_cpu(j) | 74 | for_each_online_cpu(j) |
75 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | 75 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); |
76 | #endif | 76 | #endif |
77 | seq_printf(p, " %14s", irq_desc[i].chip->typename); | 77 | seq_printf(p, " %8s", irq_desc[i].chip->name); |
78 | seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq)); | ||
78 | 79 | ||
79 | seq_printf(p, " %s", action->name); | 80 | seq_printf(p, " %s", action->name); |
80 | for (action=action->next; action; action = action->next) | 81 | for (action=action->next; action; action = action->next) |
@@ -104,7 +105,12 @@ skip: | |||
104 | asmlinkage unsigned int do_IRQ(struct pt_regs *regs) | 105 | asmlinkage unsigned int do_IRQ(struct pt_regs *regs) |
105 | { | 106 | { |
106 | /* high bit used in ret_from_ code */ | 107 | /* high bit used in ret_from_ code */ |
107 | unsigned irq = ~regs->orig_rax; | 108 | unsigned vector = ~regs->orig_rax; |
109 | unsigned irq; | ||
110 | |||
111 | exit_idle(); | ||
112 | irq_enter(); | ||
113 | irq = __get_cpu_var(vector_irq)[vector]; | ||
108 | 114 | ||
109 | if (unlikely(irq >= NR_IRQS)) { | 115 | if (unlikely(irq >= NR_IRQS)) { |
110 | printk(KERN_EMERG "%s: cannot handle IRQ %d\n", | 116 | printk(KERN_EMERG "%s: cannot handle IRQ %d\n", |
@@ -112,12 +118,10 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs) | |||
112 | BUG(); | 118 | BUG(); |
113 | } | 119 | } |
114 | 120 | ||
115 | exit_idle(); | ||
116 | irq_enter(); | ||
117 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | 121 | #ifdef CONFIG_DEBUG_STACKOVERFLOW |
118 | stack_overflow_check(regs); | 122 | stack_overflow_check(regs); |
119 | #endif | 123 | #endif |
120 | __do_IRQ(irq, regs); | 124 | generic_handle_irq(irq, regs); |
121 | irq_exit(); | 125 | irq_exit(); |
122 | 126 | ||
123 | return 1; | 127 | return 1; |
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c index b8d53dfa9931..b147ab19fbd4 100644 --- a/arch/x86_64/kernel/mpparse.c +++ b/arch/x86_64/kernel/mpparse.c | |||
@@ -790,20 +790,11 @@ void __init mp_config_acpi_legacy_irqs(void) | |||
790 | } | 790 | } |
791 | } | 791 | } |
792 | 792 | ||
793 | #define MAX_GSI_NUM 4096 | ||
794 | |||
795 | int mp_register_gsi(u32 gsi, int triggering, int polarity) | 793 | int mp_register_gsi(u32 gsi, int triggering, int polarity) |
796 | { | 794 | { |
797 | int ioapic = -1; | 795 | int ioapic = -1; |
798 | int ioapic_pin = 0; | 796 | int ioapic_pin = 0; |
799 | int idx, bit = 0; | 797 | int idx, bit = 0; |
800 | static int pci_irq = 16; | ||
801 | /* | ||
802 | * Mapping between Global System Interrupts, which | ||
803 | * represent all possible interrupts, to the IRQs | ||
804 | * assigned to actual devices. | ||
805 | */ | ||
806 | static int gsi_to_irq[MAX_GSI_NUM]; | ||
807 | 798 | ||
808 | if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) | 799 | if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) |
809 | return gsi; | 800 | return gsi; |
@@ -836,42 +827,11 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity) | |||
836 | if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) { | 827 | if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) { |
837 | Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n", | 828 | Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n", |
838 | mp_ioapic_routing[ioapic].apic_id, ioapic_pin); | 829 | mp_ioapic_routing[ioapic].apic_id, ioapic_pin); |
839 | return gsi_to_irq[gsi]; | 830 | return gsi; |
840 | } | 831 | } |
841 | 832 | ||
842 | mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit); | 833 | mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit); |
843 | 834 | ||
844 | if (triggering == ACPI_LEVEL_SENSITIVE) { | ||
845 | /* | ||
846 | * For PCI devices assign IRQs in order, avoiding gaps | ||
847 | * due to unused I/O APIC pins. | ||
848 | */ | ||
849 | int irq = gsi; | ||
850 | if (gsi < MAX_GSI_NUM) { | ||
851 | /* | ||
852 | * Retain the VIA chipset work-around (gsi > 15), but | ||
853 | * avoid a problem where the 8254 timer (IRQ0) is setup | ||
854 | * via an override (so it's not on pin 0 of the ioapic), | ||
855 | * and at the same time, the pin 0 interrupt is a PCI | ||
856 | * type. The gsi > 15 test could cause these two pins | ||
857 | * to be shared as IRQ0, and they are not shareable. | ||
858 | * So test for this condition, and if necessary, avoid | ||
859 | * the pin collision. | ||
860 | */ | ||
861 | if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0)) | ||
862 | gsi = pci_irq++; | ||
863 | /* | ||
864 | * Don't assign IRQ used by ACPI SCI | ||
865 | */ | ||
866 | if (gsi == acpi_fadt.sci_int) | ||
867 | gsi = pci_irq++; | ||
868 | gsi_to_irq[irq] = gsi; | ||
869 | } else { | ||
870 | printk(KERN_ERR "GSI %u is too high\n", gsi); | ||
871 | return gsi; | ||
872 | } | ||
873 | } | ||
874 | |||
875 | io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, | 835 | io_apic_set_pci_routing(ioapic, ioapic_pin, gsi, |
876 | triggering == ACPI_EDGE_SENSITIVE ? 0 : 1, | 836 | triggering == ACPI_EDGE_SENSITIVE ? 0 : 1, |
877 | polarity == ACPI_ACTIVE_HIGH ? 0 : 1); | 837 | polarity == ACPI_ACTIVE_HIGH ? 0 : 1); |