diff options
author | Anton Altaparmakov <aia21@cantab.net> | 2005-10-17 10:00:34 -0400 |
---|---|---|
committer | Anton Altaparmakov <aia21@cantab.net> | 2005-10-17 10:00:34 -0400 |
commit | 7946ada30bc45546cefc85809ba0fd07879eff52 (patch) | |
tree | 03c382e8e4f9b81f151be953de3b7f61411c9303 /arch | |
parent | 98b270362bb9ea6629732e7f5b65b8a6ce4743c7 (diff) | |
parent | 3d80636a0d5f056ffc26472d05b6027a7a9f6e1c (diff) |
Merge branch 'master' of /usr/src/ntfs-2.6/
Diffstat (limited to 'arch')
53 files changed, 1020 insertions, 1080 deletions
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 7779f2d1acad..299bc0468702 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile | |||
@@ -53,7 +53,7 @@ tune-$(CONFIG_CPU_ARM926T) :=-mtune=arm9tdmi | |||
53 | tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 | 53 | tune-$(CONFIG_CPU_SA110) :=-mtune=strongarm110 |
54 | tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 | 54 | tune-$(CONFIG_CPU_SA1100) :=-mtune=strongarm1100 |
55 | tune-$(CONFIG_CPU_XSCALE) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale | 55 | tune-$(CONFIG_CPU_XSCALE) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110) -Wa,-mcpu=xscale |
56 | tune-$(CONFIG_CPU_V6) :=-mtune=strongarm | 56 | tune-$(CONFIG_CPU_V6) :=$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm) |
57 | 57 | ||
58 | # Need -Uarm for gcc < 3.x | 58 | # Need -Uarm for gcc < 3.x |
59 | CFLAGS_ABI :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,) | 59 | CFLAGS_ABI :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,) |
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index 835d450797a1..7b17a87a3311 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c | |||
@@ -45,8 +45,8 @@ extern void fp_enter(void); | |||
45 | 45 | ||
46 | #define EXPORT_SYMBOL_ALIAS(sym,orig) \ | 46 | #define EXPORT_SYMBOL_ALIAS(sym,orig) \ |
47 | EXPORT_CRC_ALIAS(sym) \ | 47 | EXPORT_CRC_ALIAS(sym) \ |
48 | const struct kernel_symbol __ksymtab_##sym \ | 48 | static const struct kernel_symbol __ksymtab_##sym \ |
49 | __attribute__((section("__ksymtab"))) = \ | 49 | __attribute_used__ __attribute__((section("__ksymtab"))) = \ |
50 | { (unsigned long)&orig, #sym }; | 50 | { (unsigned long)&orig, #sym }; |
51 | 51 | ||
52 | /* | 52 | /* |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 81d450ac3fab..066597f4345a 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -106,15 +106,10 @@ ENTRY(ret_from_fork) | |||
106 | .endm | 106 | .endm |
107 | 107 | ||
108 | .Larm700bug: | 108 | .Larm700bug: |
109 | ldr r0, [sp, #S_PSR] @ Get calling cpsr | ||
110 | sub lr, lr, #4 | ||
111 | str lr, [r8] | ||
112 | msr spsr_cxsf, r0 | ||
113 | ldmia sp, {r0 - lr}^ @ Get calling r0 - lr | 109 | ldmia sp, {r0 - lr}^ @ Get calling r0 - lr |
114 | mov r0, r0 | 110 | mov r0, r0 |
115 | ldr lr, [sp, #S_PC] @ Get PC | ||
116 | add sp, sp, #S_FRAME_SIZE | 111 | add sp, sp, #S_FRAME_SIZE |
117 | movs pc, lr | 112 | subs pc, lr, #4 |
118 | #else | 113 | #else |
119 | .macro arm710_bug_check, instr, temp | 114 | .macro arm710_bug_check, instr, temp |
120 | .endm | 115 | .endm |
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S index 08e58ecd44be..0d5db5279c5c 100644 --- a/arch/arm/kernel/vmlinux.lds.S +++ b/arch/arm/kernel/vmlinux.lds.S | |||
@@ -89,13 +89,6 @@ SECTIONS | |||
89 | *(.got) /* Global offset table */ | 89 | *(.got) /* Global offset table */ |
90 | } | 90 | } |
91 | 91 | ||
92 | . = ALIGN(16); | ||
93 | __ex_table : { /* Exception table */ | ||
94 | __start___ex_table = .; | ||
95 | *(__ex_table) | ||
96 | __stop___ex_table = .; | ||
97 | } | ||
98 | |||
99 | RODATA | 92 | RODATA |
100 | 93 | ||
101 | _etext = .; /* End of text and rodata section */ | 94 | _etext = .; /* End of text and rodata section */ |
@@ -138,6 +131,14 @@ SECTIONS | |||
138 | *(.data.cacheline_aligned) | 131 | *(.data.cacheline_aligned) |
139 | 132 | ||
140 | /* | 133 | /* |
134 | * The exception fixup table (might need resorting at runtime) | ||
135 | */ | ||
136 | . = ALIGN(32); | ||
137 | __start___ex_table = .; | ||
138 | *(__ex_table) | ||
139 | __stop___ex_table = .; | ||
140 | |||
141 | /* | ||
141 | * and the usual data section | 142 | * and the usual data section |
142 | */ | 143 | */ |
143 | *(.data) | 144 | *(.data) |
diff --git a/arch/arm/mach-l7200/core.c b/arch/arm/mach-l7200/core.c index 5fd8c9f97f9a..03ed742ae2be 100644 --- a/arch/arm/mach-l7200/core.c +++ b/arch/arm/mach-l7200/core.c | |||
@@ -7,11 +7,17 @@ | |||
7 | */ | 7 | */ |
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
9 | #include <linux/init.h> | 9 | #include <linux/init.h> |
10 | #include <linux/device.h> | ||
10 | 11 | ||
12 | #include <asm/types.h> | ||
13 | #include <asm/irq.h> | ||
14 | #include <asm/mach-types.h> | ||
11 | #include <asm/hardware.h> | 15 | #include <asm/hardware.h> |
12 | #include <asm/page.h> | 16 | #include <asm/page.h> |
13 | 17 | ||
18 | #include <asm/mach/arch.h> | ||
14 | #include <asm/mach/map.h> | 19 | #include <asm/mach/map.h> |
20 | #include <asm/mach/irq.h> | ||
15 | 21 | ||
16 | /* | 22 | /* |
17 | * IRQ base register | 23 | * IRQ base register |
@@ -47,6 +53,12 @@ static void l7200_unmask_irq(unsigned int irq) | |||
47 | { | 53 | { |
48 | IRQ_ENABLE = 1 << irq; | 54 | IRQ_ENABLE = 1 << irq; |
49 | } | 55 | } |
56 | |||
57 | static struct irqchip l7200_irq_chip = { | ||
58 | .ack = l7200_mask_irq, | ||
59 | .mask = l7200_mask_irq, | ||
60 | .unmask = l7200_unmask_irq | ||
61 | }; | ||
50 | 62 | ||
51 | static void __init l7200_init_irq(void) | 63 | static void __init l7200_init_irq(void) |
52 | { | 64 | { |
@@ -56,11 +68,9 @@ static void __init l7200_init_irq(void) | |||
56 | FIQ_ENABLECLEAR = 0xffffffff; /* clear all fast interrupt enables */ | 68 | FIQ_ENABLECLEAR = 0xffffffff; /* clear all fast interrupt enables */ |
57 | 69 | ||
58 | for (irq = 0; irq < NR_IRQS; irq++) { | 70 | for (irq = 0; irq < NR_IRQS; irq++) { |
59 | irq_desc[irq].valid = 1; | 71 | set_irq_chip(irq, &l7200_irq_chip); |
60 | irq_desc[irq].probe_ok = 1; | 72 | set_irq_flags(irq, IRQF_VALID); |
61 | irq_desc[irq].mask_ack = l7200_mask_irq; | 73 | set_irq_handler(irq, do_level_IRQ); |
62 | irq_desc[irq].mask = l7200_mask_irq; | ||
63 | irq_desc[irq].unmask = l7200_unmask_irq; | ||
64 | } | 74 | } |
65 | 75 | ||
66 | init_FIQ(); | 76 | init_FIQ(); |
diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c index c02ef7c0f7ef..850538fadece 100644 --- a/arch/arm/mach-pxa/corgi_lcd.c +++ b/arch/arm/mach-pxa/corgi_lcd.c | |||
@@ -467,6 +467,7 @@ void corgi_put_hsync(void) | |||
467 | { | 467 | { |
468 | if (get_hsync_time) | 468 | if (get_hsync_time) |
469 | symbol_put(w100fb_get_hsynclen); | 469 | symbol_put(w100fb_get_hsynclen); |
470 | get_hsync_time = NULL; | ||
470 | } | 471 | } |
471 | 472 | ||
472 | void corgi_wait_hsync(void) | 473 | void corgi_wait_hsync(void) |
@@ -476,20 +477,37 @@ void corgi_wait_hsync(void) | |||
476 | #endif | 477 | #endif |
477 | 478 | ||
478 | #ifdef CONFIG_PXA_SHARP_Cxx00 | 479 | #ifdef CONFIG_PXA_SHARP_Cxx00 |
480 | static struct device *spitz_pxafb_dev; | ||
481 | |||
482 | static int is_pxafb_device(struct device * dev, void * data) | ||
483 | { | ||
484 | struct platform_device *pdev = container_of(dev, struct platform_device, dev); | ||
485 | |||
486 | return (strncmp(pdev->name, "pxa2xx-fb", 9) == 0); | ||
487 | } | ||
488 | |||
479 | unsigned long spitz_get_hsync_len(void) | 489 | unsigned long spitz_get_hsync_len(void) |
480 | { | 490 | { |
491 | if (!spitz_pxafb_dev) { | ||
492 | spitz_pxafb_dev = bus_find_device(&platform_bus_type, NULL, NULL, is_pxafb_device); | ||
493 | if (!spitz_pxafb_dev) | ||
494 | return 0; | ||
495 | } | ||
481 | if (!get_hsync_time) | 496 | if (!get_hsync_time) |
482 | get_hsync_time = symbol_get(pxafb_get_hsync_time); | 497 | get_hsync_time = symbol_get(pxafb_get_hsync_time); |
483 | if (!get_hsync_time) | 498 | if (!get_hsync_time) |
484 | return 0; | 499 | return 0; |
485 | 500 | ||
486 | return pxafb_get_hsync_time(&pxafb_device.dev); | 501 | return pxafb_get_hsync_time(spitz_pxafb_dev); |
487 | } | 502 | } |
488 | 503 | ||
489 | void spitz_put_hsync(void) | 504 | void spitz_put_hsync(void) |
490 | { | 505 | { |
506 | put_device(spitz_pxafb_dev); | ||
491 | if (get_hsync_time) | 507 | if (get_hsync_time) |
492 | symbol_put(pxafb_get_hsync_time); | 508 | symbol_put(pxafb_get_hsync_time); |
509 | spitz_pxafb_dev = NULL; | ||
510 | get_hsync_time = NULL; | ||
493 | } | 511 | } |
494 | 512 | ||
495 | void spitz_wait_hsync(void) | 513 | void spitz_wait_hsync(void) |
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index d0660a8c4b70..d327c127eddb 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c | |||
@@ -208,6 +208,11 @@ static struct platform_device pxafb_device = { | |||
208 | .resource = pxafb_resources, | 208 | .resource = pxafb_resources, |
209 | }; | 209 | }; |
210 | 210 | ||
211 | void __init set_pxa_fb_parent(struct device *parent_dev) | ||
212 | { | ||
213 | pxafb_device.dev.parent = parent_dev; | ||
214 | } | ||
215 | |||
211 | static struct platform_device ffuart_device = { | 216 | static struct platform_device ffuart_device = { |
212 | .name = "pxa2xx-uart", | 217 | .name = "pxa2xx-uart", |
213 | .id = 0, | 218 | .id = 0, |
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 568afe3d6e1a..d0ab428c2d7d 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <asm/arch/irq.h> | 36 | #include <asm/arch/irq.h> |
37 | #include <asm/arch/mmc.h> | 37 | #include <asm/arch/mmc.h> |
38 | #include <asm/arch/udc.h> | 38 | #include <asm/arch/udc.h> |
39 | #include <asm/arch/ohci.h> | ||
40 | #include <asm/arch/pxafb.h> | 39 | #include <asm/arch/pxafb.h> |
41 | #include <asm/arch/akita.h> | 40 | #include <asm/arch/akita.h> |
42 | #include <asm/arch/spitz.h> | 41 | #include <asm/arch/spitz.h> |
@@ -304,7 +303,6 @@ static struct platform_device *devices[] __initdata = { | |||
304 | &spitzkbd_device, | 303 | &spitzkbd_device, |
305 | &spitzts_device, | 304 | &spitzts_device, |
306 | &spitzbl_device, | 305 | &spitzbl_device, |
307 | &spitzbattery_device, | ||
308 | }; | 306 | }; |
309 | 307 | ||
310 | static void __init common_init(void) | 308 | static void __init common_init(void) |
@@ -328,7 +326,7 @@ static void __init common_init(void) | |||
328 | 326 | ||
329 | platform_add_devices(devices, ARRAY_SIZE(devices)); | 327 | platform_add_devices(devices, ARRAY_SIZE(devices)); |
330 | pxa_set_mci_info(&spitz_mci_platform_data); | 328 | pxa_set_mci_info(&spitz_mci_platform_data); |
331 | pxafb_device.dev.parent = &spitzssp_device.dev; | 329 | set_pxa_fb_parent(&spitzssp_device.dev); |
332 | set_pxa_fb_info(&spitz_pxafb_info); | 330 | set_pxa_fb_info(&spitz_pxafb_info); |
333 | } | 331 | } |
334 | 332 | ||
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig index 06807c6ee68a..c796bcdd6158 100644 --- a/arch/arm/mach-s3c2410/Kconfig +++ b/arch/arm/mach-s3c2410/Kconfig | |||
@@ -12,6 +12,7 @@ config MACH_ANUBIS | |||
12 | config ARCH_BAST | 12 | config ARCH_BAST |
13 | bool "Simtec Electronics BAST (EB2410ITX)" | 13 | bool "Simtec Electronics BAST (EB2410ITX)" |
14 | select CPU_S3C2410 | 14 | select CPU_S3C2410 |
15 | select ISA | ||
15 | help | 16 | help |
16 | Say Y here if you are using the Simtec Electronics EB2410ITX | 17 | Say Y here if you are using the Simtec Electronics EB2410ITX |
17 | development board (also known as BAST) | 18 | development board (also known as BAST) |
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c index 7c05f27fe1d6..5ae80f4e3e67 100644 --- a/arch/arm/mach-s3c2410/mach-anubis.c +++ b/arch/arm/mach-s3c2410/mach-anubis.c | |||
@@ -125,7 +125,7 @@ static int external_map[] = { 2 }; | |||
125 | static int chip0_map[] = { 0 }; | 125 | static int chip0_map[] = { 0 }; |
126 | static int chip1_map[] = { 1 }; | 126 | static int chip1_map[] = { 1 }; |
127 | 127 | ||
128 | struct mtd_partition anubis_default_nand_part[] = { | 128 | static struct mtd_partition anubis_default_nand_part[] = { |
129 | [0] = { | 129 | [0] = { |
130 | .name = "Boot Agent", | 130 | .name = "Boot Agent", |
131 | .size = SZ_16K, | 131 | .size = SZ_16K, |
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c index ed1f07d7252f..8ca955984645 100644 --- a/arch/arm/mach-s3c2410/mach-bast.c +++ b/arch/arm/mach-s3c2410/mach-bast.c | |||
@@ -230,7 +230,7 @@ static int chip0_map[] = { 1 }; | |||
230 | static int chip1_map[] = { 2 }; | 230 | static int chip1_map[] = { 2 }; |
231 | static int chip2_map[] = { 3 }; | 231 | static int chip2_map[] = { 3 }; |
232 | 232 | ||
233 | struct mtd_partition bast_default_nand_part[] = { | 233 | static struct mtd_partition bast_default_nand_part[] = { |
234 | [0] = { | 234 | [0] = { |
235 | .name = "Boot Agent", | 235 | .name = "Boot Agent", |
236 | .size = SZ_16K, | 236 | .size = SZ_16K, |
@@ -340,7 +340,7 @@ static struct resource bast_dm9k_resource[] = { | |||
340 | * better IO routines can be written and tested | 340 | * better IO routines can be written and tested |
341 | */ | 341 | */ |
342 | 342 | ||
343 | struct dm9000_plat_data bast_dm9k_platdata = { | 343 | static struct dm9000_plat_data bast_dm9k_platdata = { |
344 | .flags = DM9000_PLATF_16BITONLY | 344 | .flags = DM9000_PLATF_16BITONLY |
345 | }; | 345 | }; |
346 | 346 | ||
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c index 663a7f98fc0b..46b259673c18 100644 --- a/arch/arm/mach-s3c2410/mach-vr1000.c +++ b/arch/arm/mach-s3c2410/mach-vr1000.c | |||
@@ -288,7 +288,7 @@ static struct resource vr1000_dm9k1_resource[] = { | |||
288 | * better IO routines can be written and tested | 288 | * better IO routines can be written and tested |
289 | */ | 289 | */ |
290 | 290 | ||
291 | struct dm9000_plat_data vr1000_dm9k_platdata = { | 291 | static struct dm9000_plat_data vr1000_dm9k_platdata = { |
292 | .flags = DM9000_PLATF_16BITONLY, | 292 | .flags = DM9000_PLATF_16BITONLY, |
293 | }; | 293 | }; |
294 | 294 | ||
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c index 0b88993dfd27..a8bf5ec82602 100644 --- a/arch/arm/mach-s3c2410/s3c2410.c +++ b/arch/arm/mach-s3c2410/s3c2410.c | |||
@@ -125,9 +125,6 @@ static struct platform_device *uart_devices[] __initdata = { | |||
125 | &s3c_uart2 | 125 | &s3c_uart2 |
126 | }; | 126 | }; |
127 | 127 | ||
128 | /* store our uart devices for the serial driver console */ | ||
129 | struct platform_device *s3c2410_uart_devices[3]; | ||
130 | |||
131 | static int s3c2410_uart_count = 0; | 128 | static int s3c2410_uart_count = 0; |
132 | 129 | ||
133 | /* uart registration process */ | 130 | /* uart registration process */ |
diff --git a/arch/arm/mach-s3c2410/s3c2440.c b/arch/arm/mach-s3c2410/s3c2440.c index d4c8281b55f6..833fa36bce05 100644 --- a/arch/arm/mach-s3c2410/s3c2440.c +++ b/arch/arm/mach-s3c2410/s3c2440.c | |||
@@ -151,7 +151,7 @@ void __init s3c2440_init_uarts(struct s3c2410_uartcfg *cfg, int no) | |||
151 | 151 | ||
152 | #ifdef CONFIG_PM | 152 | #ifdef CONFIG_PM |
153 | 153 | ||
154 | struct sleep_save s3c2440_sleep[] = { | 154 | static struct sleep_save s3c2440_sleep[] = { |
155 | SAVE_ITEM(S3C2440_DSC0), | 155 | SAVE_ITEM(S3C2440_DSC0), |
156 | SAVE_ITEM(S3C2440_DSC1), | 156 | SAVE_ITEM(S3C2440_DSC1), |
157 | SAVE_ITEM(S3C2440_GPJDAT), | 157 | SAVE_ITEM(S3C2440_GPJDAT), |
@@ -260,7 +260,7 @@ void __init s3c2440_init_clocks(int xtal) | |||
260 | * as a driver which may support both 2410 and 2440 may try and use it. | 260 | * as a driver which may support both 2410 and 2440 may try and use it. |
261 | */ | 261 | */ |
262 | 262 | ||
263 | int __init s3c2440_core_init(void) | 263 | static int __init s3c2440_core_init(void) |
264 | { | 264 | { |
265 | return sysdev_class_register(&s3c2440_sysclass); | 265 | return sysdev_class_register(&s3c2440_sysclass); |
266 | } | 266 | } |
diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c index c0acfb2ad790..8a00e3c3cd08 100644 --- a/arch/arm/mach-s3c2410/time.c +++ b/arch/arm/mach-s3c2410/time.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <asm/hardware/clock.h> | 38 | #include <asm/hardware/clock.h> |
39 | 39 | ||
40 | #include "clock.h" | 40 | #include "clock.h" |
41 | #include "cpu.h" | ||
41 | 42 | ||
42 | static unsigned long timer_startval; | 43 | static unsigned long timer_startval; |
43 | static unsigned long timer_usec_ticks; | 44 | static unsigned long timer_usec_ticks; |
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c index f35e69e9c65c..705c98921c37 100644 --- a/arch/arm/mm/alignment.c +++ b/arch/arm/mm/alignment.c | |||
@@ -111,7 +111,7 @@ proc_alignment_read(char *page, char **start, off_t off, int count, int *eof, | |||
111 | } | 111 | } |
112 | 112 | ||
113 | static int proc_alignment_write(struct file *file, const char __user *buffer, | 113 | static int proc_alignment_write(struct file *file, const char __user *buffer, |
114 | unsigned long count, void *data) | 114 | unsigned long count, void *data) |
115 | { | 115 | { |
116 | char mode; | 116 | char mode; |
117 | 117 | ||
@@ -119,7 +119,7 @@ static int proc_alignment_write(struct file *file, const char __user *buffer, | |||
119 | if (get_user(mode, buffer)) | 119 | if (get_user(mode, buffer)) |
120 | return -EFAULT; | 120 | return -EFAULT; |
121 | if (mode >= '0' && mode <= '5') | 121 | if (mode >= '0' && mode <= '5') |
122 | ai_usermode = mode - '0'; | 122 | ai_usermode = mode - '0'; |
123 | } | 123 | } |
124 | return count; | 124 | return count; |
125 | } | 125 | } |
@@ -262,7 +262,7 @@ union offset_union { | |||
262 | goto fault; \ | 262 | goto fault; \ |
263 | } while (0) | 263 | } while (0) |
264 | 264 | ||
265 | #define put32_unaligned_check(val,addr) \ | 265 | #define put32_unaligned_check(val,addr) \ |
266 | __put32_unaligned_check("strb", val, addr) | 266 | __put32_unaligned_check("strb", val, addr) |
267 | 267 | ||
268 | #define put32t_unaligned_check(val,addr) \ | 268 | #define put32t_unaligned_check(val,addr) \ |
@@ -306,19 +306,19 @@ do_alignment_ldrhstrh(unsigned long addr, unsigned long instr, struct pt_regs *r | |||
306 | return TYPE_LDST; | 306 | return TYPE_LDST; |
307 | 307 | ||
308 | user: | 308 | user: |
309 | if (LDST_L_BIT(instr)) { | 309 | if (LDST_L_BIT(instr)) { |
310 | unsigned long val; | 310 | unsigned long val; |
311 | get16t_unaligned_check(val, addr); | 311 | get16t_unaligned_check(val, addr); |
312 | 312 | ||
313 | /* signed half-word? */ | 313 | /* signed half-word? */ |
314 | if (instr & 0x40) | 314 | if (instr & 0x40) |
315 | val = (signed long)((signed short) val); | 315 | val = (signed long)((signed short) val); |
316 | 316 | ||
317 | regs->uregs[rd] = val; | 317 | regs->uregs[rd] = val; |
318 | } else | 318 | } else |
319 | put16t_unaligned_check(regs->uregs[rd], addr); | 319 | put16t_unaligned_check(regs->uregs[rd], addr); |
320 | 320 | ||
321 | return TYPE_LDST; | 321 | return TYPE_LDST; |
322 | 322 | ||
323 | fault: | 323 | fault: |
324 | return TYPE_FAULT; | 324 | return TYPE_FAULT; |
@@ -342,11 +342,11 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, | |||
342 | unsigned long val; | 342 | unsigned long val; |
343 | get32_unaligned_check(val, addr); | 343 | get32_unaligned_check(val, addr); |
344 | regs->uregs[rd] = val; | 344 | regs->uregs[rd] = val; |
345 | get32_unaligned_check(val, addr+4); | 345 | get32_unaligned_check(val, addr + 4); |
346 | regs->uregs[rd+1] = val; | 346 | regs->uregs[rd + 1] = val; |
347 | } else { | 347 | } else { |
348 | put32_unaligned_check(regs->uregs[rd], addr); | 348 | put32_unaligned_check(regs->uregs[rd], addr); |
349 | put32_unaligned_check(regs->uregs[rd+1], addr+4); | 349 | put32_unaligned_check(regs->uregs[rd + 1], addr + 4); |
350 | } | 350 | } |
351 | 351 | ||
352 | return TYPE_LDST; | 352 | return TYPE_LDST; |
@@ -356,11 +356,11 @@ do_alignment_ldrdstrd(unsigned long addr, unsigned long instr, | |||
356 | unsigned long val; | 356 | unsigned long val; |
357 | get32t_unaligned_check(val, addr); | 357 | get32t_unaligned_check(val, addr); |
358 | regs->uregs[rd] = val; | 358 | regs->uregs[rd] = val; |
359 | get32t_unaligned_check(val, addr+4); | 359 | get32t_unaligned_check(val, addr + 4); |
360 | regs->uregs[rd+1] = val; | 360 | regs->uregs[rd + 1] = val; |
361 | } else { | 361 | } else { |
362 | put32t_unaligned_check(regs->uregs[rd], addr); | 362 | put32t_unaligned_check(regs->uregs[rd], addr); |
363 | put32t_unaligned_check(regs->uregs[rd+1], addr+4); | 363 | put32t_unaligned_check(regs->uregs[rd + 1], addr + 4); |
364 | } | 364 | } |
365 | 365 | ||
366 | return TYPE_LDST; | 366 | return TYPE_LDST; |
@@ -443,7 +443,7 @@ do_alignment_ldmstm(unsigned long addr, unsigned long instr, struct pt_regs *reg | |||
443 | if (LDST_P_EQ_U(instr)) /* U = P */ | 443 | if (LDST_P_EQ_U(instr)) /* U = P */ |
444 | eaddr += 4; | 444 | eaddr += 4; |
445 | 445 | ||
446 | /* | 446 | /* |
447 | * For alignment faults on the ARM922T/ARM920T the MMU makes | 447 | * For alignment faults on the ARM922T/ARM920T the MMU makes |
448 | * the FSR (and hence addr) equal to the updated base address | 448 | * the FSR (and hence addr) equal to the updated base address |
449 | * of the multiple access rather than the restored value. | 449 | * of the multiple access rather than the restored value. |
@@ -570,7 +570,7 @@ thumb2arm(u16 tinstr) | |||
570 | /* 6.5.1 Format 3: */ | 570 | /* 6.5.1 Format 3: */ |
571 | case 0x4800 >> 11: /* 7.1.28 LDR(3) */ | 571 | case 0x4800 >> 11: /* 7.1.28 LDR(3) */ |
572 | /* NOTE: This case is not technically possible. We're | 572 | /* NOTE: This case is not technically possible. We're |
573 | * loading 32-bit memory data via PC relative | 573 | * loading 32-bit memory data via PC relative |
574 | * addressing mode. So we can and should eliminate | 574 | * addressing mode. So we can and should eliminate |
575 | * this case. But I'll leave it here for now. | 575 | * this case. But I'll leave it here for now. |
576 | */ | 576 | */ |
@@ -642,7 +642,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |||
642 | 642 | ||
643 | if (fault) { | 643 | if (fault) { |
644 | type = TYPE_FAULT; | 644 | type = TYPE_FAULT; |
645 | goto bad_or_fault; | 645 | goto bad_or_fault; |
646 | } | 646 | } |
647 | 647 | ||
648 | if (user_mode(regs)) | 648 | if (user_mode(regs)) |
diff --git a/arch/arm/nwfpe/fpa11.c b/arch/arm/nwfpe/fpa11.c index 7690f731ee87..7b3d74d73c80 100644 --- a/arch/arm/nwfpe/fpa11.c +++ b/arch/arm/nwfpe/fpa11.c | |||
@@ -31,11 +31,6 @@ | |||
31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
32 | #include <asm/system.h> | 32 | #include <asm/system.h> |
33 | 33 | ||
34 | /* forward declarations */ | ||
35 | unsigned int EmulateCPDO(const unsigned int); | ||
36 | unsigned int EmulateCPDT(const unsigned int); | ||
37 | unsigned int EmulateCPRT(const unsigned int); | ||
38 | |||
39 | /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ | 34 | /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ |
40 | static void resetFPA11(void) | 35 | static void resetFPA11(void) |
41 | { | 36 | { |
diff --git a/arch/arm/nwfpe/fpa11.h b/arch/arm/nwfpe/fpa11.h index 93523ae4b7a1..9677ae8448e8 100644 --- a/arch/arm/nwfpe/fpa11.h +++ b/arch/arm/nwfpe/fpa11.h | |||
@@ -95,4 +95,24 @@ extern int8 SetRoundingMode(const unsigned int); | |||
95 | extern int8 SetRoundingPrecision(const unsigned int); | 95 | extern int8 SetRoundingPrecision(const unsigned int); |
96 | extern void nwfpe_init_fpa(union fp_state *fp); | 96 | extern void nwfpe_init_fpa(union fp_state *fp); |
97 | 97 | ||
98 | extern unsigned int EmulateAll(unsigned int opcode); | ||
99 | |||
100 | extern unsigned int EmulateCPDT(const unsigned int opcode); | ||
101 | extern unsigned int EmulateCPDO(const unsigned int opcode); | ||
102 | extern unsigned int EmulateCPRT(const unsigned int opcode); | ||
103 | |||
104 | /* fpa11_cpdt.c */ | ||
105 | extern unsigned int PerformLDF(const unsigned int opcode); | ||
106 | extern unsigned int PerformSTF(const unsigned int opcode); | ||
107 | extern unsigned int PerformLFM(const unsigned int opcode); | ||
108 | extern unsigned int PerformSFM(const unsigned int opcode); | ||
109 | |||
110 | /* single_cpdo.c */ | ||
111 | |||
112 | extern unsigned int SingleCPDO(struct roundingData *roundData, | ||
113 | const unsigned int opcode, FPREG * rFd); | ||
114 | /* double_cpdo.c */ | ||
115 | extern unsigned int DoubleCPDO(struct roundingData *roundData, | ||
116 | const unsigned int opcode, FPREG * rFd); | ||
117 | |||
98 | #endif | 118 | #endif |
diff --git a/arch/arm/nwfpe/fpa11_cprt.c b/arch/arm/nwfpe/fpa11_cprt.c index adf8d3000540..7c67023655e4 100644 --- a/arch/arm/nwfpe/fpa11_cprt.c +++ b/arch/arm/nwfpe/fpa11_cprt.c | |||
@@ -26,12 +26,11 @@ | |||
26 | #include "fpa11.inl" | 26 | #include "fpa11.inl" |
27 | #include "fpmodule.h" | 27 | #include "fpmodule.h" |
28 | #include "fpmodule.inl" | 28 | #include "fpmodule.inl" |
29 | #include "softfloat.h" | ||
29 | 30 | ||
30 | #ifdef CONFIG_FPE_NWFPE_XP | 31 | #ifdef CONFIG_FPE_NWFPE_XP |
31 | extern flag floatx80_is_nan(floatx80); | 32 | extern flag floatx80_is_nan(floatx80); |
32 | #endif | 33 | #endif |
33 | extern flag float64_is_nan(float64); | ||
34 | extern flag float32_is_nan(float32); | ||
35 | 34 | ||
36 | unsigned int PerformFLT(const unsigned int opcode); | 35 | unsigned int PerformFLT(const unsigned int opcode); |
37 | unsigned int PerformFIX(const unsigned int opcode); | 36 | unsigned int PerformFIX(const unsigned int opcode); |
diff --git a/arch/arm/nwfpe/fpopcode.h b/arch/arm/nwfpe/fpopcode.h index 1777e92a88e6..6528e081c83f 100644 --- a/arch/arm/nwfpe/fpopcode.h +++ b/arch/arm/nwfpe/fpopcode.h | |||
@@ -476,4 +476,10 @@ static inline unsigned int getDestinationSize(const unsigned int opcode) | |||
476 | return (nRc); | 476 | return (nRc); |
477 | } | 477 | } |
478 | 478 | ||
479 | extern unsigned int checkCondition(const unsigned int opcode, | ||
480 | const unsigned int ccodes); | ||
481 | |||
482 | extern const float64 float64Constant[]; | ||
483 | extern const float32 float32Constant[]; | ||
484 | |||
479 | #endif | 485 | #endif |
diff --git a/arch/arm/nwfpe/softfloat.h b/arch/arm/nwfpe/softfloat.h index 1c8799b9ee4d..14151700b6b2 100644 --- a/arch/arm/nwfpe/softfloat.h +++ b/arch/arm/nwfpe/softfloat.h | |||
@@ -265,4 +265,7 @@ static inline flag float64_lt_nocheck(float64 a, float64 b) | |||
265 | return (a != b) && (aSign ^ (a < b)); | 265 | return (a != b) && (aSign ^ (a < b)); |
266 | } | 266 | } |
267 | 267 | ||
268 | extern flag float32_is_nan( float32 a ); | ||
269 | extern flag float64_is_nan( float64 a ); | ||
270 | |||
268 | #endif | 271 | #endif |
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c index 2c5cae04a95c..957f551ba5ce 100644 --- a/arch/cris/arch-v32/kernel/smp.c +++ b/arch/cris/arch-v32/kernel/smp.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/cpumask.h> | 16 | #include <linux/cpumask.h> |
17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
18 | #include <linux/module.h> | ||
18 | 19 | ||
19 | #define IPI_SCHEDULE 1 | 20 | #define IPI_SCHEDULE 1 |
20 | #define IPI_CALL 2 | 21 | #define IPI_CALL 2 |
@@ -28,6 +29,7 @@ spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = SPIN_LOCK_UNLOCKED}; | |||
28 | /* CPU masks */ | 29 | /* CPU masks */ |
29 | cpumask_t cpu_online_map = CPU_MASK_NONE; | 30 | cpumask_t cpu_online_map = CPU_MASK_NONE; |
30 | cpumask_t phys_cpu_present_map = CPU_MASK_NONE; | 31 | cpumask_t phys_cpu_present_map = CPU_MASK_NONE; |
32 | EXPORT_SYMBOL(phys_cpu_present_map); | ||
31 | 33 | ||
32 | /* Variables used during SMP boot */ | 34 | /* Variables used during SMP boot */ |
33 | volatile int cpu_now_booting = 0; | 35 | volatile int cpu_now_booting = 0; |
diff --git a/arch/m32r/kernel/entry.S b/arch/m32r/kernel/entry.S index dddbf6b5ed2c..85920fb8d08c 100644 --- a/arch/m32r/kernel/entry.S +++ b/arch/m32r/kernel/entry.S | |||
@@ -681,6 +681,15 @@ ENTRY(debug_trap) | |||
681 | bl do_debug_trap | 681 | bl do_debug_trap |
682 | bra error_code | 682 | bra error_code |
683 | 683 | ||
684 | ENTRY(ill_trap) | ||
685 | /* void ill_trap(void) */ | ||
686 | SWITCH_TO_KERNEL_STACK | ||
687 | SAVE_ALL | ||
688 | ldi r1, #0 ; error_code ; FIXME | ||
689 | mv r0, sp ; pt_regs | ||
690 | bl do_ill_trap | ||
691 | bra error_code | ||
692 | |||
684 | 693 | ||
685 | /* Cache flushing handler */ | 694 | /* Cache flushing handler */ |
686 | ENTRY(cache_flushing_handler) | 695 | ENTRY(cache_flushing_handler) |
diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c index a4576ac7e870..8b1f6eb76870 100644 --- a/arch/m32r/kernel/smp.c +++ b/arch/m32r/kernel/smp.c | |||
@@ -275,12 +275,14 @@ static void flush_tlb_all_ipi(void *info) | |||
275 | *==========================================================================*/ | 275 | *==========================================================================*/ |
276 | void smp_flush_tlb_mm(struct mm_struct *mm) | 276 | void smp_flush_tlb_mm(struct mm_struct *mm) |
277 | { | 277 | { |
278 | int cpu_id = smp_processor_id(); | 278 | int cpu_id; |
279 | cpumask_t cpu_mask; | 279 | cpumask_t cpu_mask; |
280 | unsigned long *mmc = &mm->context[cpu_id]; | 280 | unsigned long *mmc; |
281 | unsigned long flags; | 281 | unsigned long flags; |
282 | 282 | ||
283 | preempt_disable(); | 283 | preempt_disable(); |
284 | cpu_id = smp_processor_id(); | ||
285 | mmc = &mm->context[cpu_id]; | ||
284 | cpu_mask = mm->cpu_vm_mask; | 286 | cpu_mask = mm->cpu_vm_mask; |
285 | cpu_clear(cpu_id, cpu_mask); | 287 | cpu_clear(cpu_id, cpu_mask); |
286 | 288 | ||
@@ -343,12 +345,14 @@ void smp_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, | |||
343 | void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va) | 345 | void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long va) |
344 | { | 346 | { |
345 | struct mm_struct *mm = vma->vm_mm; | 347 | struct mm_struct *mm = vma->vm_mm; |
346 | int cpu_id = smp_processor_id(); | 348 | int cpu_id; |
347 | cpumask_t cpu_mask; | 349 | cpumask_t cpu_mask; |
348 | unsigned long *mmc = &mm->context[cpu_id]; | 350 | unsigned long *mmc; |
349 | unsigned long flags; | 351 | unsigned long flags; |
350 | 352 | ||
351 | preempt_disable(); | 353 | preempt_disable(); |
354 | cpu_id = smp_processor_id(); | ||
355 | mmc = &mm->context[cpu_id]; | ||
352 | cpu_mask = mm->cpu_vm_mask; | 356 | cpu_mask = mm->cpu_vm_mask; |
353 | cpu_clear(cpu_id, cpu_mask); | 357 | cpu_clear(cpu_id, cpu_mask); |
354 | 358 | ||
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c index 01922271d17e..5fe8ed6d62dc 100644 --- a/arch/m32r/kernel/traps.c +++ b/arch/m32r/kernel/traps.c | |||
@@ -5,8 +5,6 @@ | |||
5 | * Hitoshi Yamamoto | 5 | * Hitoshi Yamamoto |
6 | */ | 6 | */ |
7 | 7 | ||
8 | /* $Id$ */ | ||
9 | |||
10 | /* | 8 | /* |
11 | * 'traps.c' handles hardware traps and faults after we have saved some | 9 | * 'traps.c' handles hardware traps and faults after we have saved some |
12 | * state in 'entry.S'. | 10 | * state in 'entry.S'. |
@@ -35,6 +33,7 @@ asmlinkage void ei_handler(void); | |||
35 | asmlinkage void rie_handler(void); | 33 | asmlinkage void rie_handler(void); |
36 | asmlinkage void debug_trap(void); | 34 | asmlinkage void debug_trap(void); |
37 | asmlinkage void cache_flushing_handler(void); | 35 | asmlinkage void cache_flushing_handler(void); |
36 | asmlinkage void ill_trap(void); | ||
38 | 37 | ||
39 | #ifdef CONFIG_SMP | 38 | #ifdef CONFIG_SMP |
40 | extern void smp_reschedule_interrupt(void); | 39 | extern void smp_reschedule_interrupt(void); |
@@ -77,22 +76,22 @@ void set_eit_vector_entries(void) | |||
77 | eit_vector[5] = BRA_INSN(default_eit_handler, 5); | 76 | eit_vector[5] = BRA_INSN(default_eit_handler, 5); |
78 | eit_vector[8] = BRA_INSN(rie_handler, 8); | 77 | eit_vector[8] = BRA_INSN(rie_handler, 8); |
79 | eit_vector[12] = BRA_INSN(alignment_check, 12); | 78 | eit_vector[12] = BRA_INSN(alignment_check, 12); |
80 | eit_vector[16] = 0xff000000UL; | 79 | eit_vector[16] = BRA_INSN(ill_trap, 16); |
81 | eit_vector[17] = BRA_INSN(debug_trap, 17); | 80 | eit_vector[17] = BRA_INSN(debug_trap, 17); |
82 | eit_vector[18] = BRA_INSN(system_call, 18); | 81 | eit_vector[18] = BRA_INSN(system_call, 18); |
83 | eit_vector[19] = 0xff000000UL; | 82 | eit_vector[19] = BRA_INSN(ill_trap, 19); |
84 | eit_vector[20] = 0xff000000UL; | 83 | eit_vector[20] = BRA_INSN(ill_trap, 20); |
85 | eit_vector[21] = 0xff000000UL; | 84 | eit_vector[21] = BRA_INSN(ill_trap, 21); |
86 | eit_vector[22] = 0xff000000UL; | 85 | eit_vector[22] = BRA_INSN(ill_trap, 22); |
87 | eit_vector[23] = 0xff000000UL; | 86 | eit_vector[23] = BRA_INSN(ill_trap, 23); |
88 | eit_vector[24] = 0xff000000UL; | 87 | eit_vector[24] = BRA_INSN(ill_trap, 24); |
89 | eit_vector[25] = 0xff000000UL; | 88 | eit_vector[25] = BRA_INSN(ill_trap, 25); |
90 | eit_vector[26] = 0xff000000UL; | 89 | eit_vector[26] = BRA_INSN(ill_trap, 26); |
91 | eit_vector[27] = 0xff000000UL; | 90 | eit_vector[27] = BRA_INSN(ill_trap, 27); |
92 | eit_vector[28] = BRA_INSN(cache_flushing_handler, 28); | 91 | eit_vector[28] = BRA_INSN(cache_flushing_handler, 28); |
93 | eit_vector[29] = 0xff000000UL; | 92 | eit_vector[29] = BRA_INSN(ill_trap, 29); |
94 | eit_vector[30] = 0xff000000UL; | 93 | eit_vector[30] = BRA_INSN(ill_trap, 30); |
95 | eit_vector[31] = 0xff000000UL; | 94 | eit_vector[31] = BRA_INSN(ill_trap, 31); |
96 | eit_vector[32] = BRA_INSN(ei_handler, 32); | 95 | eit_vector[32] = BRA_INSN(ei_handler, 32); |
97 | eit_vector[64] = BRA_INSN(pie_handler, 64); | 96 | eit_vector[64] = BRA_INSN(pie_handler, 64); |
98 | #ifdef CONFIG_MMU | 97 | #ifdef CONFIG_MMU |
@@ -286,7 +285,8 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ | |||
286 | 285 | ||
287 | DO_ERROR( 1, SIGTRAP, "debug trap", debug_trap) | 286 | DO_ERROR( 1, SIGTRAP, "debug trap", debug_trap) |
288 | DO_ERROR_INFO(0x20, SIGILL, "reserved instruction ", rie_handler, ILL_ILLOPC, regs->bpc) | 287 | DO_ERROR_INFO(0x20, SIGILL, "reserved instruction ", rie_handler, ILL_ILLOPC, regs->bpc) |
289 | DO_ERROR_INFO(0x100, SIGILL, "privilege instruction", pie_handler, ILL_PRVOPC, regs->bpc) | 288 | DO_ERROR_INFO(0x100, SIGILL, "privileged instruction", pie_handler, ILL_PRVOPC, regs->bpc) |
289 | DO_ERROR_INFO(-1, SIGILL, "illegal trap", ill_trap, ILL_ILLTRP, regs->bpc) | ||
290 | 290 | ||
291 | extern int handle_unaligned_access(unsigned long, struct pt_regs *); | 291 | extern int handle_unaligned_access(unsigned long, struct pt_regs *); |
292 | 292 | ||
@@ -329,4 +329,3 @@ asmlinkage void do_alignment_check(struct pt_regs *regs, long error_code) | |||
329 | set_fs(oldfs); | 329 | set_fs(oldfs); |
330 | } | 330 | } |
331 | } | 331 | } |
332 | |||
diff --git a/arch/mips/pci/fixup-tb0226.c b/arch/mips/pci/fixup-tb0226.c index 61513d5d97da..b5d42b12de10 100644 --- a/arch/mips/pci/fixup-tb0226.c +++ b/arch/mips/pci/fixup-tb0226.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fixup-tb0226.c, The TANBAC TB0226 specific PCI fixups. | 2 | * fixup-tb0226.c, The TANBAC TB0226 specific PCI fixups. |
3 | * | 3 | * |
4 | * Copyright (C) 2002-2004 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> | 4 | * Copyright (C) 2002-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
22 | 22 | ||
23 | #include <asm/vr41xx/giu.h> | ||
23 | #include <asm/vr41xx/tb0226.h> | 24 | #include <asm/vr41xx/tb0226.h> |
24 | 25 | ||
25 | int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | 26 | int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) |
@@ -29,42 +30,42 @@ int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | |||
29 | switch (slot) { | 30 | switch (slot) { |
30 | case 12: | 31 | case 12: |
31 | vr41xx_set_irq_trigger(GD82559_1_PIN, | 32 | vr41xx_set_irq_trigger(GD82559_1_PIN, |
32 | TRIGGER_LEVEL, | 33 | IRQ_TRIGGER_LEVEL, |
33 | SIGNAL_THROUGH); | 34 | IRQ_SIGNAL_THROUGH); |
34 | vr41xx_set_irq_level(GD82559_1_PIN, LEVEL_LOW); | 35 | vr41xx_set_irq_level(GD82559_1_PIN, IRQ_LEVEL_LOW); |
35 | irq = GD82559_1_IRQ; | 36 | irq = GD82559_1_IRQ; |
36 | break; | 37 | break; |
37 | case 13: | 38 | case 13: |
38 | vr41xx_set_irq_trigger(GD82559_2_PIN, | 39 | vr41xx_set_irq_trigger(GD82559_2_PIN, |
39 | TRIGGER_LEVEL, | 40 | IRQ_TRIGGER_LEVEL, |
40 | SIGNAL_THROUGH); | 41 | IRQ_SIGNAL_THROUGH); |
41 | vr41xx_set_irq_level(GD82559_2_PIN, LEVEL_LOW); | 42 | vr41xx_set_irq_level(GD82559_2_PIN, IRQ_LEVEL_LOW); |
42 | irq = GD82559_2_IRQ; | 43 | irq = GD82559_2_IRQ; |
43 | break; | 44 | break; |
44 | case 14: | 45 | case 14: |
45 | switch (pin) { | 46 | switch (pin) { |
46 | case 1: | 47 | case 1: |
47 | vr41xx_set_irq_trigger(UPD720100_INTA_PIN, | 48 | vr41xx_set_irq_trigger(UPD720100_INTA_PIN, |
48 | TRIGGER_LEVEL, | 49 | IRQ_TRIGGER_LEVEL, |
49 | SIGNAL_THROUGH); | 50 | IRQ_SIGNAL_THROUGH); |
50 | vr41xx_set_irq_level(UPD720100_INTA_PIN, | 51 | vr41xx_set_irq_level(UPD720100_INTA_PIN, |
51 | LEVEL_LOW); | 52 | IRQ_LEVEL_LOW); |
52 | irq = UPD720100_INTA_IRQ; | 53 | irq = UPD720100_INTA_IRQ; |
53 | break; | 54 | break; |
54 | case 2: | 55 | case 2: |
55 | vr41xx_set_irq_trigger(UPD720100_INTB_PIN, | 56 | vr41xx_set_irq_trigger(UPD720100_INTB_PIN, |
56 | TRIGGER_LEVEL, | 57 | IRQ_TRIGGER_LEVEL, |
57 | SIGNAL_THROUGH); | 58 | IRQ_SIGNAL_THROUGH); |
58 | vr41xx_set_irq_level(UPD720100_INTB_PIN, | 59 | vr41xx_set_irq_level(UPD720100_INTB_PIN, |
59 | LEVEL_LOW); | 60 | IRQ_LEVEL_LOW); |
60 | irq = UPD720100_INTB_IRQ; | 61 | irq = UPD720100_INTB_IRQ; |
61 | break; | 62 | break; |
62 | case 3: | 63 | case 3: |
63 | vr41xx_set_irq_trigger(UPD720100_INTC_PIN, | 64 | vr41xx_set_irq_trigger(UPD720100_INTC_PIN, |
64 | TRIGGER_LEVEL, | 65 | IRQ_TRIGGER_LEVEL, |
65 | SIGNAL_THROUGH); | 66 | IRQ_SIGNAL_THROUGH); |
66 | vr41xx_set_irq_level(UPD720100_INTC_PIN, | 67 | vr41xx_set_irq_level(UPD720100_INTC_PIN, |
67 | LEVEL_LOW); | 68 | IRQ_LEVEL_LOW); |
68 | irq = UPD720100_INTC_IRQ; | 69 | irq = UPD720100_INTC_IRQ; |
69 | break; | 70 | break; |
70 | default: | 71 | default: |
diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c index 546e1ea4cafa..6b76cf58d9e0 100644 --- a/arch/ppc/kernel/cputable.c +++ b/arch/ppc/kernel/cputable.c | |||
@@ -91,7 +91,7 @@ struct cpu_spec cpu_specs[] = { | |||
91 | .cpu_features = CPU_FTR_COMMON | CPU_FTR_601 | | 91 | .cpu_features = CPU_FTR_COMMON | CPU_FTR_601 | |
92 | CPU_FTR_HPTE_TABLE, | 92 | CPU_FTR_HPTE_TABLE, |
93 | .cpu_user_features = COMMON_PPC | PPC_FEATURE_601_INSTR | | 93 | .cpu_user_features = COMMON_PPC | PPC_FEATURE_601_INSTR | |
94 | PPC_FEATURE_UNIFIED_CACHE, | 94 | PPC_FEATURE_UNIFIED_CACHE | PPC_FEATURE_NO_TB, |
95 | .icache_bsize = 32, | 95 | .icache_bsize = 32, |
96 | .dcache_bsize = 32, | 96 | .dcache_bsize = 32, |
97 | .cpu_setup = __setup_cpu_601 | 97 | .cpu_setup = __setup_cpu_601 |
@@ -745,7 +745,8 @@ struct cpu_spec cpu_specs[] = { | |||
745 | .cpu_name = "403GCX", | 745 | .cpu_name = "403GCX", |
746 | .cpu_features = CPU_FTR_SPLIT_ID_CACHE | | 746 | .cpu_features = CPU_FTR_SPLIT_ID_CACHE | |
747 | CPU_FTR_USE_TB, | 747 | CPU_FTR_USE_TB, |
748 | .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, | 748 | .cpu_user_features = PPC_FEATURE_32 | |
749 | PPC_FEATURE_HAS_MMU | PPC_FEATURE_NO_TB, | ||
749 | .icache_bsize = 16, | 750 | .icache_bsize = 16, |
750 | .dcache_bsize = 16, | 751 | .dcache_bsize = 16, |
751 | }, | 752 | }, |
diff --git a/arch/ppc/kernel/dma-mapping.c b/arch/ppc/kernel/dma-mapping.c index b566d982806c..8edee806dae7 100644 --- a/arch/ppc/kernel/dma-mapping.c +++ b/arch/ppc/kernel/dma-mapping.c | |||
@@ -401,10 +401,10 @@ EXPORT_SYMBOL(__dma_sync); | |||
401 | static inline void __dma_sync_page_highmem(struct page *page, | 401 | static inline void __dma_sync_page_highmem(struct page *page, |
402 | unsigned long offset, size_t size, int direction) | 402 | unsigned long offset, size_t size, int direction) |
403 | { | 403 | { |
404 | size_t seg_size = min((size_t)PAGE_SIZE, size) - offset; | 404 | size_t seg_size = min((size_t)(PAGE_SIZE - offset), size); |
405 | size_t cur_size = seg_size; | 405 | size_t cur_size = seg_size; |
406 | unsigned long flags, start, seg_offset = offset; | 406 | unsigned long flags, start, seg_offset = offset; |
407 | int nr_segs = PAGE_ALIGN(size + (PAGE_SIZE - offset))/PAGE_SIZE; | 407 | int nr_segs = 1 + ((size - seg_size) + PAGE_SIZE - 1)/PAGE_SIZE; |
408 | int seg_nr = 0; | 408 | int seg_nr = 0; |
409 | 409 | ||
410 | local_irq_save(flags); | 410 | local_irq_save(flags); |
diff --git a/arch/ppc64/kernel/module.c b/arch/ppc64/kernel/module.c index c683bf88e690..928b8581fcb0 100644 --- a/arch/ppc64/kernel/module.c +++ b/arch/ppc64/kernel/module.c | |||
@@ -341,6 +341,19 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | |||
341 | *(unsigned long *)location = my_r2(sechdrs, me); | 341 | *(unsigned long *)location = my_r2(sechdrs, me); |
342 | break; | 342 | break; |
343 | 343 | ||
344 | case R_PPC64_TOC16: | ||
345 | /* Subtact TOC pointer */ | ||
346 | value -= my_r2(sechdrs, me); | ||
347 | if (value + 0x8000 > 0xffff) { | ||
348 | printk("%s: bad TOC16 relocation (%lu)\n", | ||
349 | me->name, value); | ||
350 | return -ENOEXEC; | ||
351 | } | ||
352 | *((uint16_t *) location) | ||
353 | = (*((uint16_t *) location) & ~0xffff) | ||
354 | | (value & 0xffff); | ||
355 | break; | ||
356 | |||
344 | case R_PPC64_TOC16_DS: | 357 | case R_PPC64_TOC16_DS: |
345 | /* Subtact TOC pointer */ | 358 | /* Subtact TOC pointer */ |
346 | value -= my_r2(sechdrs, me); | 359 | value -= my_r2(sechdrs, me); |
diff --git a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c index 1f5f141fb7a1..928f8febdb3b 100644 --- a/arch/ppc64/kernel/pSeries_pci.c +++ b/arch/ppc64/kernel/pSeries_pci.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | #include "pci.h" | 33 | #include "pci.h" |
34 | 34 | ||
35 | static int __initdata s7a_workaround = -1; | 35 | static int __devinitdata s7a_workaround = -1; |
36 | 36 | ||
37 | #if 0 | 37 | #if 0 |
38 | void pcibios_name_device(struct pci_dev *dev) | 38 | void pcibios_name_device(struct pci_dev *dev) |
@@ -60,7 +60,7 @@ void pcibios_name_device(struct pci_dev *dev) | |||
60 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device); | 60 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device); |
61 | #endif | 61 | #endif |
62 | 62 | ||
63 | static void __init check_s7a(void) | 63 | static void __devinit check_s7a(void) |
64 | { | 64 | { |
65 | struct device_node *root; | 65 | struct device_node *root; |
66 | char *model; | 66 | char *model; |
diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index 25755252067a..fa8121d53b89 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c | |||
@@ -115,7 +115,7 @@ static void __pmac pmac_show_cpuinfo(struct seq_file *m) | |||
115 | 115 | ||
116 | /* find motherboard type */ | 116 | /* find motherboard type */ |
117 | seq_printf(m, "machine\t\t: "); | 117 | seq_printf(m, "machine\t\t: "); |
118 | np = find_devices("device-tree"); | 118 | np = of_find_node_by_path("/"); |
119 | if (np != NULL) { | 119 | if (np != NULL) { |
120 | pp = (char *) get_property(np, "model", NULL); | 120 | pp = (char *) get_property(np, "model", NULL); |
121 | if (pp != NULL) | 121 | if (pp != NULL) |
@@ -133,6 +133,7 @@ static void __pmac pmac_show_cpuinfo(struct seq_file *m) | |||
133 | } | 133 | } |
134 | seq_printf(m, "\n"); | 134 | seq_printf(m, "\n"); |
135 | } | 135 | } |
136 | of_node_put(np); | ||
136 | } else | 137 | } else |
137 | seq_printf(m, "PowerMac\n"); | 138 | seq_printf(m, "PowerMac\n"); |
138 | 139 | ||
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c index 56a39d69e080..5ecefc02896a 100644 --- a/arch/sh/kernel/smp.c +++ b/arch/sh/kernel/smp.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/time.h> | 22 | #include <linux/time.h> |
23 | #include <linux/timex.h> | 23 | #include <linux/timex.h> |
24 | #include <linux/sched.h> | 24 | #include <linux/sched.h> |
25 | #include <linux/module.h> | ||
25 | 26 | ||
26 | #include <asm/atomic.h> | 27 | #include <asm/atomic.h> |
27 | #include <asm/processor.h> | 28 | #include <asm/processor.h> |
@@ -39,6 +40,8 @@ struct sh_cpuinfo cpu_data[NR_CPUS]; | |||
39 | extern void per_cpu_trap_init(void); | 40 | extern void per_cpu_trap_init(void); |
40 | 41 | ||
41 | cpumask_t cpu_possible_map; | 42 | cpumask_t cpu_possible_map; |
43 | EXPORT_SYMBOL(cpu_possible_map); | ||
44 | |||
42 | cpumask_t cpu_online_map; | 45 | cpumask_t cpu_online_map; |
43 | static atomic_t cpus_booted = ATOMIC_INIT(0); | 46 | static atomic_t cpus_booted = ATOMIC_INIT(0); |
44 | 47 | ||
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index f7c51b869049..6537445dac0e 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -21,10 +21,6 @@ config GENERIC_ISA_DMA | |||
21 | bool | 21 | bool |
22 | default y | 22 | default y |
23 | 23 | ||
24 | config GENERIC_IOMAP | ||
25 | bool | ||
26 | default y | ||
27 | |||
28 | source "init/Kconfig" | 24 | source "init/Kconfig" |
29 | 25 | ||
30 | menu "General machine setup" | 26 | menu "General machine setup" |
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index 8a3aef1e22f5..a69856263009 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig | |||
@@ -5,7 +5,6 @@ CONFIG_MMU=y | |||
5 | CONFIG_UID16=y | 5 | CONFIG_UID16=y |
6 | CONFIG_HIGHMEM=y | 6 | CONFIG_HIGHMEM=y |
7 | CONFIG_GENERIC_ISA_DMA=y | 7 | CONFIG_GENERIC_ISA_DMA=y |
8 | CONFIG_GENERIC_IOMAP=y | ||
9 | 8 | ||
10 | # | 9 | # |
11 | # Code maturity level options | 10 | # Code maturity level options |
diff --git a/arch/sparc64/kernel/dtlb_base.S b/arch/sparc64/kernel/dtlb_base.S index 702d349c1e88..6528786840c0 100644 --- a/arch/sparc64/kernel/dtlb_base.S +++ b/arch/sparc64/kernel/dtlb_base.S | |||
@@ -53,19 +53,18 @@ | |||
53 | * be guaranteed to be 0 ... mmu_context.h does guarantee this | 53 | * be guaranteed to be 0 ... mmu_context.h does guarantee this |
54 | * by only using 10 bits in the hwcontext value. | 54 | * by only using 10 bits in the hwcontext value. |
55 | */ | 55 | */ |
56 | #define CREATE_VPTE_OFFSET1(r1, r2) | 56 | #define CREATE_VPTE_OFFSET1(r1, r2) nop |
57 | #define CREATE_VPTE_OFFSET2(r1, r2) \ | 57 | #define CREATE_VPTE_OFFSET2(r1, r2) \ |
58 | srax r1, 10, r2 | 58 | srax r1, 10, r2 |
59 | #define CREATE_VPTE_NOP nop | ||
60 | #else | 59 | #else |
61 | #define CREATE_VPTE_OFFSET1(r1, r2) \ | 60 | #define CREATE_VPTE_OFFSET1(r1, r2) \ |
62 | srax r1, PAGE_SHIFT, r2 | 61 | srax r1, PAGE_SHIFT, r2 |
63 | #define CREATE_VPTE_OFFSET2(r1, r2) \ | 62 | #define CREATE_VPTE_OFFSET2(r1, r2) \ |
64 | sllx r2, 3, r2 | 63 | sllx r2, 3, r2 |
65 | #define CREATE_VPTE_NOP | ||
66 | #endif | 64 | #endif |
67 | 65 | ||
68 | /* DTLB ** ICACHE line 1: Quick user TLB misses */ | 66 | /* DTLB ** ICACHE line 1: Quick user TLB misses */ |
67 | mov TLB_SFSR, %g1 | ||
69 | ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS | 68 | ldxa [%g1 + %g1] ASI_DMMU, %g4 ! Get TAG_ACCESS |
70 | andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus? | 69 | andcc %g4, TAG_CONTEXT_BITS, %g0 ! From Nucleus? |
71 | from_tl1_trap: | 70 | from_tl1_trap: |
@@ -74,18 +73,16 @@ from_tl1_trap: | |||
74 | be,pn %xcc, kvmap ! Yep, special processing | 73 | be,pn %xcc, kvmap ! Yep, special processing |
75 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset | 74 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset |
76 | cmp %g5, 4 ! Last trap level? | 75 | cmp %g5, 4 ! Last trap level? |
77 | be,pn %xcc, longpath ! Yep, cannot risk VPTE miss | ||
78 | nop ! delay slot | ||
79 | 76 | ||
80 | /* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses */ | 77 | /* DTLB ** ICACHE line 2: User finish + quick kernel TLB misses */ |
78 | be,pn %xcc, longpath ! Yep, cannot risk VPTE miss | ||
79 | nop ! delay slot | ||
81 | ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE | 80 | ldxa [%g3 + %g6] ASI_S, %g5 ! Load VPTE |
82 | 1: brgez,pn %g5, longpath ! Invalid, branch out | 81 | 1: brgez,pn %g5, longpath ! Invalid, branch out |
83 | nop ! Delay-slot | 82 | nop ! Delay-slot |
84 | 9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB | 83 | 9: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB |
85 | retry ! Trap return | 84 | retry ! Trap return |
86 | nop | 85 | nop |
87 | nop | ||
88 | nop | ||
89 | 86 | ||
90 | /* DTLB ** ICACHE line 3: winfixups+real_faults */ | 87 | /* DTLB ** ICACHE line 3: winfixups+real_faults */ |
91 | longpath: | 88 | longpath: |
@@ -106,8 +103,7 @@ longpath: | |||
106 | nop | 103 | nop |
107 | nop | 104 | nop |
108 | nop | 105 | nop |
109 | CREATE_VPTE_NOP | 106 | nop |
110 | 107 | ||
111 | #undef CREATE_VPTE_OFFSET1 | 108 | #undef CREATE_VPTE_OFFSET1 |
112 | #undef CREATE_VPTE_OFFSET2 | 109 | #undef CREATE_VPTE_OFFSET2 |
113 | #undef CREATE_VPTE_NOP | ||
diff --git a/arch/sparc64/kernel/dtlb_prot.S b/arch/sparc64/kernel/dtlb_prot.S index d848bb7374bb..e0a920162604 100644 --- a/arch/sparc64/kernel/dtlb_prot.S +++ b/arch/sparc64/kernel/dtlb_prot.S | |||
@@ -14,14 +14,14 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | /* PROT ** ICACHE line 1: User DTLB protection trap */ | 16 | /* PROT ** ICACHE line 1: User DTLB protection trap */ |
17 | stxa %g0, [%g1] ASI_DMMU ! Clear SFSR FaultValid bit | 17 | mov TLB_SFSR, %g1 |
18 | membar #Sync ! Synchronize ASI stores | 18 | stxa %g0, [%g1] ASI_DMMU ! Clear FaultValid bit |
19 | rdpr %pstate, %g5 ! Move into alternate globals | 19 | membar #Sync ! Synchronize stores |
20 | rdpr %pstate, %g5 ! Move into alt-globals | ||
20 | wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate | 21 | wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate |
21 | rdpr %tl, %g1 ! Need to do a winfixup? | 22 | rdpr %tl, %g1 ! Need a winfixup? |
22 | cmp %g1, 1 ! Trap level >1? | 23 | cmp %g1, 1 ! Trap level >1? |
23 | mov TLB_TAG_ACCESS, %g4 ! Prepare reload of vaddr | 24 | mov TLB_TAG_ACCESS, %g4 ! For reload of vaddr |
24 | nop | ||
25 | 25 | ||
26 | /* PROT ** ICACHE line 2: More real fault processing */ | 26 | /* PROT ** ICACHE line 2: More real fault processing */ |
27 | bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup | 27 | bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup |
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S index f1dcdf8f7433..b49dcd4504b0 100644 --- a/arch/sparc64/kernel/head.S +++ b/arch/sparc64/kernel/head.S | |||
@@ -28,19 +28,14 @@ | |||
28 | #include <asm/mmu.h> | 28 | #include <asm/mmu.h> |
29 | 29 | ||
30 | /* This section from from _start to sparc64_boot_end should fit into | 30 | /* This section from from _start to sparc64_boot_end should fit into |
31 | * 0x0000.0000.0040.4000 to 0x0000.0000.0040.8000 and will be sharing space | 31 | * 0x0000000000404000 to 0x0000000000408000. |
32 | * with bootup_user_stack, which is from 0x0000.0000.0040.4000 to | ||
33 | * 0x0000.0000.0040.6000 and empty_bad_page, which is from | ||
34 | * 0x0000.0000.0040.6000 to 0x0000.0000.0040.8000. | ||
35 | */ | 32 | */ |
36 | |||
37 | .text | 33 | .text |
38 | .globl start, _start, stext, _stext | 34 | .globl start, _start, stext, _stext |
39 | _start: | 35 | _start: |
40 | start: | 36 | start: |
41 | _stext: | 37 | _stext: |
42 | stext: | 38 | stext: |
43 | bootup_user_stack: | ||
44 | ! 0x0000000000404000 | 39 | ! 0x0000000000404000 |
45 | b sparc64_boot | 40 | b sparc64_boot |
46 | flushw /* Flush register file. */ | 41 | flushw /* Flush register file. */ |
@@ -191,8 +186,9 @@ prom_boot_mapping_phys_low: | |||
191 | stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 5 | 186 | stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 5 |
192 | stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1: "translate" | 187 | stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1: "translate" |
193 | stx %l5, [%sp + 2047 + 128 + 0x20] ! arg2: prom_mmu_ihandle_cache | 188 | stx %l5, [%sp + 2047 + 128 + 0x20] ! arg2: prom_mmu_ihandle_cache |
194 | srlx %l0, 22, %l3 | 189 | /* PAGE align */ |
195 | sllx %l3, 22, %l3 | 190 | srlx %l0, 13, %l3 |
191 | sllx %l3, 13, %l3 | ||
196 | stx %l3, [%sp + 2047 + 128 + 0x28] ! arg3: vaddr, our PC | 192 | stx %l3, [%sp + 2047 + 128 + 0x28] ! arg3: vaddr, our PC |
197 | stx %g0, [%sp + 2047 + 128 + 0x30] ! res1 | 193 | stx %g0, [%sp + 2047 + 128 + 0x30] ! res1 |
198 | stx %g0, [%sp + 2047 + 128 + 0x38] ! res2 | 194 | stx %g0, [%sp + 2047 + 128 + 0x38] ! res2 |
@@ -211,6 +207,9 @@ prom_boot_mapping_phys_low: | |||
211 | ldx [%sp + 2047 + 128 + 0x48], %l2 ! physaddr high | 207 | ldx [%sp + 2047 + 128 + 0x48], %l2 ! physaddr high |
212 | stx %l2, [%l4 + 0x0] | 208 | stx %l2, [%l4 + 0x0] |
213 | ldx [%sp + 2047 + 128 + 0x50], %l3 ! physaddr low | 209 | ldx [%sp + 2047 + 128 + 0x50], %l3 ! physaddr low |
210 | /* 4MB align */ | ||
211 | srlx %l3, 22, %l3 | ||
212 | sllx %l3, 22, %l3 | ||
214 | stx %l3, [%l4 + 0x8] | 213 | stx %l3, [%l4 + 0x8] |
215 | 214 | ||
216 | /* Leave service as-is, "call-method" */ | 215 | /* Leave service as-is, "call-method" */ |
@@ -388,31 +387,30 @@ tlb_fixup_done: | |||
388 | * former does use this code, the latter does not yet due | 387 | * former does use this code, the latter does not yet due |
389 | * to some complexities. That should be fixed up at some | 388 | * to some complexities. That should be fixed up at some |
390 | * point. | 389 | * point. |
390 | * | ||
391 | * There used to be enormous complexity wrt. transferring | ||
392 | * over from the firwmare's trap table to the Linux kernel's. | ||
393 | * For example, there was a chicken & egg problem wrt. building | ||
394 | * the OBP page tables, yet needing to be on the Linux kernel | ||
395 | * trap table (to translate PAGE_OFFSET addresses) in order to | ||
396 | * do that. | ||
397 | * | ||
398 | * We now handle OBP tlb misses differently, via linear lookups | ||
399 | * into the prom_trans[] array. So that specific problem no | ||
400 | * longer exists. Yet, unfortunately there are still some issues | ||
401 | * preventing trampoline.S from using this code... ho hum. | ||
391 | */ | 402 | */ |
392 | .globl setup_trap_table | 403 | .globl setup_trap_table |
393 | setup_trap_table: | 404 | setup_trap_table: |
394 | save %sp, -192, %sp | 405 | save %sp, -192, %sp |
395 | 406 | ||
396 | /* Force interrupts to be disabled. Transferring over to | 407 | /* Force interrupts to be disabled. */ |
397 | * the Linux trap table is a very delicate operation. | ||
398 | * Until we are actually on the Linux trap table, we cannot | ||
399 | * get the PAGE_OFFSET linear mappings translated. We need | ||
400 | * that mapping to be setup in order to initialize the firmware | ||
401 | * page tables. | ||
402 | * | ||
403 | * So there is this window of time, from the return from | ||
404 | * prom_set_trap_table() until inherit_prom_mappings_post() | ||
405 | * (in arch/sparc64/mm/init.c) completes, during which no | ||
406 | * firmware address space accesses can be made. | ||
407 | */ | ||
408 | rdpr %pstate, %o1 | 408 | rdpr %pstate, %o1 |
409 | andn %o1, PSTATE_IE, %o1 | 409 | andn %o1, PSTATE_IE, %o1 |
410 | wrpr %o1, 0x0, %pstate | 410 | wrpr %o1, 0x0, %pstate |
411 | wrpr %g0, 15, %pil | 411 | wrpr %g0, 15, %pil |
412 | 412 | ||
413 | /* Ok, now make the final valid firmware call to jump over | 413 | /* Make the firmware call to jump over to the Linux trap table. */ |
414 | * to the Linux trap table. | ||
415 | */ | ||
416 | call prom_set_trap_table | 414 | call prom_set_trap_table |
417 | sethi %hi(sparc64_ttable_tl0), %o0 | 415 | sethi %hi(sparc64_ttable_tl0), %o0 |
418 | 416 | ||
@@ -536,15 +534,21 @@ setup_tba: /* i0 = is_starfire */ | |||
536 | 534 | ||
537 | ret | 535 | ret |
538 | restore | 536 | restore |
537 | sparc64_boot_end: | ||
538 | |||
539 | #include "systbls.S" | ||
540 | #include "ktlb.S" | ||
541 | #include "etrap.S" | ||
542 | #include "rtrap.S" | ||
543 | #include "winfixup.S" | ||
544 | #include "entry.S" | ||
539 | 545 | ||
540 | /* | 546 | /* |
541 | * The following skips make sure the trap table in ttable.S is aligned | 547 | * The following skip makes sure the trap table in ttable.S is aligned |
542 | * on a 32K boundary as required by the v9 specs for TBA register. | 548 | * on a 32K boundary as required by the v9 specs for TBA register. |
543 | */ | 549 | */ |
544 | sparc64_boot_end: | 550 | 1: |
545 | .skip 0x2000 + _start - sparc64_boot_end | 551 | .skip 0x4000 + _start - 1b |
546 | bootup_user_stack_end: | ||
547 | .skip 0x2000 | ||
548 | 552 | ||
549 | #ifdef CONFIG_SBUS | 553 | #ifdef CONFIG_SBUS |
550 | /* This is just a hack to fool make depend config.h discovering | 554 | /* This is just a hack to fool make depend config.h discovering |
@@ -556,15 +560,6 @@ bootup_user_stack_end: | |||
556 | ! 0x0000000000408000 | 560 | ! 0x0000000000408000 |
557 | 561 | ||
558 | #include "ttable.S" | 562 | #include "ttable.S" |
559 | #include "systbls.S" | ||
560 | #include "ktlb.S" | ||
561 | #include "etrap.S" | ||
562 | #include "rtrap.S" | ||
563 | #include "winfixup.S" | ||
564 | #include "entry.S" | ||
565 | |||
566 | /* This is just anal retentiveness on my part... */ | ||
567 | .align 16384 | ||
568 | 563 | ||
569 | .data | 564 | .data |
570 | .align 8 | 565 | .align 8 |
diff --git a/arch/sparc64/kernel/itlb_base.S b/arch/sparc64/kernel/itlb_base.S index b5e32dfa4fbc..4951ff8f6877 100644 --- a/arch/sparc64/kernel/itlb_base.S +++ b/arch/sparc64/kernel/itlb_base.S | |||
@@ -15,14 +15,12 @@ | |||
15 | */ | 15 | */ |
16 | #define CREATE_VPTE_OFFSET1(r1, r2) \ | 16 | #define CREATE_VPTE_OFFSET1(r1, r2) \ |
17 | srax r1, 10, r2 | 17 | srax r1, 10, r2 |
18 | #define CREATE_VPTE_OFFSET2(r1, r2) | 18 | #define CREATE_VPTE_OFFSET2(r1, r2) nop |
19 | #define CREATE_VPTE_NOP nop | ||
20 | #else /* PAGE_SHIFT */ | 19 | #else /* PAGE_SHIFT */ |
21 | #define CREATE_VPTE_OFFSET1(r1, r2) \ | 20 | #define CREATE_VPTE_OFFSET1(r1, r2) \ |
22 | srax r1, PAGE_SHIFT, r2 | 21 | srax r1, PAGE_SHIFT, r2 |
23 | #define CREATE_VPTE_OFFSET2(r1, r2) \ | 22 | #define CREATE_VPTE_OFFSET2(r1, r2) \ |
24 | sllx r2, 3, r2 | 23 | sllx r2, 3, r2 |
25 | #define CREATE_VPTE_NOP | ||
26 | #endif /* PAGE_SHIFT */ | 24 | #endif /* PAGE_SHIFT */ |
27 | 25 | ||
28 | 26 | ||
@@ -36,6 +34,7 @@ | |||
36 | */ | 34 | */ |
37 | 35 | ||
38 | /* ITLB ** ICACHE line 1: Quick user TLB misses */ | 36 | /* ITLB ** ICACHE line 1: Quick user TLB misses */ |
37 | mov TLB_SFSR, %g1 | ||
39 | ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS | 38 | ldxa [%g1 + %g1] ASI_IMMU, %g4 ! Get TAG_ACCESS |
40 | CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset | 39 | CREATE_VPTE_OFFSET1(%g4, %g6) ! Create VPTE offset |
41 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset | 40 | CREATE_VPTE_OFFSET2(%g4, %g6) ! Create VPTE offset |
@@ -43,41 +42,38 @@ | |||
43 | 1: brgez,pn %g5, 3f ! Not valid, branch out | 42 | 1: brgez,pn %g5, 3f ! Not valid, branch out |
44 | sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot | 43 | sethi %hi(_PAGE_EXEC), %g4 ! Delay-slot |
45 | andcc %g5, %g4, %g0 ! Executable? | 44 | andcc %g5, %g4, %g0 ! Executable? |
45 | |||
46 | /* ITLB ** ICACHE line 2: Real faults */ | ||
46 | be,pn %xcc, 3f ! Nope, branch. | 47 | be,pn %xcc, 3f ! Nope, branch. |
47 | nop ! Delay-slot | 48 | nop ! Delay-slot |
48 | 2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB | 49 | 2: stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load PTE into TLB |
49 | retry ! Trap return | 50 | retry ! Trap return |
50 | 3: rdpr %pstate, %g4 ! Move into alternate globals | 51 | 3: rdpr %pstate, %g4 ! Move into alt-globals |
51 | |||
52 | /* ITLB ** ICACHE line 2: Real faults */ | ||
53 | wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate | 52 | wrpr %g4, PSTATE_AG|PSTATE_MG, %pstate |
54 | rdpr %tpc, %g5 ! And load faulting VA | 53 | rdpr %tpc, %g5 ! And load faulting VA |
55 | mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB | 54 | mov FAULT_CODE_ITLB, %g4 ! It was read from ITLB |
56 | sparc64_realfault_common: ! Called by TL0 dtlb_miss too | 55 | |
56 | /* ITLB ** ICACHE line 3: Finish faults */ | ||
57 | sparc64_realfault_common: ! Called by dtlb_miss | ||
57 | stb %g4, [%g6 + TI_FAULT_CODE] | 58 | stb %g4, [%g6 + TI_FAULT_CODE] |
58 | stx %g5, [%g6 + TI_FAULT_ADDR] | 59 | stx %g5, [%g6 + TI_FAULT_ADDR] |
59 | ba,pt %xcc, etrap ! Save state | 60 | ba,pt %xcc, etrap ! Save state |
60 | 1: rd %pc, %g7 ! ... | 61 | 1: rd %pc, %g7 ! ... |
61 | nop | ||
62 | |||
63 | /* ITLB ** ICACHE line 3: Finish faults + window fixups */ | ||
64 | call do_sparc64_fault ! Call fault handler | 62 | call do_sparc64_fault ! Call fault handler |
65 | add %sp, PTREGS_OFF, %o0! Compute pt_regs arg | 63 | add %sp, PTREGS_OFF, %o0! Compute pt_regs arg |
66 | ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state | 64 | ba,pt %xcc, rtrap_clr_l6 ! Restore cpu state |
67 | nop | 65 | nop |
66 | |||
67 | /* ITLB ** ICACHE line 4: Window fixups */ | ||
68 | winfix_trampoline: | 68 | winfix_trampoline: |
69 | rdpr %tpc, %g3 ! Prepare winfixup TNPC | 69 | rdpr %tpc, %g3 ! Prepare winfixup TNPC |
70 | or %g3, 0x7c, %g3 ! Compute offset to branch | 70 | or %g3, 0x7c, %g3 ! Compute branch offset |
71 | wrpr %g3, %tnpc ! Write it into TNPC | 71 | wrpr %g3, %tnpc ! Write it into TNPC |
72 | done ! Do it to it | 72 | done ! Do it to it |
73 | |||
74 | /* ITLB ** ICACHE line 4: Unused... */ | ||
75 | nop | 73 | nop |
76 | nop | 74 | nop |
77 | nop | 75 | nop |
78 | nop | 76 | nop |
79 | CREATE_VPTE_NOP | ||
80 | 77 | ||
81 | #undef CREATE_VPTE_OFFSET1 | 78 | #undef CREATE_VPTE_OFFSET1 |
82 | #undef CREATE_VPTE_OFFSET2 | 79 | #undef CREATE_VPTE_OFFSET2 |
83 | #undef CREATE_VPTE_NOP | ||
diff --git a/arch/sparc64/kernel/ktlb.S b/arch/sparc64/kernel/ktlb.S index 7796b37f478c..d9244d3c9f73 100644 --- a/arch/sparc64/kernel/ktlb.S +++ b/arch/sparc64/kernel/ktlb.S | |||
@@ -58,9 +58,6 @@ vpte_noent: | |||
58 | done | 58 | done |
59 | 59 | ||
60 | vpte_insn_obp: | 60 | vpte_insn_obp: |
61 | sethi %hi(prom_pmd_phys), %g5 | ||
62 | ldx [%g5 + %lo(prom_pmd_phys)], %g5 | ||
63 | |||
64 | /* Behave as if we are at TL0. */ | 61 | /* Behave as if we are at TL0. */ |
65 | wrpr %g0, 1, %tl | 62 | wrpr %g0, 1, %tl |
66 | rdpr %tpc, %g4 /* Find original faulting iaddr */ | 63 | rdpr %tpc, %g4 /* Find original faulting iaddr */ |
@@ -71,58 +68,57 @@ vpte_insn_obp: | |||
71 | mov TLB_SFSR, %g1 | 68 | mov TLB_SFSR, %g1 |
72 | stxa %g4, [%g1 + %g1] ASI_IMMU | 69 | stxa %g4, [%g1 + %g1] ASI_IMMU |
73 | 70 | ||
74 | /* Get PMD offset. */ | 71 | sethi %hi(prom_trans), %g5 |
75 | srlx %g4, 23, %g6 | 72 | or %g5, %lo(prom_trans), %g5 |
76 | and %g6, 0x7ff, %g6 | 73 | |
77 | sllx %g6, 2, %g6 | 74 | 1: ldx [%g5 + 0x00], %g6 ! base |
78 | 75 | brz,a,pn %g6, longpath ! no more entries, fail | |
79 | /* Load PMD, is it valid? */ | 76 | mov TLB_SFSR, %g1 ! and restore %g1 |
80 | lduwa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | 77 | ldx [%g5 + 0x08], %g1 ! len |
81 | brz,pn %g5, longpath | 78 | add %g6, %g1, %g1 ! end |
82 | sllx %g5, 11, %g5 | 79 | cmp %g6, %g4 |
83 | 80 | bgu,pt %xcc, 2f | |
84 | /* Get PTE offset. */ | 81 | cmp %g4, %g1 |
85 | srlx %g4, 13, %g6 | 82 | bgeu,pt %xcc, 2f |
86 | and %g6, 0x3ff, %g6 | 83 | ldx [%g5 + 0x10], %g1 ! PTE |
87 | sllx %g6, 3, %g6 | 84 | |
88 | 85 | /* TLB load, restore %g1, and return from trap. */ | |
89 | /* Load PTE. */ | 86 | sub %g4, %g6, %g6 |
90 | ldxa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | 87 | add %g1, %g6, %g5 |
91 | brgez,pn %g5, longpath | 88 | mov TLB_SFSR, %g1 |
92 | nop | ||
93 | |||
94 | /* TLB load and return from trap. */ | ||
95 | stxa %g5, [%g0] ASI_ITLB_DATA_IN | 89 | stxa %g5, [%g0] ASI_ITLB_DATA_IN |
96 | retry | 90 | retry |
97 | 91 | ||
98 | kvmap_do_obp: | 92 | 2: ba,pt %xcc, 1b |
99 | sethi %hi(prom_pmd_phys), %g5 | 93 | add %g5, (3 * 8), %g5 ! next entry |
100 | ldx [%g5 + %lo(prom_pmd_phys)], %g5 | ||
101 | |||
102 | /* Get PMD offset. */ | ||
103 | srlx %g4, 23, %g6 | ||
104 | and %g6, 0x7ff, %g6 | ||
105 | sllx %g6, 2, %g6 | ||
106 | |||
107 | /* Load PMD, is it valid? */ | ||
108 | lduwa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | ||
109 | brz,pn %g5, longpath | ||
110 | sllx %g5, 11, %g5 | ||
111 | |||
112 | /* Get PTE offset. */ | ||
113 | srlx %g4, 13, %g6 | ||
114 | and %g6, 0x3ff, %g6 | ||
115 | sllx %g6, 3, %g6 | ||
116 | |||
117 | /* Load PTE. */ | ||
118 | ldxa [%g5 + %g6] ASI_PHYS_USE_EC, %g5 | ||
119 | brgez,pn %g5, longpath | ||
120 | nop | ||
121 | 94 | ||
122 | /* TLB load and return from trap. */ | 95 | kvmap_do_obp: |
96 | sethi %hi(prom_trans), %g5 | ||
97 | or %g5, %lo(prom_trans), %g5 | ||
98 | srlx %g4, 13, %g4 | ||
99 | sllx %g4, 13, %g4 | ||
100 | |||
101 | 1: ldx [%g5 + 0x00], %g6 ! base | ||
102 | brz,a,pn %g6, longpath ! no more entries, fail | ||
103 | mov TLB_SFSR, %g1 ! and restore %g1 | ||
104 | ldx [%g5 + 0x08], %g1 ! len | ||
105 | add %g6, %g1, %g1 ! end | ||
106 | cmp %g6, %g4 | ||
107 | bgu,pt %xcc, 2f | ||
108 | cmp %g4, %g1 | ||
109 | bgeu,pt %xcc, 2f | ||
110 | ldx [%g5 + 0x10], %g1 ! PTE | ||
111 | |||
112 | /* TLB load, restore %g1, and return from trap. */ | ||
113 | sub %g4, %g6, %g6 | ||
114 | add %g1, %g6, %g5 | ||
115 | mov TLB_SFSR, %g1 | ||
123 | stxa %g5, [%g0] ASI_DTLB_DATA_IN | 116 | stxa %g5, [%g0] ASI_DTLB_DATA_IN |
124 | retry | 117 | retry |
125 | 118 | ||
119 | 2: ba,pt %xcc, 1b | ||
120 | add %g5, (3 * 8), %g5 ! next entry | ||
121 | |||
126 | /* | 122 | /* |
127 | * On a first level data miss, check whether this is to the OBP range (note | 123 | * On a first level data miss, check whether this is to the OBP range (note |
128 | * that such accesses can be made by prom, as well as by kernel using | 124 | * that such accesses can be made by prom, as well as by kernel using |
diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c index 425c60cfea19..a11910be1013 100644 --- a/arch/sparc64/kernel/pci_iommu.c +++ b/arch/sparc64/kernel/pci_iommu.c | |||
@@ -49,12 +49,6 @@ static void __iommu_flushall(struct pci_iommu *iommu) | |||
49 | 49 | ||
50 | /* Ensure completion of previous PIO writes. */ | 50 | /* Ensure completion of previous PIO writes. */ |
51 | (void) pci_iommu_read(iommu->write_complete_reg); | 51 | (void) pci_iommu_read(iommu->write_complete_reg); |
52 | |||
53 | /* Now update everyone's flush point. */ | ||
54 | for (entry = 0; entry < PBM_NCLUSTERS; entry++) { | ||
55 | iommu->alloc_info[entry].flush = | ||
56 | iommu->alloc_info[entry].next; | ||
57 | } | ||
58 | } | 52 | } |
59 | 53 | ||
60 | #define IOPTE_CONSISTENT(CTX) \ | 54 | #define IOPTE_CONSISTENT(CTX) \ |
@@ -80,120 +74,117 @@ static void inline iopte_make_dummy(struct pci_iommu *iommu, iopte_t *iopte) | |||
80 | iopte_val(*iopte) = val; | 74 | iopte_val(*iopte) = val; |
81 | } | 75 | } |
82 | 76 | ||
83 | void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize) | 77 | /* Based largely upon the ppc64 iommu allocator. */ |
78 | static long pci_arena_alloc(struct pci_iommu *iommu, unsigned long npages) | ||
84 | { | 79 | { |
85 | int i; | 80 | struct pci_iommu_arena *arena = &iommu->arena; |
86 | 81 | unsigned long n, i, start, end, limit; | |
87 | tsbsize /= sizeof(iopte_t); | 82 | int pass; |
88 | 83 | ||
89 | for (i = 0; i < tsbsize; i++) | 84 | limit = arena->limit; |
90 | iopte_make_dummy(iommu, &iommu->page_table[i]); | 85 | start = arena->hint; |
91 | } | 86 | pass = 0; |
92 | 87 | ||
93 | static iopte_t *alloc_streaming_cluster(struct pci_iommu *iommu, unsigned long npages) | 88 | again: |
94 | { | 89 | n = find_next_zero_bit(arena->map, limit, start); |
95 | iopte_t *iopte, *limit, *first; | 90 | end = n + npages; |
96 | unsigned long cnum, ent, flush_point; | 91 | if (unlikely(end >= limit)) { |
97 | 92 | if (likely(pass < 1)) { | |
98 | cnum = 0; | 93 | limit = start; |
99 | while ((1UL << cnum) < npages) | 94 | start = 0; |
100 | cnum++; | 95 | __iommu_flushall(iommu); |
101 | iopte = (iommu->page_table + | 96 | pass++; |
102 | (cnum << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); | 97 | goto again; |
103 | 98 | } else { | |
104 | if (cnum == 0) | 99 | /* Scanned the whole thing, give up. */ |
105 | limit = (iommu->page_table + | 100 | return -1; |
106 | iommu->lowest_consistent_map); | ||
107 | else | ||
108 | limit = (iopte + | ||
109 | (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); | ||
110 | |||
111 | iopte += ((ent = iommu->alloc_info[cnum].next) << cnum); | ||
112 | flush_point = iommu->alloc_info[cnum].flush; | ||
113 | |||
114 | first = iopte; | ||
115 | for (;;) { | ||
116 | if (IOPTE_IS_DUMMY(iommu, iopte)) { | ||
117 | if ((iopte + (1 << cnum)) >= limit) | ||
118 | ent = 0; | ||
119 | else | ||
120 | ent = ent + 1; | ||
121 | iommu->alloc_info[cnum].next = ent; | ||
122 | if (ent == flush_point) | ||
123 | __iommu_flushall(iommu); | ||
124 | break; | ||
125 | } | 101 | } |
126 | iopte += (1 << cnum); | 102 | } |
127 | ent++; | 103 | |
128 | if (iopte >= limit) { | 104 | for (i = n; i < end; i++) { |
129 | iopte = (iommu->page_table + | 105 | if (test_bit(i, arena->map)) { |
130 | (cnum << | 106 | start = i + 1; |
131 | (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); | 107 | goto again; |
132 | ent = 0; | ||
133 | } | 108 | } |
134 | if (ent == flush_point) | ||
135 | __iommu_flushall(iommu); | ||
136 | if (iopte == first) | ||
137 | goto bad; | ||
138 | } | 109 | } |
139 | 110 | ||
140 | /* I've got your streaming cluster right here buddy boy... */ | 111 | for (i = n; i < end; i++) |
141 | return iopte; | 112 | __set_bit(i, arena->map); |
142 | 113 | ||
143 | bad: | 114 | arena->hint = end; |
144 | printk(KERN_EMERG "pci_iommu: alloc_streaming_cluster of npages(%ld) failed!\n", | 115 | |
145 | npages); | 116 | return n; |
146 | return NULL; | ||
147 | } | 117 | } |
148 | 118 | ||
149 | static void free_streaming_cluster(struct pci_iommu *iommu, dma_addr_t base, | 119 | static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages) |
150 | unsigned long npages, unsigned long ctx) | ||
151 | { | 120 | { |
152 | unsigned long cnum, ent; | 121 | unsigned long i; |
153 | 122 | ||
154 | cnum = 0; | 123 | for (i = base; i < (base + npages); i++) |
155 | while ((1UL << cnum) < npages) | 124 | __clear_bit(i, arena->map); |
156 | cnum++; | 125 | } |
157 | 126 | ||
158 | ent = (base << (32 - IO_PAGE_SHIFT + PBM_LOGCLUSTERS - iommu->page_table_sz_bits)) | 127 | void pci_iommu_table_init(struct pci_iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask) |
159 | >> (32 + PBM_LOGCLUSTERS + cnum - iommu->page_table_sz_bits); | 128 | { |
129 | unsigned long i, tsbbase, order, sz, num_tsb_entries; | ||
130 | |||
131 | num_tsb_entries = tsbsize / sizeof(iopte_t); | ||
132 | |||
133 | /* Setup initial software IOMMU state. */ | ||
134 | spin_lock_init(&iommu->lock); | ||
135 | iommu->ctx_lowest_free = 1; | ||
136 | iommu->page_table_map_base = dma_offset; | ||
137 | iommu->dma_addr_mask = dma_addr_mask; | ||
138 | |||
139 | /* Allocate and initialize the free area map. */ | ||
140 | sz = num_tsb_entries / 8; | ||
141 | sz = (sz + 7UL) & ~7UL; | ||
142 | iommu->arena.map = kmalloc(sz, GFP_KERNEL); | ||
143 | if (!iommu->arena.map) { | ||
144 | prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); | ||
145 | prom_halt(); | ||
146 | } | ||
147 | memset(iommu->arena.map, 0, sz); | ||
148 | iommu->arena.limit = num_tsb_entries; | ||
160 | 149 | ||
161 | /* If the global flush might not have caught this entry, | 150 | /* Allocate and initialize the dummy page which we |
162 | * adjust the flush point such that we will flush before | 151 | * set inactive IO PTEs to point to. |
163 | * ever trying to reuse it. | ||
164 | */ | 152 | */ |
165 | #define between(X,Y,Z) (((Z) - (Y)) >= ((X) - (Y))) | 153 | iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); |
166 | if (between(ent, iommu->alloc_info[cnum].next, iommu->alloc_info[cnum].flush)) | 154 | if (!iommu->dummy_page) { |
167 | iommu->alloc_info[cnum].flush = ent; | 155 | prom_printf("PCI_IOMMU: Error, gfp(dummy_page) failed.\n"); |
168 | #undef between | 156 | prom_halt(); |
157 | } | ||
158 | memset((void *)iommu->dummy_page, 0, PAGE_SIZE); | ||
159 | iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); | ||
160 | |||
161 | /* Now allocate and setup the IOMMU page table itself. */ | ||
162 | order = get_order(tsbsize); | ||
163 | tsbbase = __get_free_pages(GFP_KERNEL, order); | ||
164 | if (!tsbbase) { | ||
165 | prom_printf("PCI_IOMMU: Error, gfp(tsb) failed.\n"); | ||
166 | prom_halt(); | ||
167 | } | ||
168 | iommu->page_table = (iopte_t *)tsbbase; | ||
169 | |||
170 | for (i = 0; i < num_tsb_entries; i++) | ||
171 | iopte_make_dummy(iommu, &iommu->page_table[i]); | ||
169 | } | 172 | } |
170 | 173 | ||
171 | /* We allocate consistent mappings from the end of cluster zero. */ | 174 | static inline iopte_t *alloc_npages(struct pci_iommu *iommu, unsigned long npages) |
172 | static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long npages) | ||
173 | { | 175 | { |
174 | iopte_t *iopte; | 176 | long entry; |
175 | 177 | ||
176 | iopte = iommu->page_table + (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS)); | 178 | entry = pci_arena_alloc(iommu, npages); |
177 | while (iopte > iommu->page_table) { | 179 | if (unlikely(entry < 0)) |
178 | iopte--; | 180 | return NULL; |
179 | if (IOPTE_IS_DUMMY(iommu, iopte)) { | ||
180 | unsigned long tmp = npages; | ||
181 | 181 | ||
182 | while (--tmp) { | 182 | return iommu->page_table + entry; |
183 | iopte--; | 183 | } |
184 | if (!IOPTE_IS_DUMMY(iommu, iopte)) | ||
185 | break; | ||
186 | } | ||
187 | if (tmp == 0) { | ||
188 | u32 entry = (iopte - iommu->page_table); | ||
189 | 184 | ||
190 | if (entry < iommu->lowest_consistent_map) | 185 | static inline void free_npages(struct pci_iommu *iommu, dma_addr_t base, unsigned long npages) |
191 | iommu->lowest_consistent_map = entry; | 186 | { |
192 | return iopte; | 187 | pci_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); |
193 | } | ||
194 | } | ||
195 | } | ||
196 | return NULL; | ||
197 | } | 188 | } |
198 | 189 | ||
199 | static int iommu_alloc_ctx(struct pci_iommu *iommu) | 190 | static int iommu_alloc_ctx(struct pci_iommu *iommu) |
@@ -233,7 +224,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad | |||
233 | struct pcidev_cookie *pcp; | 224 | struct pcidev_cookie *pcp; |
234 | struct pci_iommu *iommu; | 225 | struct pci_iommu *iommu; |
235 | iopte_t *iopte; | 226 | iopte_t *iopte; |
236 | unsigned long flags, order, first_page, ctx; | 227 | unsigned long flags, order, first_page; |
237 | void *ret; | 228 | void *ret; |
238 | int npages; | 229 | int npages; |
239 | 230 | ||
@@ -251,9 +242,10 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad | |||
251 | iommu = pcp->pbm->iommu; | 242 | iommu = pcp->pbm->iommu; |
252 | 243 | ||
253 | spin_lock_irqsave(&iommu->lock, flags); | 244 | spin_lock_irqsave(&iommu->lock, flags); |
254 | iopte = alloc_consistent_cluster(iommu, size >> IO_PAGE_SHIFT); | 245 | iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); |
255 | if (iopte == NULL) { | 246 | spin_unlock_irqrestore(&iommu->lock, flags); |
256 | spin_unlock_irqrestore(&iommu->lock, flags); | 247 | |
248 | if (unlikely(iopte == NULL)) { | ||
257 | free_pages(first_page, order); | 249 | free_pages(first_page, order); |
258 | return NULL; | 250 | return NULL; |
259 | } | 251 | } |
@@ -262,31 +254,15 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad | |||
262 | ((iopte - iommu->page_table) << IO_PAGE_SHIFT)); | 254 | ((iopte - iommu->page_table) << IO_PAGE_SHIFT)); |
263 | ret = (void *) first_page; | 255 | ret = (void *) first_page; |
264 | npages = size >> IO_PAGE_SHIFT; | 256 | npages = size >> IO_PAGE_SHIFT; |
265 | ctx = 0; | ||
266 | if (iommu->iommu_ctxflush) | ||
267 | ctx = iommu_alloc_ctx(iommu); | ||
268 | first_page = __pa(first_page); | 257 | first_page = __pa(first_page); |
269 | while (npages--) { | 258 | while (npages--) { |
270 | iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) | | 259 | iopte_val(*iopte) = (IOPTE_CONSISTENT(0UL) | |
271 | IOPTE_WRITE | | 260 | IOPTE_WRITE | |
272 | (first_page & IOPTE_PAGE)); | 261 | (first_page & IOPTE_PAGE)); |
273 | iopte++; | 262 | iopte++; |
274 | first_page += IO_PAGE_SIZE; | 263 | first_page += IO_PAGE_SIZE; |
275 | } | 264 | } |
276 | 265 | ||
277 | { | ||
278 | int i; | ||
279 | u32 daddr = *dma_addrp; | ||
280 | |||
281 | npages = size >> IO_PAGE_SHIFT; | ||
282 | for (i = 0; i < npages; i++) { | ||
283 | pci_iommu_write(iommu->iommu_flush, daddr); | ||
284 | daddr += IO_PAGE_SIZE; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
289 | |||
290 | return ret; | 266 | return ret; |
291 | } | 267 | } |
292 | 268 | ||
@@ -296,7 +272,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ | |||
296 | struct pcidev_cookie *pcp; | 272 | struct pcidev_cookie *pcp; |
297 | struct pci_iommu *iommu; | 273 | struct pci_iommu *iommu; |
298 | iopte_t *iopte; | 274 | iopte_t *iopte; |
299 | unsigned long flags, order, npages, i, ctx; | 275 | unsigned long flags, order, npages; |
300 | 276 | ||
301 | npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; | 277 | npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; |
302 | pcp = pdev->sysdata; | 278 | pcp = pdev->sysdata; |
@@ -306,46 +282,7 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ | |||
306 | 282 | ||
307 | spin_lock_irqsave(&iommu->lock, flags); | 283 | spin_lock_irqsave(&iommu->lock, flags); |
308 | 284 | ||
309 | if ((iopte - iommu->page_table) == | 285 | free_npages(iommu, dvma, npages); |
310 | iommu->lowest_consistent_map) { | ||
311 | iopte_t *walk = iopte + npages; | ||
312 | iopte_t *limit; | ||
313 | |||
314 | limit = (iommu->page_table + | ||
315 | (1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS))); | ||
316 | while (walk < limit) { | ||
317 | if (!IOPTE_IS_DUMMY(iommu, walk)) | ||
318 | break; | ||
319 | walk++; | ||
320 | } | ||
321 | iommu->lowest_consistent_map = | ||
322 | (walk - iommu->page_table); | ||
323 | } | ||
324 | |||
325 | /* Data for consistent mappings cannot enter the streaming | ||
326 | * buffers, so we only need to update the TSB. We flush | ||
327 | * the IOMMU here as well to prevent conflicts with the | ||
328 | * streaming mapping deferred tlb flush scheme. | ||
329 | */ | ||
330 | |||
331 | ctx = 0; | ||
332 | if (iommu->iommu_ctxflush) | ||
333 | ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; | ||
334 | |||
335 | for (i = 0; i < npages; i++, iopte++) | ||
336 | iopte_make_dummy(iommu, iopte); | ||
337 | |||
338 | if (iommu->iommu_ctxflush) { | ||
339 | pci_iommu_write(iommu->iommu_ctxflush, ctx); | ||
340 | } else { | ||
341 | for (i = 0; i < npages; i++) { | ||
342 | u32 daddr = dvma + (i << IO_PAGE_SHIFT); | ||
343 | |||
344 | pci_iommu_write(iommu->iommu_flush, daddr); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | iommu_free_ctx(iommu, ctx); | ||
349 | 286 | ||
350 | spin_unlock_irqrestore(&iommu->lock, flags); | 287 | spin_unlock_irqrestore(&iommu->lock, flags); |
351 | 288 | ||
@@ -372,25 +309,27 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct | |||
372 | iommu = pcp->pbm->iommu; | 309 | iommu = pcp->pbm->iommu; |
373 | strbuf = &pcp->pbm->stc; | 310 | strbuf = &pcp->pbm->stc; |
374 | 311 | ||
375 | if (direction == PCI_DMA_NONE) | 312 | if (unlikely(direction == PCI_DMA_NONE)) |
376 | BUG(); | 313 | goto bad_no_ctx; |
377 | 314 | ||
378 | oaddr = (unsigned long)ptr; | 315 | oaddr = (unsigned long)ptr; |
379 | npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); | 316 | npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); |
380 | npages >>= IO_PAGE_SHIFT; | 317 | npages >>= IO_PAGE_SHIFT; |
381 | 318 | ||
382 | spin_lock_irqsave(&iommu->lock, flags); | 319 | spin_lock_irqsave(&iommu->lock, flags); |
320 | base = alloc_npages(iommu, npages); | ||
321 | ctx = 0; | ||
322 | if (iommu->iommu_ctxflush) | ||
323 | ctx = iommu_alloc_ctx(iommu); | ||
324 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
383 | 325 | ||
384 | base = alloc_streaming_cluster(iommu, npages); | 326 | if (unlikely(!base)) |
385 | if (base == NULL) | ||
386 | goto bad; | 327 | goto bad; |
328 | |||
387 | bus_addr = (iommu->page_table_map_base + | 329 | bus_addr = (iommu->page_table_map_base + |
388 | ((base - iommu->page_table) << IO_PAGE_SHIFT)); | 330 | ((base - iommu->page_table) << IO_PAGE_SHIFT)); |
389 | ret = bus_addr | (oaddr & ~IO_PAGE_MASK); | 331 | ret = bus_addr | (oaddr & ~IO_PAGE_MASK); |
390 | base_paddr = __pa(oaddr & IO_PAGE_MASK); | 332 | base_paddr = __pa(oaddr & IO_PAGE_MASK); |
391 | ctx = 0; | ||
392 | if (iommu->iommu_ctxflush) | ||
393 | ctx = iommu_alloc_ctx(iommu); | ||
394 | if (strbuf->strbuf_enabled) | 333 | if (strbuf->strbuf_enabled) |
395 | iopte_protection = IOPTE_STREAMING(ctx); | 334 | iopte_protection = IOPTE_STREAMING(ctx); |
396 | else | 335 | else |
@@ -401,12 +340,13 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct | |||
401 | for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE) | 340 | for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE) |
402 | iopte_val(*base) = iopte_protection | base_paddr; | 341 | iopte_val(*base) = iopte_protection | base_paddr; |
403 | 342 | ||
404 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
405 | |||
406 | return ret; | 343 | return ret; |
407 | 344 | ||
408 | bad: | 345 | bad: |
409 | spin_unlock_irqrestore(&iommu->lock, flags); | 346 | iommu_free_ctx(iommu, ctx); |
347 | bad_no_ctx: | ||
348 | if (printk_ratelimit()) | ||
349 | WARN_ON(1); | ||
410 | return PCI_DMA_ERROR_CODE; | 350 | return PCI_DMA_ERROR_CODE; |
411 | } | 351 | } |
412 | 352 | ||
@@ -481,10 +421,13 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int | |||
481 | struct pci_iommu *iommu; | 421 | struct pci_iommu *iommu; |
482 | struct pci_strbuf *strbuf; | 422 | struct pci_strbuf *strbuf; |
483 | iopte_t *base; | 423 | iopte_t *base; |
484 | unsigned long flags, npages, ctx; | 424 | unsigned long flags, npages, ctx, i; |
485 | 425 | ||
486 | if (direction == PCI_DMA_NONE) | 426 | if (unlikely(direction == PCI_DMA_NONE)) { |
487 | BUG(); | 427 | if (printk_ratelimit()) |
428 | WARN_ON(1); | ||
429 | return; | ||
430 | } | ||
488 | 431 | ||
489 | pcp = pdev->sysdata; | 432 | pcp = pdev->sysdata; |
490 | iommu = pcp->pbm->iommu; | 433 | iommu = pcp->pbm->iommu; |
@@ -510,13 +453,14 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int | |||
510 | 453 | ||
511 | /* Step 1: Kick data out of streaming buffers if necessary. */ | 454 | /* Step 1: Kick data out of streaming buffers if necessary. */ |
512 | if (strbuf->strbuf_enabled) | 455 | if (strbuf->strbuf_enabled) |
513 | pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); | 456 | pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, |
457 | npages, direction); | ||
514 | 458 | ||
515 | /* Step 2: Clear out first TSB entry. */ | 459 | /* Step 2: Clear out TSB entries. */ |
516 | iopte_make_dummy(iommu, base); | 460 | for (i = 0; i < npages; i++) |
461 | iopte_make_dummy(iommu, base + i); | ||
517 | 462 | ||
518 | free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, | 463 | free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); |
519 | npages, ctx); | ||
520 | 464 | ||
521 | iommu_free_ctx(iommu, ctx); | 465 | iommu_free_ctx(iommu, ctx); |
522 | 466 | ||
@@ -621,6 +565,8 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int | |||
621 | pci_map_single(pdev, | 565 | pci_map_single(pdev, |
622 | (page_address(sglist->page) + sglist->offset), | 566 | (page_address(sglist->page) + sglist->offset), |
623 | sglist->length, direction); | 567 | sglist->length, direction); |
568 | if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE)) | ||
569 | return 0; | ||
624 | sglist->dma_length = sglist->length; | 570 | sglist->dma_length = sglist->length; |
625 | return 1; | 571 | return 1; |
626 | } | 572 | } |
@@ -629,21 +575,29 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int | |||
629 | iommu = pcp->pbm->iommu; | 575 | iommu = pcp->pbm->iommu; |
630 | strbuf = &pcp->pbm->stc; | 576 | strbuf = &pcp->pbm->stc; |
631 | 577 | ||
632 | if (direction == PCI_DMA_NONE) | 578 | if (unlikely(direction == PCI_DMA_NONE)) |
633 | BUG(); | 579 | goto bad_no_ctx; |
634 | 580 | ||
635 | /* Step 1: Prepare scatter list. */ | 581 | /* Step 1: Prepare scatter list. */ |
636 | 582 | ||
637 | npages = prepare_sg(sglist, nelems); | 583 | npages = prepare_sg(sglist, nelems); |
638 | 584 | ||
639 | /* Step 2: Allocate a cluster. */ | 585 | /* Step 2: Allocate a cluster and context, if necessary. */ |
640 | 586 | ||
641 | spin_lock_irqsave(&iommu->lock, flags); | 587 | spin_lock_irqsave(&iommu->lock, flags); |
642 | 588 | ||
643 | base = alloc_streaming_cluster(iommu, npages); | 589 | base = alloc_npages(iommu, npages); |
590 | ctx = 0; | ||
591 | if (iommu->iommu_ctxflush) | ||
592 | ctx = iommu_alloc_ctx(iommu); | ||
593 | |||
594 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
595 | |||
644 | if (base == NULL) | 596 | if (base == NULL) |
645 | goto bad; | 597 | goto bad; |
646 | dma_base = iommu->page_table_map_base + ((base - iommu->page_table) << IO_PAGE_SHIFT); | 598 | |
599 | dma_base = iommu->page_table_map_base + | ||
600 | ((base - iommu->page_table) << IO_PAGE_SHIFT); | ||
647 | 601 | ||
648 | /* Step 3: Normalize DMA addresses. */ | 602 | /* Step 3: Normalize DMA addresses. */ |
649 | used = nelems; | 603 | used = nelems; |
@@ -656,30 +610,28 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int | |||
656 | } | 610 | } |
657 | used = nelems - used; | 611 | used = nelems - used; |
658 | 612 | ||
659 | /* Step 4: Choose a context if necessary. */ | 613 | /* Step 4: Create the mappings. */ |
660 | ctx = 0; | ||
661 | if (iommu->iommu_ctxflush) | ||
662 | ctx = iommu_alloc_ctx(iommu); | ||
663 | |||
664 | /* Step 5: Create the mappings. */ | ||
665 | if (strbuf->strbuf_enabled) | 614 | if (strbuf->strbuf_enabled) |
666 | iopte_protection = IOPTE_STREAMING(ctx); | 615 | iopte_protection = IOPTE_STREAMING(ctx); |
667 | else | 616 | else |
668 | iopte_protection = IOPTE_CONSISTENT(ctx); | 617 | iopte_protection = IOPTE_CONSISTENT(ctx); |
669 | if (direction != PCI_DMA_TODEVICE) | 618 | if (direction != PCI_DMA_TODEVICE) |
670 | iopte_protection |= IOPTE_WRITE; | 619 | iopte_protection |= IOPTE_WRITE; |
671 | fill_sg (base, sglist, used, nelems, iopte_protection); | 620 | |
621 | fill_sg(base, sglist, used, nelems, iopte_protection); | ||
622 | |||
672 | #ifdef VERIFY_SG | 623 | #ifdef VERIFY_SG |
673 | verify_sglist(sglist, nelems, base, npages); | 624 | verify_sglist(sglist, nelems, base, npages); |
674 | #endif | 625 | #endif |
675 | 626 | ||
676 | spin_unlock_irqrestore(&iommu->lock, flags); | ||
677 | |||
678 | return used; | 627 | return used; |
679 | 628 | ||
680 | bad: | 629 | bad: |
681 | spin_unlock_irqrestore(&iommu->lock, flags); | 630 | iommu_free_ctx(iommu, ctx); |
682 | return PCI_DMA_ERROR_CODE; | 631 | bad_no_ctx: |
632 | if (printk_ratelimit()) | ||
633 | WARN_ON(1); | ||
634 | return 0; | ||
683 | } | 635 | } |
684 | 636 | ||
685 | /* Unmap a set of streaming mode DMA translations. */ | 637 | /* Unmap a set of streaming mode DMA translations. */ |
@@ -692,8 +644,10 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, | |||
692 | unsigned long flags, ctx, i, npages; | 644 | unsigned long flags, ctx, i, npages; |
693 | u32 bus_addr; | 645 | u32 bus_addr; |
694 | 646 | ||
695 | if (direction == PCI_DMA_NONE) | 647 | if (unlikely(direction == PCI_DMA_NONE)) { |
696 | BUG(); | 648 | if (printk_ratelimit()) |
649 | WARN_ON(1); | ||
650 | } | ||
697 | 651 | ||
698 | pcp = pdev->sysdata; | 652 | pcp = pdev->sysdata; |
699 | iommu = pcp->pbm->iommu; | 653 | iommu = pcp->pbm->iommu; |
@@ -705,7 +659,8 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, | |||
705 | if (sglist[i].dma_length == 0) | 659 | if (sglist[i].dma_length == 0) |
706 | break; | 660 | break; |
707 | i--; | 661 | i--; |
708 | npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - bus_addr) >> IO_PAGE_SHIFT; | 662 | npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - |
663 | bus_addr) >> IO_PAGE_SHIFT; | ||
709 | 664 | ||
710 | base = iommu->page_table + | 665 | base = iommu->page_table + |
711 | ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); | 666 | ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); |
@@ -726,11 +681,11 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, | |||
726 | if (strbuf->strbuf_enabled) | 681 | if (strbuf->strbuf_enabled) |
727 | pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); | 682 | pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); |
728 | 683 | ||
729 | /* Step 2: Clear out first TSB entry. */ | 684 | /* Step 2: Clear out the TSB entries. */ |
730 | iopte_make_dummy(iommu, base); | 685 | for (i = 0; i < npages; i++) |
686 | iopte_make_dummy(iommu, base + i); | ||
731 | 687 | ||
732 | free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, | 688 | free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); |
733 | npages, ctx); | ||
734 | 689 | ||
735 | iommu_free_ctx(iommu, ctx); | 690 | iommu_free_ctx(iommu, ctx); |
736 | 691 | ||
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 6ed1ef25e0ac..c03ed5f49d31 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c | |||
@@ -1207,13 +1207,9 @@ static void psycho_scan_bus(struct pci_controller_info *p) | |||
1207 | static void psycho_iommu_init(struct pci_controller_info *p) | 1207 | static void psycho_iommu_init(struct pci_controller_info *p) |
1208 | { | 1208 | { |
1209 | struct pci_iommu *iommu = p->pbm_A.iommu; | 1209 | struct pci_iommu *iommu = p->pbm_A.iommu; |
1210 | unsigned long tsbbase, i; | 1210 | unsigned long i; |
1211 | u64 control; | 1211 | u64 control; |
1212 | 1212 | ||
1213 | /* Setup initial software IOMMU state. */ | ||
1214 | spin_lock_init(&iommu->lock); | ||
1215 | iommu->ctx_lowest_free = 1; | ||
1216 | |||
1217 | /* Register addresses. */ | 1213 | /* Register addresses. */ |
1218 | iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL; | 1214 | iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL; |
1219 | iommu->iommu_tsbbase = p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE; | 1215 | iommu->iommu_tsbbase = p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE; |
@@ -1240,40 +1236,10 @@ static void psycho_iommu_init(struct pci_controller_info *p) | |||
1240 | /* Leave diag mode enabled for full-flushing done | 1236 | /* Leave diag mode enabled for full-flushing done |
1241 | * in pci_iommu.c | 1237 | * in pci_iommu.c |
1242 | */ | 1238 | */ |
1239 | pci_iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff); | ||
1243 | 1240 | ||
1244 | iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); | 1241 | psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE, |
1245 | if (!iommu->dummy_page) { | 1242 | __pa(iommu->page_table)); |
1246 | prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); | ||
1247 | prom_halt(); | ||
1248 | } | ||
1249 | memset((void *)iommu->dummy_page, 0, PAGE_SIZE); | ||
1250 | iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); | ||
1251 | |||
1252 | /* Using assumed page size 8K with 128K entries we need 1MB iommu page | ||
1253 | * table (128K ioptes * 8 bytes per iopte). This is | ||
1254 | * page order 7 on UltraSparc. | ||
1255 | */ | ||
1256 | tsbbase = __get_free_pages(GFP_KERNEL, get_order(IO_TSB_SIZE)); | ||
1257 | if (!tsbbase) { | ||
1258 | prom_printf("PSYCHO_IOMMU: Error, gfp(tsb) failed.\n"); | ||
1259 | prom_halt(); | ||
1260 | } | ||
1261 | iommu->page_table = (iopte_t *)tsbbase; | ||
1262 | iommu->page_table_sz_bits = 17; | ||
1263 | iommu->page_table_map_base = 0xc0000000; | ||
1264 | iommu->dma_addr_mask = 0xffffffff; | ||
1265 | pci_iommu_table_init(iommu, IO_TSB_SIZE); | ||
1266 | |||
1267 | /* We start with no consistent mappings. */ | ||
1268 | iommu->lowest_consistent_map = | ||
1269 | 1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS); | ||
1270 | |||
1271 | for (i = 0; i < PBM_NCLUSTERS; i++) { | ||
1272 | iommu->alloc_info[i].flush = 0; | ||
1273 | iommu->alloc_info[i].next = 0; | ||
1274 | } | ||
1275 | |||
1276 | psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(tsbbase)); | ||
1277 | 1243 | ||
1278 | control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL); | 1244 | control = psycho_read(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL); |
1279 | control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ); | 1245 | control &= ~(PSYCHO_IOMMU_CTRL_TSBSZ | PSYCHO_IOMMU_CTRL_TBWSZ); |
@@ -1281,7 +1247,7 @@ static void psycho_iommu_init(struct pci_controller_info *p) | |||
1281 | psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control); | 1247 | psycho_write(p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL, control); |
1282 | 1248 | ||
1283 | /* If necessary, hook us up for starfire IRQ translations. */ | 1249 | /* If necessary, hook us up for starfire IRQ translations. */ |
1284 | if(this_is_starfire) | 1250 | if (this_is_starfire) |
1285 | p->starfire_cookie = starfire_hookup(p->pbm_A.portid); | 1251 | p->starfire_cookie = starfire_hookup(p->pbm_A.portid); |
1286 | else | 1252 | else |
1287 | p->starfire_cookie = NULL; | 1253 | p->starfire_cookie = NULL; |
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 0ee6bd5b9ac6..da8e1364194f 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c | |||
@@ -1267,13 +1267,9 @@ static void sabre_iommu_init(struct pci_controller_info *p, | |||
1267 | u32 dma_mask) | 1267 | u32 dma_mask) |
1268 | { | 1268 | { |
1269 | struct pci_iommu *iommu = p->pbm_A.iommu; | 1269 | struct pci_iommu *iommu = p->pbm_A.iommu; |
1270 | unsigned long tsbbase, i, order; | 1270 | unsigned long i; |
1271 | u64 control; | 1271 | u64 control; |
1272 | 1272 | ||
1273 | /* Setup initial software IOMMU state. */ | ||
1274 | spin_lock_init(&iommu->lock); | ||
1275 | iommu->ctx_lowest_free = 1; | ||
1276 | |||
1277 | /* Register addresses. */ | 1273 | /* Register addresses. */ |
1278 | iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL; | 1274 | iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL; |
1279 | iommu->iommu_tsbbase = p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE; | 1275 | iommu->iommu_tsbbase = p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE; |
@@ -1295,26 +1291,10 @@ static void sabre_iommu_init(struct pci_controller_info *p, | |||
1295 | /* Leave diag mode enabled for full-flushing done | 1291 | /* Leave diag mode enabled for full-flushing done |
1296 | * in pci_iommu.c | 1292 | * in pci_iommu.c |
1297 | */ | 1293 | */ |
1294 | pci_iommu_table_init(iommu, tsbsize * 1024 * 8, dvma_offset, dma_mask); | ||
1298 | 1295 | ||
1299 | iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); | 1296 | sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE, |
1300 | if (!iommu->dummy_page) { | 1297 | __pa(iommu->page_table)); |
1301 | prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); | ||
1302 | prom_halt(); | ||
1303 | } | ||
1304 | memset((void *)iommu->dummy_page, 0, PAGE_SIZE); | ||
1305 | iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); | ||
1306 | |||
1307 | tsbbase = __get_free_pages(GFP_KERNEL, order = get_order(tsbsize * 1024 * 8)); | ||
1308 | if (!tsbbase) { | ||
1309 | prom_printf("SABRE_IOMMU: Error, gfp(tsb) failed.\n"); | ||
1310 | prom_halt(); | ||
1311 | } | ||
1312 | iommu->page_table = (iopte_t *)tsbbase; | ||
1313 | iommu->page_table_map_base = dvma_offset; | ||
1314 | iommu->dma_addr_mask = dma_mask; | ||
1315 | pci_iommu_table_init(iommu, PAGE_SIZE << order); | ||
1316 | |||
1317 | sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_TSBBASE, __pa(tsbbase)); | ||
1318 | 1298 | ||
1319 | control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL); | 1299 | control = sabre_read(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL); |
1320 | control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ); | 1300 | control &= ~(SABRE_IOMMUCTRL_TSBSZ | SABRE_IOMMUCTRL_TBWSZ); |
@@ -1322,11 +1302,9 @@ static void sabre_iommu_init(struct pci_controller_info *p, | |||
1322 | switch(tsbsize) { | 1302 | switch(tsbsize) { |
1323 | case 64: | 1303 | case 64: |
1324 | control |= SABRE_IOMMU_TSBSZ_64K; | 1304 | control |= SABRE_IOMMU_TSBSZ_64K; |
1325 | iommu->page_table_sz_bits = 16; | ||
1326 | break; | 1305 | break; |
1327 | case 128: | 1306 | case 128: |
1328 | control |= SABRE_IOMMU_TSBSZ_128K; | 1307 | control |= SABRE_IOMMU_TSBSZ_128K; |
1329 | iommu->page_table_sz_bits = 17; | ||
1330 | break; | 1308 | break; |
1331 | default: | 1309 | default: |
1332 | prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); | 1310 | prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); |
@@ -1334,15 +1312,6 @@ static void sabre_iommu_init(struct pci_controller_info *p, | |||
1334 | break; | 1312 | break; |
1335 | } | 1313 | } |
1336 | sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control); | 1314 | sabre_write(p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL, control); |
1337 | |||
1338 | /* We start with no consistent mappings. */ | ||
1339 | iommu->lowest_consistent_map = | ||
1340 | 1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS); | ||
1341 | |||
1342 | for (i = 0; i < PBM_NCLUSTERS; i++) { | ||
1343 | iommu->alloc_info[i].flush = 0; | ||
1344 | iommu->alloc_info[i].next = 0; | ||
1345 | } | ||
1346 | } | 1315 | } |
1347 | 1316 | ||
1348 | static void pbm_register_toplevel_resources(struct pci_controller_info *p, | 1317 | static void pbm_register_toplevel_resources(struct pci_controller_info *p, |
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index cae5b61fe2f0..d8c4e0919b4e 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c | |||
@@ -1765,7 +1765,7 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm) | |||
1765 | static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) | 1765 | static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) |
1766 | { | 1766 | { |
1767 | struct pci_iommu *iommu = pbm->iommu; | 1767 | struct pci_iommu *iommu = pbm->iommu; |
1768 | unsigned long tsbbase, i, tagbase, database, order; | 1768 | unsigned long i, tagbase, database; |
1769 | u32 vdma[2], dma_mask; | 1769 | u32 vdma[2], dma_mask; |
1770 | u64 control; | 1770 | u64 control; |
1771 | int err, tsbsize; | 1771 | int err, tsbsize; |
@@ -1800,10 +1800,6 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) | |||
1800 | prom_halt(); | 1800 | prom_halt(); |
1801 | }; | 1801 | }; |
1802 | 1802 | ||
1803 | /* Setup initial software IOMMU state. */ | ||
1804 | spin_lock_init(&iommu->lock); | ||
1805 | iommu->ctx_lowest_free = 1; | ||
1806 | |||
1807 | /* Register addresses, SCHIZO has iommu ctx flushing. */ | 1803 | /* Register addresses, SCHIZO has iommu ctx flushing. */ |
1808 | iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; | 1804 | iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; |
1809 | iommu->iommu_tsbbase = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE; | 1805 | iommu->iommu_tsbbase = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE; |
@@ -1832,56 +1828,9 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) | |||
1832 | /* Leave diag mode enabled for full-flushing done | 1828 | /* Leave diag mode enabled for full-flushing done |
1833 | * in pci_iommu.c | 1829 | * in pci_iommu.c |
1834 | */ | 1830 | */ |
1831 | pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask); | ||
1835 | 1832 | ||
1836 | iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); | 1833 | schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table)); |
1837 | if (!iommu->dummy_page) { | ||
1838 | prom_printf("PSYCHO_IOMMU: Error, gfp(dummy_page) failed.\n"); | ||
1839 | prom_halt(); | ||
1840 | } | ||
1841 | memset((void *)iommu->dummy_page, 0, PAGE_SIZE); | ||
1842 | iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); | ||
1843 | |||
1844 | /* Using assumed page size 8K with 128K entries we need 1MB iommu page | ||
1845 | * table (128K ioptes * 8 bytes per iopte). This is | ||
1846 | * page order 7 on UltraSparc. | ||
1847 | */ | ||
1848 | order = get_order(tsbsize * 8 * 1024); | ||
1849 | tsbbase = __get_free_pages(GFP_KERNEL, order); | ||
1850 | if (!tsbbase) { | ||
1851 | prom_printf("%s: Error, gfp(tsb) failed.\n", pbm->name); | ||
1852 | prom_halt(); | ||
1853 | } | ||
1854 | |||
1855 | iommu->page_table = (iopte_t *)tsbbase; | ||
1856 | iommu->page_table_map_base = vdma[0]; | ||
1857 | iommu->dma_addr_mask = dma_mask; | ||
1858 | pci_iommu_table_init(iommu, PAGE_SIZE << order); | ||
1859 | |||
1860 | switch (tsbsize) { | ||
1861 | case 64: | ||
1862 | iommu->page_table_sz_bits = 16; | ||
1863 | break; | ||
1864 | |||
1865 | case 128: | ||
1866 | iommu->page_table_sz_bits = 17; | ||
1867 | break; | ||
1868 | |||
1869 | default: | ||
1870 | prom_printf("iommu_init: Illegal TSB size %d\n", tsbsize); | ||
1871 | prom_halt(); | ||
1872 | break; | ||
1873 | }; | ||
1874 | |||
1875 | /* We start with no consistent mappings. */ | ||
1876 | iommu->lowest_consistent_map = | ||
1877 | 1 << (iommu->page_table_sz_bits - PBM_LOGCLUSTERS); | ||
1878 | |||
1879 | for (i = 0; i < PBM_NCLUSTERS; i++) { | ||
1880 | iommu->alloc_info[i].flush = 0; | ||
1881 | iommu->alloc_info[i].next = 0; | ||
1882 | } | ||
1883 | |||
1884 | schizo_write(iommu->iommu_tsbbase, __pa(tsbbase)); | ||
1885 | 1834 | ||
1886 | control = schizo_read(iommu->iommu_control); | 1835 | control = schizo_read(iommu->iommu_control); |
1887 | control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ); | 1836 | control &= ~(SCHIZO_IOMMU_CTRL_TSBSZ | SCHIZO_IOMMU_CTRL_TBWSZ); |
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 590df5a16f5a..b137fd63f5e1 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c | |||
@@ -1001,13 +1001,6 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs) | |||
1001 | preempt_enable(); | 1001 | preempt_enable(); |
1002 | } | 1002 | } |
1003 | 1003 | ||
1004 | extern unsigned long xcall_promstop; | ||
1005 | |||
1006 | void smp_promstop_others(void) | ||
1007 | { | ||
1008 | smp_cross_call(&xcall_promstop, 0, 0, 0); | ||
1009 | } | ||
1010 | |||
1011 | #define prof_multiplier(__cpu) cpu_data(__cpu).multiplier | 1004 | #define prof_multiplier(__cpu) cpu_data(__cpu).multiplier |
1012 | #define prof_counter(__cpu) cpu_data(__cpu).counter | 1005 | #define prof_counter(__cpu) cpu_data(__cpu).counter |
1013 | 1006 | ||
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 0d2e967c7200..1e44ee26cee8 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c | |||
@@ -105,7 +105,7 @@ static void __init read_obp_memory(const char *property, | |||
105 | regs[i].phys_addr = base; | 105 | regs[i].phys_addr = base; |
106 | regs[i].reg_size = size; | 106 | regs[i].reg_size = size; |
107 | } | 107 | } |
108 | sort(regs, ents, sizeof(struct linux_prom64_registers), | 108 | sort(regs, ents, sizeof(struct linux_prom64_registers), |
109 | cmp_p64, NULL); | 109 | cmp_p64, NULL); |
110 | } | 110 | } |
111 | 111 | ||
@@ -367,8 +367,11 @@ struct linux_prom_translation { | |||
367 | unsigned long size; | 367 | unsigned long size; |
368 | unsigned long data; | 368 | unsigned long data; |
369 | }; | 369 | }; |
370 | static struct linux_prom_translation prom_trans[512] __initdata; | 370 | |
371 | static unsigned int prom_trans_ents __initdata; | 371 | /* Exported for kernel TLB miss handling in ktlb.S */ |
372 | struct linux_prom_translation prom_trans[512] __read_mostly; | ||
373 | unsigned int prom_trans_ents __read_mostly; | ||
374 | unsigned int swapper_pgd_zero __read_mostly; | ||
372 | 375 | ||
373 | extern unsigned long prom_boot_page; | 376 | extern unsigned long prom_boot_page; |
374 | extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); | 377 | extern void prom_remap(unsigned long physpage, unsigned long virtpage, int mmu_ihandle); |
@@ -378,122 +381,57 @@ extern void register_prom_callbacks(void); | |||
378 | /* Exported for SMP bootup purposes. */ | 381 | /* Exported for SMP bootup purposes. */ |
379 | unsigned long kern_locked_tte_data; | 382 | unsigned long kern_locked_tte_data; |
380 | 383 | ||
381 | /* Exported for kernel TLB miss handling in ktlb.S */ | ||
382 | unsigned long prom_pmd_phys __read_mostly; | ||
383 | unsigned int swapper_pgd_zero __read_mostly; | ||
384 | |||
385 | static pmd_t *prompmd __read_mostly; | ||
386 | |||
387 | #define BASE_PAGE_SIZE 8192 | ||
388 | |||
389 | /* | 384 | /* |
390 | * Translate PROM's mapping we capture at boot time into physical address. | 385 | * Translate PROM's mapping we capture at boot time into physical address. |
391 | * The second parameter is only set from prom_callback() invocations. | 386 | * The second parameter is only set from prom_callback() invocations. |
392 | */ | 387 | */ |
393 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) | 388 | unsigned long prom_virt_to_phys(unsigned long promva, int *error) |
394 | { | 389 | { |
395 | pmd_t *pmdp = prompmd + ((promva >> 23) & 0x7ff); | 390 | int i; |
396 | pte_t *ptep; | ||
397 | unsigned long base; | ||
398 | |||
399 | if (pmd_none(*pmdp)) { | ||
400 | if (error) | ||
401 | *error = 1; | ||
402 | return 0; | ||
403 | } | ||
404 | ptep = (pte_t *)__pmd_page(*pmdp) + ((promva >> 13) & 0x3ff); | ||
405 | if (!pte_present(*ptep)) { | ||
406 | if (error) | ||
407 | *error = 1; | ||
408 | return 0; | ||
409 | } | ||
410 | if (error) { | ||
411 | *error = 0; | ||
412 | return pte_val(*ptep); | ||
413 | } | ||
414 | base = pte_val(*ptep) & _PAGE_PADDR; | ||
415 | |||
416 | return base + (promva & (BASE_PAGE_SIZE - 1)); | ||
417 | } | ||
418 | 391 | ||
419 | /* The obp translations are saved based on 8k pagesize, since obp can | 392 | for (i = 0; i < prom_trans_ents; i++) { |
420 | * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS -> | 393 | struct linux_prom_translation *p = &prom_trans[i]; |
421 | * HI_OBP_ADDRESS range are handled in entry.S and do not use the vpte | ||
422 | * scheme (also, see rant in inherit_locked_prom_mappings()). | ||
423 | */ | ||
424 | static void __init build_obp_range(unsigned long start, unsigned long end, unsigned long data) | ||
425 | { | ||
426 | unsigned long vaddr; | ||
427 | 394 | ||
428 | for (vaddr = start; vaddr < end; vaddr += BASE_PAGE_SIZE) { | 395 | if (promva >= p->virt && |
429 | unsigned long val; | 396 | promva < (p->virt + p->size)) { |
430 | pmd_t *pmd; | 397 | unsigned long base = p->data & _PAGE_PADDR; |
431 | pte_t *pte; | ||
432 | 398 | ||
433 | pmd = prompmd + ((vaddr >> 23) & 0x7ff); | 399 | if (error) |
434 | if (pmd_none(*pmd)) { | 400 | *error = 0; |
435 | pte = __alloc_bootmem(BASE_PAGE_SIZE, BASE_PAGE_SIZE, | 401 | return base + (promva & (8192 - 1)); |
436 | PAGE_SIZE); | ||
437 | if (!pte) | ||
438 | prom_halt(); | ||
439 | memset(pte, 0, BASE_PAGE_SIZE); | ||
440 | pmd_set(pmd, pte); | ||
441 | } | 402 | } |
442 | pte = (pte_t *) __pmd_page(*pmd) + ((vaddr >> 13) & 0x3ff); | ||
443 | |||
444 | val = data; | ||
445 | |||
446 | /* Clear diag TTE bits. */ | ||
447 | if (tlb_type == spitfire) | ||
448 | val &= ~0x0003fe0000000000UL; | ||
449 | |||
450 | set_pte_at(&init_mm, vaddr, pte, | ||
451 | __pte(val | _PAGE_MODIFIED)); | ||
452 | |||
453 | data += BASE_PAGE_SIZE; | ||
454 | } | 403 | } |
404 | if (error) | ||
405 | *error = 1; | ||
406 | return 0UL; | ||
455 | } | 407 | } |
456 | 408 | ||
409 | /* The obp translations are saved based on 8k pagesize, since obp can | ||
410 | * use a mixture of pagesizes. Misses to the LOW_OBP_ADDRESS -> | ||
411 | * HI_OBP_ADDRESS range are handled in ktlb.S and do not use the vpte | ||
412 | * scheme (also, see rant in inherit_locked_prom_mappings()). | ||
413 | */ | ||
457 | static inline int in_obp_range(unsigned long vaddr) | 414 | static inline int in_obp_range(unsigned long vaddr) |
458 | { | 415 | { |
459 | return (vaddr >= LOW_OBP_ADDRESS && | 416 | return (vaddr >= LOW_OBP_ADDRESS && |
460 | vaddr < HI_OBP_ADDRESS); | 417 | vaddr < HI_OBP_ADDRESS); |
461 | } | 418 | } |
462 | 419 | ||
463 | #define OBP_PMD_SIZE 2048 | 420 | static int cmp_ptrans(const void *a, const void *b) |
464 | static void __init build_obp_pgtable(void) | ||
465 | { | 421 | { |
466 | unsigned long i; | 422 | const struct linux_prom_translation *x = a, *y = b; |
467 | |||
468 | prompmd = __alloc_bootmem(OBP_PMD_SIZE, OBP_PMD_SIZE, PAGE_SIZE); | ||
469 | if (!prompmd) | ||
470 | prom_halt(); | ||
471 | |||
472 | memset(prompmd, 0, OBP_PMD_SIZE); | ||
473 | |||
474 | prom_pmd_phys = __pa(prompmd); | ||
475 | |||
476 | for (i = 0; i < prom_trans_ents; i++) { | ||
477 | unsigned long start, end; | ||
478 | |||
479 | if (!in_obp_range(prom_trans[i].virt)) | ||
480 | continue; | ||
481 | 423 | ||
482 | start = prom_trans[i].virt; | 424 | if (x->virt > y->virt) |
483 | end = start + prom_trans[i].size; | 425 | return 1; |
484 | if (end > HI_OBP_ADDRESS) | 426 | if (x->virt < y->virt) |
485 | end = HI_OBP_ADDRESS; | 427 | return -1; |
486 | 428 | return 0; | |
487 | build_obp_range(start, end, prom_trans[i].data); | ||
488 | } | ||
489 | } | 429 | } |
490 | 430 | ||
491 | /* Read OBP translations property into 'prom_trans[]'. | 431 | /* Read OBP translations property into 'prom_trans[]'. */ |
492 | * Return the number of entries. | ||
493 | */ | ||
494 | static void __init read_obp_translations(void) | 432 | static void __init read_obp_translations(void) |
495 | { | 433 | { |
496 | int n, node; | 434 | int n, node, ents, first, last, i; |
497 | 435 | ||
498 | node = prom_finddevice("/virtual-memory"); | 436 | node = prom_finddevice("/virtual-memory"); |
499 | n = prom_getproplen(node, "translations"); | 437 | n = prom_getproplen(node, "translations"); |
@@ -515,7 +453,41 @@ static void __init read_obp_translations(void) | |||
515 | 453 | ||
516 | n = n / sizeof(struct linux_prom_translation); | 454 | n = n / sizeof(struct linux_prom_translation); |
517 | 455 | ||
518 | prom_trans_ents = n; | 456 | ents = n; |
457 | |||
458 | sort(prom_trans, ents, sizeof(struct linux_prom_translation), | ||
459 | cmp_ptrans, NULL); | ||
460 | |||
461 | /* Now kick out all the non-OBP entries. */ | ||
462 | for (i = 0; i < ents; i++) { | ||
463 | if (in_obp_range(prom_trans[i].virt)) | ||
464 | break; | ||
465 | } | ||
466 | first = i; | ||
467 | for (; i < ents; i++) { | ||
468 | if (!in_obp_range(prom_trans[i].virt)) | ||
469 | break; | ||
470 | } | ||
471 | last = i; | ||
472 | |||
473 | for (i = 0; i < (last - first); i++) { | ||
474 | struct linux_prom_translation *src = &prom_trans[i + first]; | ||
475 | struct linux_prom_translation *dest = &prom_trans[i]; | ||
476 | |||
477 | *dest = *src; | ||
478 | } | ||
479 | for (; i < ents; i++) { | ||
480 | struct linux_prom_translation *dest = &prom_trans[i]; | ||
481 | dest->virt = dest->size = dest->data = 0x0UL; | ||
482 | } | ||
483 | |||
484 | prom_trans_ents = last - first; | ||
485 | |||
486 | if (tlb_type == spitfire) { | ||
487 | /* Clear diag TTE bits. */ | ||
488 | for (i = 0; i < prom_trans_ents; i++) | ||
489 | prom_trans[i].data &= ~0x0003fe0000000000UL; | ||
490 | } | ||
519 | } | 491 | } |
520 | 492 | ||
521 | static void __init remap_kernel(void) | 493 | static void __init remap_kernel(void) |
@@ -553,21 +525,18 @@ static void __init remap_kernel(void) | |||
553 | } | 525 | } |
554 | 526 | ||
555 | 527 | ||
556 | static void __init inherit_prom_mappings_pre(void) | 528 | static void __init inherit_prom_mappings(void) |
557 | { | 529 | { |
558 | read_obp_translations(); | 530 | read_obp_translations(); |
559 | 531 | ||
560 | /* Now fixup OBP's idea about where we really are mapped. */ | 532 | /* Now fixup OBP's idea about where we really are mapped. */ |
561 | prom_printf("Remapping the kernel... "); | 533 | prom_printf("Remapping the kernel... "); |
562 | remap_kernel(); | 534 | remap_kernel(); |
563 | |||
564 | prom_printf("done.\n"); | 535 | prom_printf("done.\n"); |
565 | } | ||
566 | 536 | ||
567 | static void __init inherit_prom_mappings_post(void) | 537 | prom_printf("Registering callbacks... "); |
568 | { | ||
569 | build_obp_pgtable(); | ||
570 | register_prom_callbacks(); | 538 | register_prom_callbacks(); |
539 | prom_printf("done.\n"); | ||
571 | } | 540 | } |
572 | 541 | ||
573 | /* The OBP specifications for sun4u mark 0xfffffffc00000000 and | 542 | /* The OBP specifications for sun4u mark 0xfffffffc00000000 and |
@@ -1519,7 +1488,7 @@ void __init paging_init(void) | |||
1519 | 1488 | ||
1520 | swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); | 1489 | swapper_pgd_zero = pgd_val(swapper_pg_dir[0]); |
1521 | 1490 | ||
1522 | inherit_prom_mappings_pre(); | 1491 | inherit_prom_mappings(); |
1523 | 1492 | ||
1524 | /* Ok, we can use our TLB miss and window trap handlers safely. | 1493 | /* Ok, we can use our TLB miss and window trap handlers safely. |
1525 | * We need to do a quick peek here to see if we are on StarFire | 1494 | * We need to do a quick peek here to see if we are on StarFire |
@@ -1530,23 +1499,15 @@ void __init paging_init(void) | |||
1530 | extern void setup_tba(int); | 1499 | extern void setup_tba(int); |
1531 | setup_tba(this_is_starfire); | 1500 | setup_tba(this_is_starfire); |
1532 | } | 1501 | } |
1533 | __flush_tlb_all(); | ||
1534 | 1502 | ||
1535 | /* Everything from this point forward, until we are done with | 1503 | inherit_locked_prom_mappings(1); |
1536 | * inherit_prom_mappings_post(), must complete successfully | 1504 | |
1537 | * without calling into the firmware. The firwmare page tables | 1505 | __flush_tlb_all(); |
1538 | * have not been built, but we are running on the Linux kernel's | ||
1539 | * trap table. | ||
1540 | */ | ||
1541 | 1506 | ||
1542 | /* Setup bootmem... */ | 1507 | /* Setup bootmem... */ |
1543 | pages_avail = 0; | 1508 | pages_avail = 0; |
1544 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail); | 1509 | last_valid_pfn = end_pfn = bootmem_init(&pages_avail); |
1545 | 1510 | ||
1546 | inherit_prom_mappings_post(); | ||
1547 | |||
1548 | inherit_locked_prom_mappings(1); | ||
1549 | |||
1550 | #ifdef CONFIG_DEBUG_PAGEALLOC | 1511 | #ifdef CONFIG_DEBUG_PAGEALLOC |
1551 | kernel_physical_mapping_init(); | 1512 | kernel_physical_mapping_init(); |
1552 | #endif | 1513 | #endif |
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index 058b8126c1a7..e4c9151fa116 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S | |||
@@ -453,22 +453,6 @@ xcall_flush_dcache_page_spitfire: /* %g1 == physical page address | |||
453 | nop | 453 | nop |
454 | nop | 454 | nop |
455 | 455 | ||
456 | .globl xcall_promstop | ||
457 | xcall_promstop: | ||
458 | rdpr %pstate, %g2 | ||
459 | wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate | ||
460 | rdpr %pil, %g2 | ||
461 | wrpr %g0, 15, %pil | ||
462 | sethi %hi(109f), %g7 | ||
463 | b,pt %xcc, etrap_irq | ||
464 | 109: or %g7, %lo(109b), %g7 | ||
465 | flushw | ||
466 | call prom_stopself | ||
467 | nop | ||
468 | /* We should not return, just spin if we do... */ | ||
469 | 1: b,a,pt %xcc, 1b | ||
470 | nop | ||
471 | |||
472 | .data | 456 | .data |
473 | 457 | ||
474 | errata32_hwbug: | 458 | errata32_hwbug: |
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 9b895faf077b..87f5cfce23bb 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c | |||
@@ -68,19 +68,11 @@ void prom_cmdline(void) | |||
68 | local_irq_restore(flags); | 68 | local_irq_restore(flags); |
69 | } | 69 | } |
70 | 70 | ||
71 | #ifdef CONFIG_SMP | ||
72 | extern void smp_promstop_others(void); | ||
73 | #endif | ||
74 | |||
75 | /* Drop into the prom, but completely terminate the program. | 71 | /* Drop into the prom, but completely terminate the program. |
76 | * No chance of continuing. | 72 | * No chance of continuing. |
77 | */ | 73 | */ |
78 | void prom_halt(void) | 74 | void prom_halt(void) |
79 | { | 75 | { |
80 | #ifdef CONFIG_SMP | ||
81 | smp_promstop_others(); | ||
82 | udelay(8000); | ||
83 | #endif | ||
84 | again: | 76 | again: |
85 | p1275_cmd("exit", P1275_INOUT(0, 0)); | 77 | p1275_cmd("exit", P1275_INOUT(0, 0)); |
86 | goto again; /* PROM is out to get me -DaveM */ | 78 | goto again; /* PROM is out to get me -DaveM */ |
@@ -88,10 +80,6 @@ again: | |||
88 | 80 | ||
89 | void prom_halt_power_off(void) | 81 | void prom_halt_power_off(void) |
90 | { | 82 | { |
91 | #ifdef CONFIG_SMP | ||
92 | smp_promstop_others(); | ||
93 | udelay(8000); | ||
94 | #endif | ||
95 | p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0)); | 83 | p1275_cmd("SUNW,power-off", P1275_INOUT(0, 0)); |
96 | 84 | ||
97 | /* if nothing else helps, we just halt */ | 85 | /* if nothing else helps, we just halt */ |
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile index 783e18cae090..de17d4c6e02d 100644 --- a/arch/um/drivers/Makefile +++ b/arch/um/drivers/Makefile | |||
@@ -13,7 +13,7 @@ mcast-objs := mcast_kern.o mcast_user.o | |||
13 | net-objs := net_kern.o net_user.o | 13 | net-objs := net_kern.o net_user.o |
14 | mconsole-objs := mconsole_kern.o mconsole_user.o | 14 | mconsole-objs := mconsole_kern.o mconsole_user.o |
15 | hostaudio-objs := hostaudio_kern.o | 15 | hostaudio-objs := hostaudio_kern.o |
16 | ubd-objs := ubd_kern.o | 16 | ubd-objs := ubd_kern.o ubd_user.o |
17 | port-objs := port_kern.o port_user.o | 17 | port-objs := port_kern.o port_user.o |
18 | harddog-objs := harddog_kern.o harddog_user.o | 18 | harddog-objs := harddog_kern.o harddog_user.o |
19 | 19 | ||
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index e77a38da4350..f73134333f64 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -35,7 +35,6 @@ | |||
35 | #include "linux/blkpg.h" | 35 | #include "linux/blkpg.h" |
36 | #include "linux/genhd.h" | 36 | #include "linux/genhd.h" |
37 | #include "linux/spinlock.h" | 37 | #include "linux/spinlock.h" |
38 | #include "asm/atomic.h" | ||
39 | #include "asm/segment.h" | 38 | #include "asm/segment.h" |
40 | #include "asm/uaccess.h" | 39 | #include "asm/uaccess.h" |
41 | #include "asm/irq.h" | 40 | #include "asm/irq.h" |
@@ -54,21 +53,20 @@ | |||
54 | #include "mem.h" | 53 | #include "mem.h" |
55 | #include "mem_kern.h" | 54 | #include "mem_kern.h" |
56 | #include "cow.h" | 55 | #include "cow.h" |
57 | #include "aio.h" | ||
58 | 56 | ||
59 | enum ubd_req { UBD_READ, UBD_WRITE }; | 57 | enum ubd_req { UBD_READ, UBD_WRITE }; |
60 | 58 | ||
61 | struct io_thread_req { | 59 | struct io_thread_req { |
62 | enum aio_type op; | 60 | enum ubd_req op; |
63 | int fds[2]; | 61 | int fds[2]; |
64 | unsigned long offsets[2]; | 62 | unsigned long offsets[2]; |
65 | unsigned long long offset; | 63 | unsigned long long offset; |
66 | unsigned long length; | 64 | unsigned long length; |
67 | char *buffer; | 65 | char *buffer; |
68 | int sectorsize; | 66 | int sectorsize; |
69 | int bitmap_offset; | 67 | unsigned long sector_mask; |
70 | long bitmap_start; | 68 | unsigned long long cow_offset; |
71 | long bitmap_end; | 69 | unsigned long bitmap_words[2]; |
72 | int error; | 70 | int error; |
73 | }; | 71 | }; |
74 | 72 | ||
@@ -82,31 +80,28 @@ extern int create_cow_file(char *cow_file, char *backing_file, | |||
82 | unsigned long *bitmap_len_out, | 80 | unsigned long *bitmap_len_out, |
83 | int *data_offset_out); | 81 | int *data_offset_out); |
84 | extern int read_cow_bitmap(int fd, void *buf, int offset, int len); | 82 | extern int read_cow_bitmap(int fd, void *buf, int offset, int len); |
85 | extern void do_io(struct io_thread_req *req, struct request *r, | 83 | extern void do_io(struct io_thread_req *req); |
86 | unsigned long *bitmap); | ||
87 | 84 | ||
88 | static inline int ubd_test_bit(__u64 bit, void *data) | 85 | static inline int ubd_test_bit(__u64 bit, unsigned char *data) |
89 | { | 86 | { |
90 | unsigned char *buffer = data; | ||
91 | __u64 n; | 87 | __u64 n; |
92 | int bits, off; | 88 | int bits, off; |
93 | 89 | ||
94 | bits = sizeof(buffer[0]) * 8; | 90 | bits = sizeof(data[0]) * 8; |
95 | n = bit / bits; | 91 | n = bit / bits; |
96 | off = bit % bits; | 92 | off = bit % bits; |
97 | return((buffer[n] & (1 << off)) != 0); | 93 | return((data[n] & (1 << off)) != 0); |
98 | } | 94 | } |
99 | 95 | ||
100 | static inline void ubd_set_bit(__u64 bit, void *data) | 96 | static inline void ubd_set_bit(__u64 bit, unsigned char *data) |
101 | { | 97 | { |
102 | unsigned char *buffer = data; | ||
103 | __u64 n; | 98 | __u64 n; |
104 | int bits, off; | 99 | int bits, off; |
105 | 100 | ||
106 | bits = sizeof(buffer[0]) * 8; | 101 | bits = sizeof(data[0]) * 8; |
107 | n = bit / bits; | 102 | n = bit / bits; |
108 | off = bit % bits; | 103 | off = bit % bits; |
109 | buffer[n] |= (1 << off); | 104 | data[n] |= (1 << off); |
110 | } | 105 | } |
111 | /*End stuff from ubd_user.h*/ | 106 | /*End stuff from ubd_user.h*/ |
112 | 107 | ||
@@ -115,6 +110,8 @@ static inline void ubd_set_bit(__u64 bit, void *data) | |||
115 | static DEFINE_SPINLOCK(ubd_io_lock); | 110 | static DEFINE_SPINLOCK(ubd_io_lock); |
116 | static DEFINE_SPINLOCK(ubd_lock); | 111 | static DEFINE_SPINLOCK(ubd_lock); |
117 | 112 | ||
113 | static void (*do_ubd)(void); | ||
114 | |||
118 | static int ubd_open(struct inode * inode, struct file * filp); | 115 | static int ubd_open(struct inode * inode, struct file * filp); |
119 | static int ubd_release(struct inode * inode, struct file * file); | 116 | static int ubd_release(struct inode * inode, struct file * file); |
120 | static int ubd_ioctl(struct inode * inode, struct file * file, | 117 | static int ubd_ioctl(struct inode * inode, struct file * file, |
@@ -161,8 +158,6 @@ struct cow { | |||
161 | int data_offset; | 158 | int data_offset; |
162 | }; | 159 | }; |
163 | 160 | ||
164 | #define MAX_SG 64 | ||
165 | |||
166 | struct ubd { | 161 | struct ubd { |
167 | char *file; | 162 | char *file; |
168 | int count; | 163 | int count; |
@@ -173,7 +168,6 @@ struct ubd { | |||
173 | int no_cow; | 168 | int no_cow; |
174 | struct cow cow; | 169 | struct cow cow; |
175 | struct platform_device pdev; | 170 | struct platform_device pdev; |
176 | struct scatterlist sg[MAX_SG]; | ||
177 | }; | 171 | }; |
178 | 172 | ||
179 | #define DEFAULT_COW { \ | 173 | #define DEFAULT_COW { \ |
@@ -466,114 +460,81 @@ __uml_help(fakehd, | |||
466 | ); | 460 | ); |
467 | 461 | ||
468 | static void do_ubd_request(request_queue_t * q); | 462 | static void do_ubd_request(request_queue_t * q); |
469 | static int in_ubd; | 463 | |
464 | /* Only changed by ubd_init, which is an initcall. */ | ||
465 | int thread_fd = -1; | ||
470 | 466 | ||
471 | /* Changed by ubd_handler, which is serialized because interrupts only | 467 | /* Changed by ubd_handler, which is serialized because interrupts only |
472 | * happen on CPU 0. | 468 | * happen on CPU 0. |
473 | */ | 469 | */ |
474 | int intr_count = 0; | 470 | int intr_count = 0; |
475 | 471 | ||
476 | static void ubd_end_request(struct request *req, int bytes, int uptodate) | 472 | /* call ubd_finish if you need to serialize */ |
473 | static void __ubd_finish(struct request *req, int error) | ||
477 | { | 474 | { |
478 | if (!end_that_request_first(req, uptodate, bytes >> 9)) { | 475 | int nsect; |
479 | add_disk_randomness(req->rq_disk); | 476 | |
480 | end_that_request_last(req); | 477 | if(error){ |
478 | end_request(req, 0); | ||
479 | return; | ||
481 | } | 480 | } |
481 | nsect = req->current_nr_sectors; | ||
482 | req->sector += nsect; | ||
483 | req->buffer += nsect << 9; | ||
484 | req->errors = 0; | ||
485 | req->nr_sectors -= nsect; | ||
486 | req->current_nr_sectors = 0; | ||
487 | end_request(req, 1); | ||
482 | } | 488 | } |
483 | 489 | ||
484 | /* call ubd_finish if you need to serialize */ | 490 | static inline void ubd_finish(struct request *req, int error) |
485 | static void __ubd_finish(struct request *req, int bytes) | ||
486 | { | 491 | { |
487 | if(bytes < 0){ | 492 | spin_lock(&ubd_io_lock); |
488 | ubd_end_request(req, 0, 0); | 493 | __ubd_finish(req, error); |
489 | return; | 494 | spin_unlock(&ubd_io_lock); |
490 | } | ||
491 | |||
492 | ubd_end_request(req, bytes, 1); | ||
493 | } | 495 | } |
494 | 496 | ||
495 | static inline void ubd_finish(struct request *req, int bytes) | 497 | /* Called without ubd_io_lock held */ |
498 | static void ubd_handler(void) | ||
496 | { | 499 | { |
497 | spin_lock(&ubd_io_lock); | 500 | struct io_thread_req req; |
498 | __ubd_finish(req, bytes); | 501 | struct request *rq = elv_next_request(ubd_queue); |
499 | spin_unlock(&ubd_io_lock); | 502 | int n; |
503 | |||
504 | do_ubd = NULL; | ||
505 | intr_count++; | ||
506 | n = os_read_file(thread_fd, &req, sizeof(req)); | ||
507 | if(n != sizeof(req)){ | ||
508 | printk(KERN_ERR "Pid %d - spurious interrupt in ubd_handler, " | ||
509 | "err = %d\n", os_getpid(), -n); | ||
510 | spin_lock(&ubd_io_lock); | ||
511 | end_request(rq, 0); | ||
512 | spin_unlock(&ubd_io_lock); | ||
513 | return; | ||
514 | } | ||
515 | |||
516 | ubd_finish(rq, req.error); | ||
517 | reactivate_fd(thread_fd, UBD_IRQ); | ||
518 | do_ubd_request(ubd_queue); | ||
500 | } | 519 | } |
501 | 520 | ||
502 | struct bitmap_io { | ||
503 | atomic_t count; | ||
504 | struct aio_context aio; | ||
505 | }; | ||
506 | |||
507 | struct ubd_aio { | ||
508 | struct aio_context aio; | ||
509 | struct request *req; | ||
510 | int len; | ||
511 | struct bitmap_io *bitmap; | ||
512 | void *bitmap_buf; | ||
513 | }; | ||
514 | |||
515 | static int ubd_reply_fd = -1; | ||
516 | |||
517 | static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) | 521 | static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused) |
518 | { | 522 | { |
519 | struct aio_thread_reply reply; | 523 | ubd_handler(); |
520 | struct ubd_aio *aio; | 524 | return(IRQ_HANDLED); |
521 | struct request *req; | 525 | } |
522 | int err, n, fd = (int) (long) dev; | ||
523 | |||
524 | while(1){ | ||
525 | err = os_read_file(fd, &reply, sizeof(reply)); | ||
526 | if(err == -EAGAIN) | ||
527 | break; | ||
528 | if(err < 0){ | ||
529 | printk("ubd_aio_handler - read returned err %d\n", | ||
530 | -err); | ||
531 | break; | ||
532 | } | ||
533 | |||
534 | aio = container_of(reply.data, struct ubd_aio, aio); | ||
535 | n = reply.err; | ||
536 | |||
537 | if(n == 0){ | ||
538 | req = aio->req; | ||
539 | req->nr_sectors -= aio->len >> 9; | ||
540 | |||
541 | if((aio->bitmap != NULL) && | ||
542 | (atomic_dec_and_test(&aio->bitmap->count))){ | ||
543 | aio->aio = aio->bitmap->aio; | ||
544 | aio->len = 0; | ||
545 | kfree(aio->bitmap); | ||
546 | aio->bitmap = NULL; | ||
547 | submit_aio(&aio->aio); | ||
548 | } | ||
549 | else { | ||
550 | if((req->nr_sectors == 0) && | ||
551 | (aio->bitmap == NULL)){ | ||
552 | int len = req->hard_nr_sectors << 9; | ||
553 | ubd_finish(req, len); | ||
554 | } | ||
555 | |||
556 | if(aio->bitmap_buf != NULL) | ||
557 | kfree(aio->bitmap_buf); | ||
558 | kfree(aio); | ||
559 | } | ||
560 | } | ||
561 | else if(n < 0){ | ||
562 | ubd_finish(aio->req, n); | ||
563 | if(aio->bitmap != NULL) | ||
564 | kfree(aio->bitmap); | ||
565 | if(aio->bitmap_buf != NULL) | ||
566 | kfree(aio->bitmap_buf); | ||
567 | kfree(aio); | ||
568 | } | ||
569 | } | ||
570 | reactivate_fd(fd, UBD_IRQ); | ||
571 | 526 | ||
572 | do_ubd_request(ubd_queue); | 527 | /* Only changed by ubd_init, which is an initcall. */ |
528 | static int io_pid = -1; | ||
573 | 529 | ||
574 | return(IRQ_HANDLED); | 530 | void kill_io_thread(void) |
531 | { | ||
532 | if(io_pid != -1) | ||
533 | os_kill_process(io_pid, 1); | ||
575 | } | 534 | } |
576 | 535 | ||
536 | __uml_exitcall(kill_io_thread); | ||
537 | |||
577 | static int ubd_file_size(struct ubd *dev, __u64 *size_out) | 538 | static int ubd_file_size(struct ubd *dev, __u64 *size_out) |
578 | { | 539 | { |
579 | char *file; | 540 | char *file; |
@@ -608,7 +569,7 @@ static int ubd_open_dev(struct ubd *dev) | |||
608 | &dev->cow.data_offset, create_ptr); | 569 | &dev->cow.data_offset, create_ptr); |
609 | 570 | ||
610 | if((dev->fd == -ENOENT) && create_cow){ | 571 | if((dev->fd == -ENOENT) && create_cow){ |
611 | dev->fd = create_cow_file(dev->file, dev->cow.file, | 572 | dev->fd = create_cow_file(dev->file, dev->cow.file, |
612 | dev->openflags, 1 << 9, PAGE_SIZE, | 573 | dev->openflags, 1 << 9, PAGE_SIZE, |
613 | &dev->cow.bitmap_offset, | 574 | &dev->cow.bitmap_offset, |
614 | &dev->cow.bitmap_len, | 575 | &dev->cow.bitmap_len, |
@@ -870,10 +831,6 @@ int ubd_init(void) | |||
870 | { | 831 | { |
871 | int i; | 832 | int i; |
872 | 833 | ||
873 | ubd_reply_fd = init_aio_irq(UBD_IRQ, "ubd", ubd_intr); | ||
874 | if(ubd_reply_fd < 0) | ||
875 | printk("Setting up ubd AIO failed, err = %d\n", ubd_reply_fd); | ||
876 | |||
877 | devfs_mk_dir("ubd"); | 834 | devfs_mk_dir("ubd"); |
878 | if (register_blkdev(MAJOR_NR, "ubd")) | 835 | if (register_blkdev(MAJOR_NR, "ubd")) |
879 | return -1; | 836 | return -1; |
@@ -884,7 +841,6 @@ int ubd_init(void) | |||
884 | return -1; | 841 | return -1; |
885 | } | 842 | } |
886 | 843 | ||
887 | blk_queue_max_hw_segments(ubd_queue, MAX_SG); | ||
888 | if (fake_major != MAJOR_NR) { | 844 | if (fake_major != MAJOR_NR) { |
889 | char name[sizeof("ubd_nnn\0")]; | 845 | char name[sizeof("ubd_nnn\0")]; |
890 | 846 | ||
@@ -896,12 +852,40 @@ int ubd_init(void) | |||
896 | driver_register(&ubd_driver); | 852 | driver_register(&ubd_driver); |
897 | for (i = 0; i < MAX_DEV; i++) | 853 | for (i = 0; i < MAX_DEV; i++) |
898 | ubd_add(i); | 854 | ubd_add(i); |
899 | |||
900 | return 0; | 855 | return 0; |
901 | } | 856 | } |
902 | 857 | ||
903 | late_initcall(ubd_init); | 858 | late_initcall(ubd_init); |
904 | 859 | ||
860 | int ubd_driver_init(void){ | ||
861 | unsigned long stack; | ||
862 | int err; | ||
863 | |||
864 | /* Set by CONFIG_BLK_DEV_UBD_SYNC or ubd=sync.*/ | ||
865 | if(global_openflags.s){ | ||
866 | printk(KERN_INFO "ubd: Synchronous mode\n"); | ||
867 | /* Letting ubd=sync be like using ubd#s= instead of ubd#= is | ||
868 | * enough. So use anyway the io thread. */ | ||
869 | } | ||
870 | stack = alloc_stack(0, 0); | ||
871 | io_pid = start_io_thread(stack + PAGE_SIZE - sizeof(void *), | ||
872 | &thread_fd); | ||
873 | if(io_pid < 0){ | ||
874 | printk(KERN_ERR | ||
875 | "ubd : Failed to start I/O thread (errno = %d) - " | ||
876 | "falling back to synchronous I/O\n", -io_pid); | ||
877 | io_pid = -1; | ||
878 | return(0); | ||
879 | } | ||
880 | err = um_request_irq(UBD_IRQ, thread_fd, IRQ_READ, ubd_intr, | ||
881 | SA_INTERRUPT, "ubd", ubd_dev); | ||
882 | if(err != 0) | ||
883 | printk(KERN_ERR "um_request_irq failed - errno = %d\n", -err); | ||
884 | return(err); | ||
885 | } | ||
886 | |||
887 | device_initcall(ubd_driver_init); | ||
888 | |||
905 | static int ubd_open(struct inode *inode, struct file *filp) | 889 | static int ubd_open(struct inode *inode, struct file *filp) |
906 | { | 890 | { |
907 | struct gendisk *disk = inode->i_bdev->bd_disk; | 891 | struct gendisk *disk = inode->i_bdev->bd_disk; |
@@ -939,55 +923,105 @@ static int ubd_release(struct inode * inode, struct file * file) | |||
939 | return(0); | 923 | return(0); |
940 | } | 924 | } |
941 | 925 | ||
942 | static void cowify_bitmap(struct io_thread_req *req, unsigned long *bitmap) | 926 | static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, |
927 | __u64 *cow_offset, unsigned long *bitmap, | ||
928 | __u64 bitmap_offset, unsigned long *bitmap_words, | ||
929 | __u64 bitmap_len) | ||
943 | { | 930 | { |
944 | __u64 sector = req->offset / req->sectorsize; | 931 | __u64 sector = io_offset >> 9; |
945 | int i; | 932 | int i, update_bitmap = 0; |
933 | |||
934 | for(i = 0; i < length >> 9; i++){ | ||
935 | if(cow_mask != NULL) | ||
936 | ubd_set_bit(i, (unsigned char *) cow_mask); | ||
937 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) | ||
938 | continue; | ||
946 | 939 | ||
947 | for(i = 0; i < req->length / req->sectorsize; i++){ | 940 | update_bitmap = 1; |
948 | if(ubd_test_bit(sector + i, bitmap)) | 941 | ubd_set_bit(sector + i, (unsigned char *) bitmap); |
949 | continue; | 942 | } |
943 | |||
944 | if(!update_bitmap) | ||
945 | return; | ||
950 | 946 | ||
951 | if(req->bitmap_start == -1) | 947 | *cow_offset = sector / (sizeof(unsigned long) * 8); |
952 | req->bitmap_start = sector + i; | ||
953 | req->bitmap_end = sector + i + 1; | ||
954 | 948 | ||
955 | ubd_set_bit(sector + i, bitmap); | 949 | /* This takes care of the case where we're exactly at the end of the |
956 | } | 950 | * device, and *cow_offset + 1 is off the end. So, just back it up |
951 | * by one word. Thanks to Lynn Kerby for the fix and James McMechan | ||
952 | * for the original diagnosis. | ||
953 | */ | ||
954 | if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / | ||
955 | sizeof(unsigned long) - 1)) | ||
956 | (*cow_offset)--; | ||
957 | |||
958 | bitmap_words[0] = bitmap[*cow_offset]; | ||
959 | bitmap_words[1] = bitmap[*cow_offset + 1]; | ||
960 | |||
961 | *cow_offset *= sizeof(unsigned long); | ||
962 | *cow_offset += bitmap_offset; | ||
963 | } | ||
964 | |||
965 | static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, | ||
966 | __u64 bitmap_offset, __u64 bitmap_len) | ||
967 | { | ||
968 | __u64 sector = req->offset >> 9; | ||
969 | int i; | ||
970 | |||
971 | if(req->length > (sizeof(req->sector_mask) * 8) << 9) | ||
972 | panic("Operation too long"); | ||
973 | |||
974 | if(req->op == UBD_READ) { | ||
975 | for(i = 0; i < req->length >> 9; i++){ | ||
976 | if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) | ||
977 | ubd_set_bit(i, (unsigned char *) | ||
978 | &req->sector_mask); | ||
979 | } | ||
980 | } | ||
981 | else cowify_bitmap(req->offset, req->length, &req->sector_mask, | ||
982 | &req->cow_offset, bitmap, bitmap_offset, | ||
983 | req->bitmap_words, bitmap_len); | ||
957 | } | 984 | } |
958 | 985 | ||
959 | /* Called with ubd_io_lock held */ | 986 | /* Called with ubd_io_lock held */ |
960 | static int prepare_request(struct request *req, struct io_thread_req *io_req, | 987 | static int prepare_request(struct request *req, struct io_thread_req *io_req) |
961 | unsigned long long offset, int page_offset, | ||
962 | int len, struct page *page) | ||
963 | { | 988 | { |
964 | struct gendisk *disk = req->rq_disk; | 989 | struct gendisk *disk = req->rq_disk; |
965 | struct ubd *dev = disk->private_data; | 990 | struct ubd *dev = disk->private_data; |
991 | __u64 offset; | ||
992 | int len; | ||
993 | |||
994 | if(req->rq_status == RQ_INACTIVE) return(1); | ||
966 | 995 | ||
967 | /* This should be impossible now */ | 996 | /* This should be impossible now */ |
968 | if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ | 997 | if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ |
969 | printk("Write attempted on readonly ubd device %s\n", | 998 | printk("Write attempted on readonly ubd device %s\n", |
970 | disk->disk_name); | 999 | disk->disk_name); |
971 | ubd_end_request(req, 0, 0); | 1000 | end_request(req, 0); |
972 | return(1); | 1001 | return(1); |
973 | } | 1002 | } |
974 | 1003 | ||
1004 | offset = ((__u64) req->sector) << 9; | ||
1005 | len = req->current_nr_sectors << 9; | ||
1006 | |||
975 | io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; | 1007 | io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; |
976 | io_req->fds[1] = dev->fd; | 1008 | io_req->fds[1] = dev->fd; |
1009 | io_req->cow_offset = -1; | ||
977 | io_req->offset = offset; | 1010 | io_req->offset = offset; |
978 | io_req->length = len; | 1011 | io_req->length = len; |
979 | io_req->error = 0; | 1012 | io_req->error = 0; |
980 | io_req->op = (rq_data_dir(req) == READ) ? AIO_READ : AIO_WRITE; | 1013 | io_req->sector_mask = 0; |
1014 | |||
1015 | io_req->op = (rq_data_dir(req) == READ) ? UBD_READ : UBD_WRITE; | ||
981 | io_req->offsets[0] = 0; | 1016 | io_req->offsets[0] = 0; |
982 | io_req->offsets[1] = dev->cow.data_offset; | 1017 | io_req->offsets[1] = dev->cow.data_offset; |
983 | io_req->buffer = page_address(page) + page_offset; | 1018 | io_req->buffer = req->buffer; |
984 | io_req->sectorsize = 1 << 9; | 1019 | io_req->sectorsize = 1 << 9; |
985 | io_req->bitmap_offset = dev->cow.bitmap_offset; | ||
986 | io_req->bitmap_start = -1; | ||
987 | io_req->bitmap_end = -1; | ||
988 | 1020 | ||
989 | if((dev->cow.file != NULL) && (io_req->op == UBD_WRITE)) | 1021 | if(dev->cow.file != NULL) |
990 | cowify_bitmap(io_req, dev->cow.bitmap); | 1022 | cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset, |
1023 | dev->cow.bitmap_len); | ||
1024 | |||
991 | return(0); | 1025 | return(0); |
992 | } | 1026 | } |
993 | 1027 | ||
@@ -996,36 +1030,30 @@ static void do_ubd_request(request_queue_t *q) | |||
996 | { | 1030 | { |
997 | struct io_thread_req io_req; | 1031 | struct io_thread_req io_req; |
998 | struct request *req; | 1032 | struct request *req; |
999 | __u64 sector; | 1033 | int err, n; |
1000 | int err; | 1034 | |
1001 | 1035 | if(thread_fd == -1){ | |
1002 | if(in_ubd) | 1036 | while((req = elv_next_request(q)) != NULL){ |
1003 | return; | 1037 | err = prepare_request(req, &io_req); |
1004 | in_ubd = 1; | 1038 | if(!err){ |
1005 | while((req = elv_next_request(q)) != NULL){ | 1039 | do_io(&io_req); |
1006 | struct gendisk *disk = req->rq_disk; | 1040 | __ubd_finish(req, io_req.error); |
1007 | struct ubd *dev = disk->private_data; | 1041 | } |
1008 | int n, i; | 1042 | } |
1009 | 1043 | } | |
1010 | blkdev_dequeue_request(req); | 1044 | else { |
1011 | 1045 | if(do_ubd || (req = elv_next_request(q)) == NULL) | |
1012 | sector = req->sector; | 1046 | return; |
1013 | n = blk_rq_map_sg(q, req, dev->sg); | 1047 | err = prepare_request(req, &io_req); |
1014 | 1048 | if(!err){ | |
1015 | for(i = 0; i < n; i++){ | 1049 | do_ubd = ubd_handler; |
1016 | struct scatterlist *sg = &dev->sg[i]; | 1050 | n = os_write_file(thread_fd, (char *) &io_req, |
1017 | 1051 | sizeof(io_req)); | |
1018 | err = prepare_request(req, &io_req, sector << 9, | 1052 | if(n != sizeof(io_req)) |
1019 | sg->offset, sg->length, | 1053 | printk("write to io thread failed, " |
1020 | sg->page); | 1054 | "errno = %d\n", -n); |
1021 | if(err) | ||
1022 | continue; | ||
1023 | |||
1024 | sector += sg->length >> 9; | ||
1025 | do_io(&io_req, req, dev->cow.bitmap); | ||
1026 | } | 1055 | } |
1027 | } | 1056 | } |
1028 | in_ubd = 0; | ||
1029 | } | 1057 | } |
1030 | 1058 | ||
1031 | static int ubd_ioctl(struct inode * inode, struct file * file, | 1059 | static int ubd_ioctl(struct inode * inode, struct file * file, |
@@ -1241,95 +1269,131 @@ int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, | |||
1241 | return(err); | 1269 | return(err); |
1242 | } | 1270 | } |
1243 | 1271 | ||
1244 | void do_io(struct io_thread_req *req, struct request *r, unsigned long *bitmap) | 1272 | static int update_bitmap(struct io_thread_req *req) |
1245 | { | 1273 | { |
1246 | struct ubd_aio *aio; | 1274 | int n; |
1247 | struct bitmap_io *bitmap_io = NULL; | ||
1248 | char *buf; | ||
1249 | void *bitmap_buf = NULL; | ||
1250 | unsigned long len, sector; | ||
1251 | int nsectors, start, end, bit, err; | ||
1252 | __u64 off; | ||
1253 | |||
1254 | if(req->bitmap_start != -1){ | ||
1255 | /* Round up to the nearest word */ | ||
1256 | int round = sizeof(unsigned long); | ||
1257 | len = (req->bitmap_end - req->bitmap_start + | ||
1258 | round * 8 - 1) / (round * 8); | ||
1259 | len *= round; | ||
1260 | |||
1261 | off = req->bitmap_start / (8 * round); | ||
1262 | off *= round; | ||
1263 | |||
1264 | bitmap_io = kmalloc(sizeof(*bitmap_io), GFP_KERNEL); | ||
1265 | if(bitmap_io == NULL){ | ||
1266 | printk("Failed to kmalloc bitmap IO\n"); | ||
1267 | req->error = 1; | ||
1268 | return; | ||
1269 | } | ||
1270 | 1275 | ||
1271 | bitmap_buf = kmalloc(len, GFP_KERNEL); | 1276 | if(req->cow_offset == -1) |
1272 | if(bitmap_buf == NULL){ | 1277 | return(0); |
1273 | printk("do_io : kmalloc of bitmap chunk " | ||
1274 | "failed\n"); | ||
1275 | kfree(bitmap_io); | ||
1276 | req->error = 1; | ||
1277 | return; | ||
1278 | } | ||
1279 | memcpy(bitmap_buf, &bitmap[off / sizeof(bitmap[0])], len); | ||
1280 | |||
1281 | *bitmap_io = ((struct bitmap_io) | ||
1282 | { .count = ATOMIC_INIT(0), | ||
1283 | .aio = INIT_AIO(AIO_WRITE, req->fds[1], | ||
1284 | bitmap_buf, len, | ||
1285 | req->bitmap_offset + off, | ||
1286 | ubd_reply_fd) } ); | ||
1287 | } | ||
1288 | 1278 | ||
1289 | nsectors = req->length / req->sectorsize; | 1279 | n = os_seek_file(req->fds[1], req->cow_offset); |
1290 | start = 0; | 1280 | if(n < 0){ |
1291 | end = nsectors; | 1281 | printk("do_io - bitmap lseek failed : err = %d\n", -n); |
1292 | bit = 0; | 1282 | return(1); |
1293 | do { | 1283 | } |
1294 | if(bitmap != NULL){ | ||
1295 | sector = req->offset / req->sectorsize; | ||
1296 | bit = ubd_test_bit(sector + start, bitmap); | ||
1297 | end = start; | ||
1298 | while((end < nsectors) && | ||
1299 | (ubd_test_bit(sector + end, bitmap) == bit)) | ||
1300 | end++; | ||
1301 | } | ||
1302 | 1284 | ||
1303 | off = req->offsets[bit] + req->offset + | 1285 | n = os_write_file(req->fds[1], &req->bitmap_words, |
1304 | start * req->sectorsize; | 1286 | sizeof(req->bitmap_words)); |
1305 | len = (end - start) * req->sectorsize; | 1287 | if(n != sizeof(req->bitmap_words)){ |
1306 | buf = &req->buffer[start * req->sectorsize]; | 1288 | printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, |
1289 | req->fds[1]); | ||
1290 | return(1); | ||
1291 | } | ||
1307 | 1292 | ||
1308 | aio = kmalloc(sizeof(*aio), GFP_KERNEL); | 1293 | return(0); |
1309 | if(aio == NULL){ | 1294 | } |
1310 | req->error = 1; | ||
1311 | return; | ||
1312 | } | ||
1313 | 1295 | ||
1314 | *aio = ((struct ubd_aio) | 1296 | void do_io(struct io_thread_req *req) |
1315 | { .aio = INIT_AIO(req->op, req->fds[bit], buf, | 1297 | { |
1316 | len, off, ubd_reply_fd), | 1298 | char *buf; |
1317 | .len = len, | 1299 | unsigned long len; |
1318 | .req = r, | 1300 | int n, nsectors, start, end, bit; |
1319 | .bitmap = bitmap_io, | 1301 | int err; |
1320 | .bitmap_buf = bitmap_buf }); | 1302 | __u64 off; |
1321 | 1303 | ||
1322 | if(aio->bitmap != NULL) | 1304 | nsectors = req->length / req->sectorsize; |
1323 | atomic_inc(&aio->bitmap->count); | 1305 | start = 0; |
1324 | 1306 | do { | |
1325 | err = submit_aio(&aio->aio); | 1307 | bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask); |
1326 | if(err){ | 1308 | end = start; |
1327 | printk("do_io - submit_aio failed, " | 1309 | while((end < nsectors) && |
1328 | "err = %d\n", err); | 1310 | (ubd_test_bit(end, (unsigned char *) |
1329 | req->error = 1; | 1311 | &req->sector_mask) == bit)) |
1330 | return; | 1312 | end++; |
1331 | } | 1313 | |
1314 | off = req->offset + req->offsets[bit] + | ||
1315 | start * req->sectorsize; | ||
1316 | len = (end - start) * req->sectorsize; | ||
1317 | buf = &req->buffer[start * req->sectorsize]; | ||
1318 | |||
1319 | err = os_seek_file(req->fds[bit], off); | ||
1320 | if(err < 0){ | ||
1321 | printk("do_io - lseek failed : err = %d\n", -err); | ||
1322 | req->error = 1; | ||
1323 | return; | ||
1324 | } | ||
1325 | if(req->op == UBD_READ){ | ||
1326 | n = 0; | ||
1327 | do { | ||
1328 | buf = &buf[n]; | ||
1329 | len -= n; | ||
1330 | n = os_read_file(req->fds[bit], buf, len); | ||
1331 | if (n < 0) { | ||
1332 | printk("do_io - read failed, err = %d " | ||
1333 | "fd = %d\n", -n, req->fds[bit]); | ||
1334 | req->error = 1; | ||
1335 | return; | ||
1336 | } | ||
1337 | } while((n < len) && (n != 0)); | ||
1338 | if (n < len) memset(&buf[n], 0, len - n); | ||
1339 | } else { | ||
1340 | n = os_write_file(req->fds[bit], buf, len); | ||
1341 | if(n != len){ | ||
1342 | printk("do_io - write failed err = %d " | ||
1343 | "fd = %d\n", -n, req->fds[bit]); | ||
1344 | req->error = 1; | ||
1345 | return; | ||
1346 | } | ||
1347 | } | ||
1348 | |||
1349 | start = end; | ||
1350 | } while(start < nsectors); | ||
1332 | 1351 | ||
1333 | start = end; | 1352 | req->error = update_bitmap(req); |
1334 | } while(start < nsectors); | ||
1335 | } | 1353 | } |
1354 | |||
1355 | /* Changed in start_io_thread, which is serialized by being called only | ||
1356 | * from ubd_init, which is an initcall. | ||
1357 | */ | ||
1358 | int kernel_fd = -1; | ||
1359 | |||
1360 | /* Only changed by the io thread */ | ||
1361 | int io_count = 0; | ||
1362 | |||
1363 | int io_thread(void *arg) | ||
1364 | { | ||
1365 | struct io_thread_req req; | ||
1366 | int n; | ||
1367 | |||
1368 | ignore_sigwinch_sig(); | ||
1369 | while(1){ | ||
1370 | n = os_read_file(kernel_fd, &req, sizeof(req)); | ||
1371 | if(n != sizeof(req)){ | ||
1372 | if(n < 0) | ||
1373 | printk("io_thread - read failed, fd = %d, " | ||
1374 | "err = %d\n", kernel_fd, -n); | ||
1375 | else { | ||
1376 | printk("io_thread - short read, fd = %d, " | ||
1377 | "length = %d\n", kernel_fd, n); | ||
1378 | } | ||
1379 | continue; | ||
1380 | } | ||
1381 | io_count++; | ||
1382 | do_io(&req); | ||
1383 | n = os_write_file(kernel_fd, &req, sizeof(req)); | ||
1384 | if(n != sizeof(req)) | ||
1385 | printk("io_thread - write failed, fd = %d, err = %d\n", | ||
1386 | kernel_fd, -n); | ||
1387 | } | ||
1388 | } | ||
1389 | |||
1390 | /* | ||
1391 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1392 | * Emacs will notice this stuff at the end of the file and automatically | ||
1393 | * adjust the settings for this buffer only. This must remain at the end | ||
1394 | * of the file. | ||
1395 | * --------------------------------------------------------------------------- | ||
1396 | * Local variables: | ||
1397 | * c-file-style: "linux" | ||
1398 | * End: | ||
1399 | */ | ||
diff --git a/arch/um/drivers/ubd_user.c b/arch/um/drivers/ubd_user.c new file mode 100644 index 000000000000..b94d2bc4fe06 --- /dev/null +++ b/arch/um/drivers/ubd_user.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com) | ||
4 | * Licensed under the GPL | ||
5 | */ | ||
6 | |||
7 | #include <stddef.h> | ||
8 | #include <unistd.h> | ||
9 | #include <errno.h> | ||
10 | #include <sched.h> | ||
11 | #include <signal.h> | ||
12 | #include <string.h> | ||
13 | #include <netinet/in.h> | ||
14 | #include <sys/time.h> | ||
15 | #include <sys/socket.h> | ||
16 | #include <sys/mman.h> | ||
17 | #include <sys/param.h> | ||
18 | #include "asm/types.h" | ||
19 | #include "user_util.h" | ||
20 | #include "kern_util.h" | ||
21 | #include "user.h" | ||
22 | #include "ubd_user.h" | ||
23 | #include "os.h" | ||
24 | #include "cow.h" | ||
25 | |||
26 | #include <endian.h> | ||
27 | #include <byteswap.h> | ||
28 | |||
29 | void ignore_sigwinch_sig(void) | ||
30 | { | ||
31 | signal(SIGWINCH, SIG_IGN); | ||
32 | } | ||
33 | |||
34 | int start_io_thread(unsigned long sp, int *fd_out) | ||
35 | { | ||
36 | int pid, fds[2], err; | ||
37 | |||
38 | err = os_pipe(fds, 1, 1); | ||
39 | if(err < 0){ | ||
40 | printk("start_io_thread - os_pipe failed, err = %d\n", -err); | ||
41 | goto out; | ||
42 | } | ||
43 | |||
44 | kernel_fd = fds[0]; | ||
45 | *fd_out = fds[1]; | ||
46 | |||
47 | pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, | ||
48 | NULL); | ||
49 | if(pid < 0){ | ||
50 | printk("start_io_thread - clone failed : errno = %d\n", errno); | ||
51 | err = -errno; | ||
52 | goto out_close; | ||
53 | } | ||
54 | |||
55 | return(pid); | ||
56 | |||
57 | out_close: | ||
58 | os_close_file(fds[0]); | ||
59 | os_close_file(fds[1]); | ||
60 | kernel_fd = -1; | ||
61 | *fd_out = -1; | ||
62 | out: | ||
63 | return(err); | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
68 | * Emacs will notice this stuff at the end of the file and automatically | ||
69 | * adjust the settings for this buffer only. This must remain at the end | ||
70 | * of the file. | ||
71 | * --------------------------------------------------------------------------- | ||
72 | * Local variables: | ||
73 | * c-file-style: "linux" | ||
74 | * End: | ||
75 | */ | ||
diff --git a/arch/um/include/aio.h b/arch/um/include/aio.h index 83f16877ab08..423bae9153f8 100644 --- a/arch/um/include/aio.h +++ b/arch/um/include/aio.h | |||
@@ -14,27 +14,15 @@ struct aio_thread_reply { | |||
14 | }; | 14 | }; |
15 | 15 | ||
16 | struct aio_context { | 16 | struct aio_context { |
17 | enum aio_type type; | ||
18 | int fd; | ||
19 | void *data; | ||
20 | int len; | ||
21 | unsigned long long offset; | ||
22 | int reply_fd; | 17 | int reply_fd; |
23 | struct aio_context *next; | 18 | struct aio_context *next; |
24 | }; | 19 | }; |
25 | 20 | ||
26 | #define INIT_AIO(aio_type, aio_fd, aio_data, aio_len, aio_offset, \ | ||
27 | aio_reply_fd) \ | ||
28 | { .type = aio_type, \ | ||
29 | .fd = aio_fd, \ | ||
30 | .data = aio_data, \ | ||
31 | .len = aio_len, \ | ||
32 | .offset = aio_offset, \ | ||
33 | .reply_fd = aio_reply_fd } | ||
34 | |||
35 | #define INIT_AIO_CONTEXT { .reply_fd = -1, \ | 21 | #define INIT_AIO_CONTEXT { .reply_fd = -1, \ |
36 | .next = NULL } | 22 | .next = NULL } |
37 | 23 | ||
38 | extern int submit_aio(struct aio_context *aio); | 24 | extern int submit_aio(enum aio_type type, int fd, char *buf, int len, |
25 | unsigned long long offset, int reply_fd, | ||
26 | struct aio_context *aio); | ||
39 | 27 | ||
40 | #endif | 28 | #endif |
diff --git a/arch/um/include/os.h b/arch/um/include/os.h index 6f766e1faecc..2e58e304b8be 100644 --- a/arch/um/include/os.h +++ b/arch/um/include/os.h | |||
@@ -6,6 +6,7 @@ | |||
6 | #ifndef __OS_H__ | 6 | #ifndef __OS_H__ |
7 | #define __OS_H__ | 7 | #define __OS_H__ |
8 | 8 | ||
9 | #include "uml-config.h" | ||
9 | #include "asm/types.h" | 10 | #include "asm/types.h" |
10 | #include "../os/include/file.h" | 11 | #include "../os/include/file.h" |
11 | 12 | ||
@@ -159,7 +160,11 @@ extern int can_do_skas(void); | |||
159 | 160 | ||
160 | /* Make sure they are clear when running in TT mode. Required by | 161 | /* Make sure they are clear when running in TT mode. Required by |
161 | * SEGV_MAYBE_FIXABLE */ | 162 | * SEGV_MAYBE_FIXABLE */ |
163 | #ifdef UML_CONFIG_MODE_SKAS | ||
162 | #define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0) | 164 | #define clear_can_do_skas() do { ptrace_faultinfo = proc_mm = 0; } while (0) |
165 | #else | ||
166 | #define clear_can_do_skas() do {} while (0) | ||
167 | #endif | ||
163 | 168 | ||
164 | /* mem.c */ | 169 | /* mem.c */ |
165 | extern int create_mem_file(unsigned long len); | 170 | extern int create_mem_file(unsigned long len); |
diff --git a/arch/um/os-Linux/aio.c b/arch/um/os-Linux/aio.c index f6e64026f995..41cfb0944201 100644 --- a/arch/um/os-Linux/aio.c +++ b/arch/um/os-Linux/aio.c | |||
@@ -6,7 +6,6 @@ | |||
6 | #include <stdlib.h> | 6 | #include <stdlib.h> |
7 | #include <unistd.h> | 7 | #include <unistd.h> |
8 | #include <signal.h> | 8 | #include <signal.h> |
9 | #include <string.h> | ||
10 | #include <errno.h> | 9 | #include <errno.h> |
11 | #include <sched.h> | 10 | #include <sched.h> |
12 | #include <sys/syscall.h> | 11 | #include <sys/syscall.h> |
@@ -17,31 +16,18 @@ | |||
17 | #include "user.h" | 16 | #include "user.h" |
18 | #include "mode.h" | 17 | #include "mode.h" |
19 | 18 | ||
19 | struct aio_thread_req { | ||
20 | enum aio_type type; | ||
21 | int io_fd; | ||
22 | unsigned long long offset; | ||
23 | char *buf; | ||
24 | int len; | ||
25 | struct aio_context *aio; | ||
26 | }; | ||
27 | |||
20 | static int aio_req_fd_r = -1; | 28 | static int aio_req_fd_r = -1; |
21 | static int aio_req_fd_w = -1; | 29 | static int aio_req_fd_w = -1; |
22 | 30 | ||
23 | static int update_aio(struct aio_context *aio, int res) | ||
24 | { | ||
25 | if(res < 0) | ||
26 | aio->len = res; | ||
27 | else if((res == 0) && (aio->type == AIO_READ)){ | ||
28 | /* This is the EOF case - we have hit the end of the file | ||
29 | * and it ends in a partial block, so we fill the end of | ||
30 | * the block with zeros and claim success. | ||
31 | */ | ||
32 | memset(aio->data, 0, aio->len); | ||
33 | aio->len = 0; | ||
34 | } | ||
35 | else if(res > 0){ | ||
36 | aio->len -= res; | ||
37 | aio->data += res; | ||
38 | aio->offset += res; | ||
39 | return aio->len; | ||
40 | } | ||
41 | |||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | #if defined(HAVE_AIO_ABI) | 31 | #if defined(HAVE_AIO_ABI) |
46 | #include <linux/aio_abi.h> | 32 | #include <linux/aio_abi.h> |
47 | 33 | ||
@@ -80,7 +66,8 @@ static long io_getevents(aio_context_t ctx_id, long min_nr, long nr, | |||
80 | * that it now backs the mmapped area. | 66 | * that it now backs the mmapped area. |
81 | */ | 67 | */ |
82 | 68 | ||
83 | static int do_aio(aio_context_t ctx, struct aio_context *aio) | 69 | static int do_aio(aio_context_t ctx, enum aio_type type, int fd, char *buf, |
70 | int len, unsigned long long offset, struct aio_context *aio) | ||
84 | { | 71 | { |
85 | struct iocb iocb, *iocbp = &iocb; | 72 | struct iocb iocb, *iocbp = &iocb; |
86 | char c; | 73 | char c; |
@@ -88,39 +75,40 @@ static int do_aio(aio_context_t ctx, struct aio_context *aio) | |||
88 | 75 | ||
89 | iocb = ((struct iocb) { .aio_data = (unsigned long) aio, | 76 | iocb = ((struct iocb) { .aio_data = (unsigned long) aio, |
90 | .aio_reqprio = 0, | 77 | .aio_reqprio = 0, |
91 | .aio_fildes = aio->fd, | 78 | .aio_fildes = fd, |
92 | .aio_buf = (unsigned long) aio->data, | 79 | .aio_buf = (unsigned long) buf, |
93 | .aio_nbytes = aio->len, | 80 | .aio_nbytes = len, |
94 | .aio_offset = aio->offset, | 81 | .aio_offset = offset, |
95 | .aio_reserved1 = 0, | 82 | .aio_reserved1 = 0, |
96 | .aio_reserved2 = 0, | 83 | .aio_reserved2 = 0, |
97 | .aio_reserved3 = 0 }); | 84 | .aio_reserved3 = 0 }); |
98 | 85 | ||
99 | switch(aio->type){ | 86 | switch(type){ |
100 | case AIO_READ: | 87 | case AIO_READ: |
101 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; | 88 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; |
89 | err = io_submit(ctx, 1, &iocbp); | ||
102 | break; | 90 | break; |
103 | case AIO_WRITE: | 91 | case AIO_WRITE: |
104 | iocb.aio_lio_opcode = IOCB_CMD_PWRITE; | 92 | iocb.aio_lio_opcode = IOCB_CMD_PWRITE; |
93 | err = io_submit(ctx, 1, &iocbp); | ||
105 | break; | 94 | break; |
106 | case AIO_MMAP: | 95 | case AIO_MMAP: |
107 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; | 96 | iocb.aio_lio_opcode = IOCB_CMD_PREAD; |
108 | iocb.aio_buf = (unsigned long) &c; | 97 | iocb.aio_buf = (unsigned long) &c; |
109 | iocb.aio_nbytes = sizeof(c); | 98 | iocb.aio_nbytes = sizeof(c); |
99 | err = io_submit(ctx, 1, &iocbp); | ||
110 | break; | 100 | break; |
111 | default: | 101 | default: |
112 | printk("Bogus op in do_aio - %d\n", aio->type); | 102 | printk("Bogus op in do_aio - %d\n", type); |
113 | err = -EINVAL; | 103 | err = -EINVAL; |
114 | goto out; | 104 | break; |
115 | } | 105 | } |
116 | 106 | ||
117 | err = io_submit(ctx, 1, &iocbp); | ||
118 | if(err > 0) | 107 | if(err > 0) |
119 | err = 0; | 108 | err = 0; |
120 | else | 109 | else |
121 | err = -errno; | 110 | err = -errno; |
122 | 111 | ||
123 | out: | ||
124 | return err; | 112 | return err; |
125 | } | 113 | } |
126 | 114 | ||
@@ -129,9 +117,8 @@ static aio_context_t ctx = 0; | |||
129 | static int aio_thread(void *arg) | 117 | static int aio_thread(void *arg) |
130 | { | 118 | { |
131 | struct aio_thread_reply reply; | 119 | struct aio_thread_reply reply; |
132 | struct aio_context *aio; | ||
133 | struct io_event event; | 120 | struct io_event event; |
134 | int err, n; | 121 | int err, n, reply_fd; |
135 | 122 | ||
136 | signal(SIGWINCH, SIG_IGN); | 123 | signal(SIGWINCH, SIG_IGN); |
137 | 124 | ||
@@ -144,22 +131,14 @@ static int aio_thread(void *arg) | |||
144 | "errno = %d\n", errno); | 131 | "errno = %d\n", errno); |
145 | } | 132 | } |
146 | else { | 133 | else { |
147 | /* This is safe as we've just a pointer here. */ | ||
148 | aio = (struct aio_context *) (long) event.data; | ||
149 | if(update_aio(aio, event.res)){ | ||
150 | do_aio(ctx, aio); | ||
151 | continue; | ||
152 | } | ||
153 | |||
154 | reply = ((struct aio_thread_reply) | 134 | reply = ((struct aio_thread_reply) |
155 | { .data = aio, | 135 | { .data = (void *) (long) event.data, |
156 | .err = aio->len }); | 136 | .err = event.res }); |
157 | err = os_write_file(aio->reply_fd, &reply, | 137 | reply_fd = ((struct aio_context *) reply.data)->reply_fd; |
158 | sizeof(reply)); | 138 | err = os_write_file(reply_fd, &reply, sizeof(reply)); |
159 | if(err != sizeof(reply)) | 139 | if(err != sizeof(reply)) |
160 | printk("aio_thread - write failed, " | 140 | printk("aio_thread - write failed, fd = %d, " |
161 | "fd = %d, err = %d\n", aio->reply_fd, | 141 | "err = %d\n", aio_req_fd_r, -err); |
162 | -err); | ||
163 | } | 142 | } |
164 | } | 143 | } |
165 | return 0; | 144 | return 0; |
@@ -167,35 +146,35 @@ static int aio_thread(void *arg) | |||
167 | 146 | ||
168 | #endif | 147 | #endif |
169 | 148 | ||
170 | static int do_not_aio(struct aio_context *aio) | 149 | static int do_not_aio(struct aio_thread_req *req) |
171 | { | 150 | { |
172 | char c; | 151 | char c; |
173 | int err; | 152 | int err; |
174 | 153 | ||
175 | switch(aio->type){ | 154 | switch(req->type){ |
176 | case AIO_READ: | 155 | case AIO_READ: |
177 | err = os_seek_file(aio->fd, aio->offset); | 156 | err = os_seek_file(req->io_fd, req->offset); |
178 | if(err) | 157 | if(err) |
179 | goto out; | 158 | goto out; |
180 | 159 | ||
181 | err = os_read_file(aio->fd, aio->data, aio->len); | 160 | err = os_read_file(req->io_fd, req->buf, req->len); |
182 | break; | 161 | break; |
183 | case AIO_WRITE: | 162 | case AIO_WRITE: |
184 | err = os_seek_file(aio->fd, aio->offset); | 163 | err = os_seek_file(req->io_fd, req->offset); |
185 | if(err) | 164 | if(err) |
186 | goto out; | 165 | goto out; |
187 | 166 | ||
188 | err = os_write_file(aio->fd, aio->data, aio->len); | 167 | err = os_write_file(req->io_fd, req->buf, req->len); |
189 | break; | 168 | break; |
190 | case AIO_MMAP: | 169 | case AIO_MMAP: |
191 | err = os_seek_file(aio->fd, aio->offset); | 170 | err = os_seek_file(req->io_fd, req->offset); |
192 | if(err) | 171 | if(err) |
193 | goto out; | 172 | goto out; |
194 | 173 | ||
195 | err = os_read_file(aio->fd, &c, sizeof(c)); | 174 | err = os_read_file(req->io_fd, &c, sizeof(c)); |
196 | break; | 175 | break; |
197 | default: | 176 | default: |
198 | printk("do_not_aio - bad request type : %d\n", aio->type); | 177 | printk("do_not_aio - bad request type : %d\n", req->type); |
199 | err = -EINVAL; | 178 | err = -EINVAL; |
200 | break; | 179 | break; |
201 | } | 180 | } |
@@ -206,14 +185,14 @@ static int do_not_aio(struct aio_context *aio) | |||
206 | 185 | ||
207 | static int not_aio_thread(void *arg) | 186 | static int not_aio_thread(void *arg) |
208 | { | 187 | { |
209 | struct aio_context *aio; | 188 | struct aio_thread_req req; |
210 | struct aio_thread_reply reply; | 189 | struct aio_thread_reply reply; |
211 | int err; | 190 | int err; |
212 | 191 | ||
213 | signal(SIGWINCH, SIG_IGN); | 192 | signal(SIGWINCH, SIG_IGN); |
214 | while(1){ | 193 | while(1){ |
215 | err = os_read_file(aio_req_fd_r, &aio, sizeof(aio)); | 194 | err = os_read_file(aio_req_fd_r, &req, sizeof(req)); |
216 | if(err != sizeof(aio)){ | 195 | if(err != sizeof(req)){ |
217 | if(err < 0) | 196 | if(err < 0) |
218 | printk("not_aio_thread - read failed, " | 197 | printk("not_aio_thread - read failed, " |
219 | "fd = %d, err = %d\n", aio_req_fd_r, | 198 | "fd = %d, err = %d\n", aio_req_fd_r, |
@@ -224,34 +203,17 @@ static int not_aio_thread(void *arg) | |||
224 | } | 203 | } |
225 | continue; | 204 | continue; |
226 | } | 205 | } |
227 | again: | 206 | err = do_not_aio(&req); |
228 | err = do_not_aio(aio); | 207 | reply = ((struct aio_thread_reply) { .data = req.aio, |
229 | 208 | .err = err }); | |
230 | if(update_aio(aio, err)) | 209 | err = os_write_file(req.aio->reply_fd, &reply, sizeof(reply)); |
231 | goto again; | ||
232 | |||
233 | reply = ((struct aio_thread_reply) { .data = aio, | ||
234 | .err = aio->len }); | ||
235 | err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); | ||
236 | if(err != sizeof(reply)) | 210 | if(err != sizeof(reply)) |
237 | printk("not_aio_thread - write failed, fd = %d, " | 211 | printk("not_aio_thread - write failed, fd = %d, " |
238 | "err = %d\n", aio_req_fd_r, -err); | 212 | "err = %d\n", aio_req_fd_r, -err); |
239 | } | 213 | } |
240 | } | 214 | } |
241 | 215 | ||
242 | static int submit_aio_24(struct aio_context *aio) | ||
243 | { | ||
244 | int err; | ||
245 | |||
246 | err = os_write_file(aio_req_fd_w, &aio, sizeof(aio)); | ||
247 | if(err == sizeof(aio)) | ||
248 | err = 0; | ||
249 | |||
250 | return err; | ||
251 | } | ||
252 | |||
253 | static int aio_pid = -1; | 216 | static int aio_pid = -1; |
254 | static int (*submit_proc)(struct aio_context *aio); | ||
255 | 217 | ||
256 | static int init_aio_24(void) | 218 | static int init_aio_24(void) |
257 | { | 219 | { |
@@ -283,33 +245,11 @@ static int init_aio_24(void) | |||
283 | #endif | 245 | #endif |
284 | printk("2.6 host AIO support not used - falling back to I/O " | 246 | printk("2.6 host AIO support not used - falling back to I/O " |
285 | "thread\n"); | 247 | "thread\n"); |
286 | |||
287 | submit_proc = submit_aio_24; | ||
288 | |||
289 | return 0; | 248 | return 0; |
290 | } | 249 | } |
291 | 250 | ||
292 | #ifdef HAVE_AIO_ABI | 251 | #ifdef HAVE_AIO_ABI |
293 | #define DEFAULT_24_AIO 0 | 252 | #define DEFAULT_24_AIO 0 |
294 | static int submit_aio_26(struct aio_context *aio) | ||
295 | { | ||
296 | struct aio_thread_reply reply; | ||
297 | int err; | ||
298 | |||
299 | err = do_aio(ctx, aio); | ||
300 | if(err){ | ||
301 | reply = ((struct aio_thread_reply) { .data = aio, | ||
302 | .err = err }); | ||
303 | err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); | ||
304 | if(err != sizeof(reply)) | ||
305 | printk("submit_aio_26 - write failed, " | ||
306 | "fd = %d, err = %d\n", aio->reply_fd, -err); | ||
307 | else err = 0; | ||
308 | } | ||
309 | |||
310 | return err; | ||
311 | } | ||
312 | |||
313 | static int init_aio_26(void) | 253 | static int init_aio_26(void) |
314 | { | 254 | { |
315 | unsigned long stack; | 255 | unsigned long stack; |
@@ -330,22 +270,39 @@ static int init_aio_26(void) | |||
330 | aio_pid = err; | 270 | aio_pid = err; |
331 | 271 | ||
332 | printk("Using 2.6 host AIO\n"); | 272 | printk("Using 2.6 host AIO\n"); |
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, | ||
277 | unsigned long long offset, struct aio_context *aio) | ||
278 | { | ||
279 | struct aio_thread_reply reply; | ||
280 | int err; | ||
333 | 281 | ||
334 | submit_proc = submit_aio_26; | 282 | err = do_aio(ctx, type, io_fd, buf, len, offset, aio); |
283 | if(err){ | ||
284 | reply = ((struct aio_thread_reply) { .data = aio, | ||
285 | .err = err }); | ||
286 | err = os_write_file(aio->reply_fd, &reply, sizeof(reply)); | ||
287 | if(err != sizeof(reply)) | ||
288 | printk("submit_aio_26 - write failed, " | ||
289 | "fd = %d, err = %d\n", aio->reply_fd, -err); | ||
290 | else err = 0; | ||
291 | } | ||
335 | 292 | ||
336 | return 0; | 293 | return err; |
337 | } | 294 | } |
338 | 295 | ||
339 | #else | 296 | #else |
340 | #define DEFAULT_24_AIO 1 | 297 | #define DEFAULT_24_AIO 1 |
341 | static int submit_aio_26(struct aio_context *aio) | 298 | static int init_aio_26(void) |
342 | { | 299 | { |
343 | return -ENOSYS; | 300 | return -ENOSYS; |
344 | } | 301 | } |
345 | 302 | ||
346 | static int init_aio_26(void) | 303 | static int submit_aio_26(enum aio_type type, int io_fd, char *buf, int len, |
304 | unsigned long long offset, struct aio_context *aio) | ||
347 | { | 305 | { |
348 | submit_proc = submit_aio_26; | ||
349 | return -ENOSYS; | 306 | return -ENOSYS; |
350 | } | 307 | } |
351 | #endif | 308 | #endif |
@@ -412,7 +369,33 @@ static void exit_aio(void) | |||
412 | 369 | ||
413 | __uml_exitcall(exit_aio); | 370 | __uml_exitcall(exit_aio); |
414 | 371 | ||
415 | int submit_aio(struct aio_context *aio) | 372 | static int submit_aio_24(enum aio_type type, int io_fd, char *buf, int len, |
373 | unsigned long long offset, struct aio_context *aio) | ||
416 | { | 374 | { |
417 | return (*submit_proc)(aio); | 375 | struct aio_thread_req req = { .type = type, |
376 | .io_fd = io_fd, | ||
377 | .offset = offset, | ||
378 | .buf = buf, | ||
379 | .len = len, | ||
380 | .aio = aio, | ||
381 | }; | ||
382 | int err; | ||
383 | |||
384 | err = os_write_file(aio_req_fd_w, &req, sizeof(req)); | ||
385 | if(err == sizeof(req)) | ||
386 | err = 0; | ||
387 | |||
388 | return err; | ||
389 | } | ||
390 | |||
391 | int submit_aio(enum aio_type type, int io_fd, char *buf, int len, | ||
392 | unsigned long long offset, int reply_fd, | ||
393 | struct aio_context *aio) | ||
394 | { | ||
395 | aio->reply_fd = reply_fd; | ||
396 | if(aio_24) | ||
397 | return submit_aio_24(type, io_fd, buf, len, offset, aio); | ||
398 | else { | ||
399 | return submit_aio_26(type, io_fd, buf, len, offset, aio); | ||
400 | } | ||
418 | } | 401 | } |