diff options
108 files changed, 6300 insertions, 1359 deletions
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt index 3af4d29a8938..89aa89d526ac 100644 --- a/Documentation/arm/Samsung-S3C24XX/Overview.txt +++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt | |||
| @@ -81,7 +81,8 @@ Adding New Machines | |||
| 81 | 81 | ||
| 82 | Any large scale modifications, or new drivers should be discussed | 82 | Any large scale modifications, or new drivers should be discussed |
| 83 | on the ARM kernel mailing list (linux-arm-kernel) before being | 83 | on the ARM kernel mailing list (linux-arm-kernel) before being |
| 84 | attempted. | 84 | attempted. See http://www.arm.linux.org.uk/mailinglists/ for the |
| 85 | mailing list information. | ||
| 85 | 86 | ||
| 86 | 87 | ||
| 87 | NAND | 88 | NAND |
| @@ -120,6 +121,43 @@ Clock Management | |||
| 120 | various clock units | 121 | various clock units |
| 121 | 122 | ||
| 122 | 123 | ||
| 124 | Platform Data | ||
| 125 | ------------- | ||
| 126 | |||
| 127 | Whenever a device has platform specific data that is specified | ||
| 128 | on a per-machine basis, care should be taken to ensure the | ||
| 129 | following: | ||
| 130 | |||
| 131 | 1) that default data is not left in the device to confuse the | ||
| 132 | driver if a machine does not set it at startup | ||
| 133 | |||
| 134 | 2) the data should (if possible) be marked as __initdata, | ||
| 135 | to ensure that the data is thrown away if the machine is | ||
| 136 | not the one currently in use. | ||
| 137 | |||
| 138 | The best way of doing this is to make a function that | ||
| 139 | kmalloc()s an area of memory, and copies the __initdata | ||
| 140 | and then sets the relevant device's platform data. Making | ||
| 141 | the function `__init` takes care of ensuring it is discarded | ||
| 142 | with the rest of the initialisation code | ||
| 143 | |||
| 144 | static __init void s3c24xx_xxx_set_platdata(struct xxx_data *pd) | ||
| 145 | { | ||
| 146 | struct s3c2410_xxx_mach_info *npd; | ||
| 147 | |||
| 148 | npd = kmalloc(sizeof(struct s3c2410_xxx_mach_info), GFP_KERNEL); | ||
| 149 | if (npd) { | ||
| 150 | memcpy(npd, pd, sizeof(struct s3c2410_xxx_mach_info)); | ||
| 151 | s3c_device_xxx.dev.platform_data = npd; | ||
| 152 | } else { | ||
| 153 | printk(KERN_ERR "no memory for xxx platform data\n"); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | Note, since the code is marked as __init, it should not be | ||
| 158 | exported outside arch/arm/mach-s3c2410/, or exported to | ||
| 159 | modules via EXPORT_SYMBOL() and related functions. | ||
| 160 | |||
| 123 | Port Contributors | 161 | Port Contributors |
| 124 | ----------------- | 162 | ----------------- |
| 125 | 163 | ||
| @@ -149,6 +187,7 @@ Document Changes | |||
| 149 | 06 Mar 2005 - BJD - Added Christer Weinigel | 187 | 06 Mar 2005 - BJD - Added Christer Weinigel |
| 150 | 08 Mar 2005 - BJD - Added LCVR to list of people, updated introduction | 188 | 08 Mar 2005 - BJD - Added LCVR to list of people, updated introduction |
| 151 | 08 Mar 2005 - BJD - Added section on adding machines | 189 | 08 Mar 2005 - BJD - Added section on adding machines |
| 190 | 09 Sep 2005 - BJD - Added section on platform data | ||
| 152 | 191 | ||
| 153 | Document Author | 192 | Document Author |
| 154 | --------------- | 193 | --------------- |
diff --git a/Documentation/serial/driver b/Documentation/serial/driver index 87856d3cfb67..42ef9970bc86 100644 --- a/Documentation/serial/driver +++ b/Documentation/serial/driver | |||
| @@ -116,12 +116,15 @@ hardware. | |||
| 116 | line becoming inactive or the tty layer indicating we want | 116 | line becoming inactive or the tty layer indicating we want |
| 117 | to stop transmission due to an XOFF character. | 117 | to stop transmission due to an XOFF character. |
| 118 | 118 | ||
| 119 | The driver should stop transmitting characters as soon as | ||
| 120 | possible. | ||
| 121 | |||
| 119 | Locking: port->lock taken. | 122 | Locking: port->lock taken. |
| 120 | Interrupts: locally disabled. | 123 | Interrupts: locally disabled. |
| 121 | This call must not sleep | 124 | This call must not sleep |
| 122 | 125 | ||
| 123 | start_tx(port) | 126 | start_tx(port) |
| 124 | start transmitting characters. | 127 | Start transmitting characters. |
| 125 | 128 | ||
| 126 | Locking: port->lock taken. | 129 | Locking: port->lock taken. |
| 127 | Interrupts: locally disabled. | 130 | Interrupts: locally disabled. |
| @@ -281,26 +284,31 @@ hardware. | |||
| 281 | Other functions | 284 | Other functions |
| 282 | --------------- | 285 | --------------- |
| 283 | 286 | ||
| 284 | uart_update_timeout(port,cflag,quot) | 287 | uart_update_timeout(port,cflag,baud) |
| 285 | Update the FIFO drain timeout, port->timeout, according to the | 288 | Update the FIFO drain timeout, port->timeout, according to the |
| 286 | number of bits, parity, stop bits and quotient. | 289 | number of bits, parity, stop bits and baud rate. |
| 287 | 290 | ||
| 288 | Locking: caller is expected to take port->lock | 291 | Locking: caller is expected to take port->lock |
| 289 | Interrupts: n/a | 292 | Interrupts: n/a |
| 290 | 293 | ||
| 291 | uart_get_baud_rate(port,termios) | 294 | uart_get_baud_rate(port,termios,old,min,max) |
| 292 | Return the numeric baud rate for the specified termios, taking | 295 | Return the numeric baud rate for the specified termios, taking |
| 293 | account of the special 38400 baud "kludge". The B0 baud rate | 296 | account of the special 38400 baud "kludge". The B0 baud rate |
| 294 | is mapped to 9600 baud. | 297 | is mapped to 9600 baud. |
| 295 | 298 | ||
| 299 | If the baud rate is not within min..max, then if old is non-NULL, | ||
| 300 | the original baud rate will be tried. If that exceeds the | ||
| 301 | min..max constraint, 9600 baud will be returned. termios will | ||
| 302 | be updated to the baud rate in use. | ||
| 303 | |||
| 304 | Note: min..max must always allow 9600 baud to be selected. | ||
| 305 | |||
| 296 | Locking: caller dependent. | 306 | Locking: caller dependent. |
| 297 | Interrupts: n/a | 307 | Interrupts: n/a |
| 298 | 308 | ||
| 299 | uart_get_divisor(port,termios,oldtermios) | 309 | uart_get_divisor(port,baud) |
| 300 | Return the divsor (baud_base / baud) for the selected baud rate | 310 | Return the divsor (baud_base / baud) for the specified baud |
| 301 | specified by termios. If the baud rate is out of range, try | 311 | rate, appropriately rounded. |
| 302 | the original baud rate specified by oldtermios (if non-NULL). | ||
| 303 | If that fails, try 9600 baud. | ||
| 304 | 312 | ||
| 305 | If 38400 baud and custom divisor is selected, return the | 313 | If 38400 baud and custom divisor is selected, return the |
| 306 | custom divisor instead. | 314 | custom divisor instead. |
| @@ -308,6 +316,46 @@ uart_get_divisor(port,termios,oldtermios) | |||
| 308 | Locking: caller dependent. | 316 | Locking: caller dependent. |
| 309 | Interrupts: n/a | 317 | Interrupts: n/a |
| 310 | 318 | ||
| 319 | uart_match_port(port1,port2) | ||
| 320 | This utility function can be used to determine whether two | ||
| 321 | uart_port structures describe the same port. | ||
| 322 | |||
| 323 | Locking: n/a | ||
| 324 | Interrupts: n/a | ||
| 325 | |||
| 326 | uart_write_wakeup(port) | ||
| 327 | A driver is expected to call this function when the number of | ||
| 328 | characters in the transmit buffer have dropped below a threshold. | ||
| 329 | |||
| 330 | Locking: port->lock should be held. | ||
| 331 | Interrupts: n/a | ||
| 332 | |||
| 333 | uart_register_driver(drv) | ||
| 334 | Register a uart driver with the core driver. We in turn register | ||
| 335 | with the tty layer, and initialise the core driver per-port state. | ||
| 336 | |||
| 337 | drv->port should be NULL, and the per-port structures should be | ||
| 338 | registered using uart_add_one_port after this call has succeeded. | ||
| 339 | |||
| 340 | Locking: none | ||
| 341 | Interrupts: enabled | ||
| 342 | |||
| 343 | uart_unregister_driver() | ||
| 344 | Remove all references to a driver from the core driver. The low | ||
| 345 | level driver must have removed all its ports via the | ||
| 346 | uart_remove_one_port() if it registered them with uart_add_one_port(). | ||
| 347 | |||
| 348 | Locking: none | ||
| 349 | Interrupts: enabled | ||
| 350 | |||
| 351 | uart_suspend_port() | ||
| 352 | |||
| 353 | uart_resume_port() | ||
| 354 | |||
| 355 | uart_add_one_port() | ||
| 356 | |||
| 357 | uart_remove_one_port() | ||
| 358 | |||
| 311 | Other notes | 359 | Other notes |
| 312 | ----------- | 360 | ----------- |
| 313 | 361 | ||
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 682367bd0f65..dc6d8342e5e6 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -194,6 +194,13 @@ config ARCH_VERSATILE | |||
| 194 | help | 194 | help |
| 195 | This enables support for ARM Ltd Versatile board. | 195 | This enables support for ARM Ltd Versatile board. |
| 196 | 196 | ||
| 197 | config ARCH_REALVIEW | ||
| 198 | bool "RealView" | ||
| 199 | select ARM_AMBA | ||
| 200 | select ICST307 | ||
| 201 | help | ||
| 202 | This enables support for ARM Ltd RealView boards. | ||
| 203 | |||
| 197 | config ARCH_IMX | 204 | config ARCH_IMX |
| 198 | bool "IMX" | 205 | bool "IMX" |
| 199 | 206 | ||
| @@ -244,6 +251,8 @@ source "arch/arm/mach-versatile/Kconfig" | |||
| 244 | 251 | ||
| 245 | source "arch/arm/mach-aaec2000/Kconfig" | 252 | source "arch/arm/mach-aaec2000/Kconfig" |
| 246 | 253 | ||
| 254 | source "arch/arm/mach-realview/Kconfig" | ||
| 255 | |||
| 247 | # Definitions to make life easier | 256 | # Definitions to make life easier |
| 248 | config ARCH_ACORN | 257 | config ARCH_ACORN |
| 249 | bool | 258 | bool |
diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 64cf480b0b02..d80749ae2a7e 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile | |||
| @@ -99,6 +99,7 @@ textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000 | |||
| 99 | machine-$(CONFIG_ARCH_IMX) := imx | 99 | machine-$(CONFIG_ARCH_IMX) := imx |
| 100 | machine-$(CONFIG_ARCH_H720X) := h720x | 100 | machine-$(CONFIG_ARCH_H720X) := h720x |
| 101 | machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 | 101 | machine-$(CONFIG_ARCH_AAEC2000) := aaec2000 |
| 102 | machine-$(CONFIG_ARCH_REALVIEW) := realview | ||
| 102 | 103 | ||
| 103 | ifeq ($(CONFIG_ARCH_EBSA110),y) | 104 | ifeq ($(CONFIG_ARCH_EBSA110),y) |
| 104 | # This is what happens if you forget the IOCS16 line. | 105 | # This is what happens if you forget the IOCS16 line. |
diff --git a/arch/arm/configs/ixp4xx_defconfig b/arch/arm/configs/ixp4xx_defconfig index c279e41ed10e..f74c926beb42 100644 --- a/arch/arm/configs/ixp4xx_defconfig +++ b/arch/arm/configs/ixp4xx_defconfig | |||
| @@ -104,7 +104,7 @@ CONFIG_ARCH_IXCDP1100=y | |||
| 104 | CONFIG_ARCH_PRPMC1100=y | 104 | CONFIG_ARCH_PRPMC1100=y |
| 105 | CONFIG_ARCH_IXDP4XX=y | 105 | CONFIG_ARCH_IXDP4XX=y |
| 106 | CONFIG_CPU_IXP46X=y | 106 | CONFIG_CPU_IXP46X=y |
| 107 | CONFIG_MACH_GTWX5715=y | 107 | # CONFIG_MACH_GTWX5715 is not set |
| 108 | 108 | ||
| 109 | # | 109 | # |
| 110 | # IXP4xx Options | 110 | # IXP4xx Options |
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 71e5b99e519e..391f3ab3ff32 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile | |||
| @@ -7,13 +7,27 @@ | |||
| 7 | lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ | 7 | lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ |
| 8 | csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ | 8 | csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ |
| 9 | copy_page.o delay.o findbit.o memchr.o memcpy.o \ | 9 | copy_page.o delay.o findbit.o memchr.o memcpy.o \ |
| 10 | memset.o memzero.o setbit.o strncpy_from_user.o \ | 10 | memmove.o memset.o memzero.o setbit.o \ |
| 11 | strnlen_user.o strchr.o strrchr.o testchangebit.o \ | 11 | strncpy_from_user.o strnlen_user.o \ |
| 12 | testclearbit.o testsetbit.o uaccess.o getuser.o \ | 12 | strchr.o strrchr.o \ |
| 13 | putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ | 13 | testchangebit.o testclearbit.o testsetbit.o \ |
| 14 | getuser.o putuser.o clear_user.o \ | ||
| 15 | ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ | ||
| 14 | ucmpdi2.o lib1funcs.o div64.o sha1.o \ | 16 | ucmpdi2.o lib1funcs.o div64.o sha1.o \ |
| 15 | io-readsb.o io-writesb.o io-readsl.o io-writesl.o | 17 | io-readsb.o io-writesb.o io-readsl.o io-writesl.o |
| 16 | 18 | ||
| 19 | # the code in uaccess.S is not preemption safe and | ||
| 20 | # probably faster on ARMv3 only | ||
| 21 | ifeq ($CONFIG_PREEMPT,y) | ||
| 22 | lib-y += copy_from_user.o copy_to_user.o | ||
| 23 | else | ||
| 24 | ifneq ($(CONFIG_CPU_32v3),y) | ||
| 25 | lib-y += copy_from_user.o copy_to_user.o | ||
| 26 | else | ||
| 27 | lib-y += uaccess.o | ||
| 28 | endif | ||
| 29 | endif | ||
| 30 | |||
| 17 | ifeq ($(CONFIG_CPU_32v3),y) | 31 | ifeq ($(CONFIG_CPU_32v3),y) |
| 18 | lib-y += io-readsw-armv3.o io-writesw-armv3.o | 32 | lib-y += io-readsw-armv3.o io-writesw-armv3.o |
| 19 | else | 33 | else |
diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S new file mode 100644 index 000000000000..7ff9f831b3f9 --- /dev/null +++ b/arch/arm/lib/clear_user.S | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/clear_user.S | ||
| 3 | * | ||
| 4 | * Copyright (C) 1995, 1996,1997,1998 Russell King | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | #include <linux/linkage.h> | ||
| 11 | #include <asm/assembler.h> | ||
| 12 | |||
| 13 | .text | ||
| 14 | |||
| 15 | /* Prototype: int __arch_clear_user(void *addr, size_t sz) | ||
| 16 | * Purpose : clear some user memory | ||
| 17 | * Params : addr - user memory address to clear | ||
| 18 | * : sz - number of bytes to clear | ||
| 19 | * Returns : number of bytes NOT cleared | ||
| 20 | */ | ||
| 21 | ENTRY(__arch_clear_user) | ||
| 22 | stmfd sp!, {r1, lr} | ||
| 23 | mov r2, #0 | ||
| 24 | cmp r1, #4 | ||
| 25 | blt 2f | ||
| 26 | ands ip, r0, #3 | ||
| 27 | beq 1f | ||
| 28 | cmp ip, #2 | ||
| 29 | USER( strbt r2, [r0], #1) | ||
| 30 | USER( strlebt r2, [r0], #1) | ||
| 31 | USER( strltbt r2, [r0], #1) | ||
| 32 | rsb ip, ip, #4 | ||
| 33 | sub r1, r1, ip @ 7 6 5 4 3 2 1 | ||
| 34 | 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 | ||
| 35 | USER( strplt r2, [r0], #4) | ||
| 36 | USER( strplt r2, [r0], #4) | ||
| 37 | bpl 1b | ||
| 38 | adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 | ||
| 39 | USER( strplt r2, [r0], #4) | ||
| 40 | 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x | ||
| 41 | USER( strnebt r2, [r0], #1) | ||
| 42 | USER( strnebt r2, [r0], #1) | ||
| 43 | tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 | ||
| 44 | USER( strnebt r2, [r0], #1) | ||
| 45 | mov r0, #0 | ||
| 46 | LOADREGS(fd,sp!, {r1, pc}) | ||
| 47 | |||
| 48 | .section .fixup,"ax" | ||
| 49 | .align 0 | ||
| 50 | 9001: LOADREGS(fd,sp!, {r0, pc}) | ||
| 51 | .previous | ||
| 52 | |||
diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S new file mode 100644 index 000000000000..7497393a0e81 --- /dev/null +++ b/arch/arm/lib/copy_from_user.S | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/copy_from_user.S | ||
| 3 | * | ||
| 4 | * Author: Nicolas Pitre | ||
| 5 | * Created: Sep 29, 2005 | ||
| 6 | * Copyright: MontaVista Software, Inc. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/linkage.h> | ||
| 14 | #include <asm/assembler.h> | ||
| 15 | |||
| 16 | /* | ||
| 17 | * Prototype: | ||
| 18 | * | ||
| 19 | * size_t __arch_copy_from_user(void *to, const void *from, size_t n) | ||
| 20 | * | ||
| 21 | * Purpose: | ||
| 22 | * | ||
| 23 | * copy a block to kernel memory from user memory | ||
| 24 | * | ||
| 25 | * Params: | ||
| 26 | * | ||
| 27 | * to = kernel memory | ||
| 28 | * from = user memory | ||
| 29 | * n = number of bytes to copy | ||
| 30 | * | ||
| 31 | * Return value: | ||
| 32 | * | ||
| 33 | * Number of bytes NOT copied. | ||
| 34 | */ | ||
| 35 | |||
| 36 | .macro ldr1w ptr reg abort | ||
| 37 | 100: ldrt \reg, [\ptr], #4 | ||
| 38 | .section __ex_table, "a" | ||
| 39 | .long 100b, \abort | ||
| 40 | .previous | ||
| 41 | .endm | ||
| 42 | |||
| 43 | .macro ldr4w ptr reg1 reg2 reg3 reg4 abort | ||
| 44 | ldr1w \ptr, \reg1, \abort | ||
| 45 | ldr1w \ptr, \reg2, \abort | ||
| 46 | ldr1w \ptr, \reg3, \abort | ||
| 47 | ldr1w \ptr, \reg4, \abort | ||
| 48 | .endm | ||
| 49 | |||
| 50 | .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
| 51 | ldr4w \ptr, \reg1, \reg2, \reg3, \reg4, \abort | ||
| 52 | ldr4w \ptr, \reg5, \reg6, \reg7, \reg8, \abort | ||
| 53 | .endm | ||
| 54 | |||
| 55 | .macro ldr1b ptr reg cond=al abort | ||
| 56 | 100: ldr\cond\()bt \reg, [\ptr], #1 | ||
| 57 | .section __ex_table, "a" | ||
| 58 | .long 100b, \abort | ||
| 59 | .previous | ||
| 60 | .endm | ||
| 61 | |||
| 62 | .macro str1w ptr reg abort | ||
| 63 | str \reg, [\ptr], #4 | ||
| 64 | .endm | ||
| 65 | |||
| 66 | .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
| 67 | stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} | ||
| 68 | .endm | ||
| 69 | |||
| 70 | .macro str1b ptr reg cond=al abort | ||
| 71 | str\cond\()b \reg, [\ptr], #1 | ||
| 72 | .endm | ||
| 73 | |||
| 74 | .macro enter reg1 reg2 | ||
| 75 | mov r3, #0 | ||
| 76 | stmdb sp!, {r0, r2, r3, \reg1, \reg2} | ||
| 77 | .endm | ||
| 78 | |||
| 79 | .macro exit reg1 reg2 | ||
| 80 | add sp, sp, #8 | ||
| 81 | ldmfd sp!, {r0, \reg1, \reg2} | ||
| 82 | .endm | ||
| 83 | |||
| 84 | .text | ||
| 85 | |||
| 86 | ENTRY(__arch_copy_from_user) | ||
| 87 | |||
| 88 | #include "copy_template.S" | ||
| 89 | |||
| 90 | .section .fixup,"ax" | ||
| 91 | .align 0 | ||
| 92 | copy_abort_preamble | ||
| 93 | ldmfd sp!, {r1, r2} | ||
| 94 | sub r3, r0, r1 | ||
| 95 | rsb r1, r3, r2 | ||
| 96 | str r1, [sp] | ||
| 97 | bl __memzero | ||
| 98 | ldr r0, [sp], #4 | ||
| 99 | copy_abort_end | ||
| 100 | .previous | ||
| 101 | |||
diff --git a/arch/arm/lib/copy_template.S b/arch/arm/lib/copy_template.S new file mode 100644 index 000000000000..838e435e4922 --- /dev/null +++ b/arch/arm/lib/copy_template.S | |||
| @@ -0,0 +1,255 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/copy_template.s | ||
| 3 | * | ||
| 4 | * Code template for optimized memory copy functions | ||
| 5 | * | ||
| 6 | * Author: Nicolas Pitre | ||
| 7 | * Created: Sep 28, 2005 | ||
| 8 | * Copyright: MontaVista Software, Inc. | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License version 2 as | ||
| 12 | * published by the Free Software Foundation. | ||
| 13 | */ | ||
| 14 | |||
| 15 | /* | ||
| 16 | * This can be used to enable code to cacheline align the source pointer. | ||
| 17 | * Experiments on tested architectures (StrongARM and XScale) didn't show | ||
| 18 | * this a worthwhile thing to do. That might be different in the future. | ||
| 19 | */ | ||
| 20 | //#define CALGN(code...) code | ||
| 21 | #define CALGN(code...) | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Theory of operation | ||
| 25 | * ------------------- | ||
| 26 | * | ||
| 27 | * This file provides the core code for a forward memory copy used in | ||
| 28 | * the implementation of memcopy(), copy_to_user() and copy_from_user(). | ||
| 29 | * | ||
| 30 | * The including file must define the following accessor macros | ||
| 31 | * according to the need of the given function: | ||
| 32 | * | ||
| 33 | * ldr1w ptr reg abort | ||
| 34 | * | ||
| 35 | * This loads one word from 'ptr', stores it in 'reg' and increments | ||
| 36 | * 'ptr' to the next word. The 'abort' argument is used for fixup tables. | ||
| 37 | * | ||
| 38 | * ldr4w ptr reg1 reg2 reg3 reg4 abort | ||
| 39 | * ldr8w ptr, reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
| 40 | * | ||
| 41 | * This loads four or eight words starting from 'ptr', stores them | ||
| 42 | * in provided registers and increments 'ptr' past those words. | ||
| 43 | * The'abort' argument is used for fixup tables. | ||
| 44 | * | ||
| 45 | * ldr1b ptr reg cond abort | ||
| 46 | * | ||
| 47 | * Similar to ldr1w, but it loads a byte and increments 'ptr' one byte. | ||
| 48 | * It also must apply the condition code if provided, otherwise the | ||
| 49 | * "al" condition is assumed by default. | ||
| 50 | * | ||
| 51 | * str1w ptr reg abort | ||
| 52 | * str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
| 53 | * str1b ptr reg cond abort | ||
| 54 | * | ||
| 55 | * Same as their ldr* counterparts, but data is stored to 'ptr' location | ||
| 56 | * rather than being loaded. | ||
| 57 | * | ||
| 58 | * enter reg1 reg2 | ||
| 59 | * | ||
| 60 | * Preserve the provided registers on the stack plus any additional | ||
| 61 | * data as needed by the implementation including this code. Called | ||
| 62 | * upon code entry. | ||
| 63 | * | ||
| 64 | * exit reg1 reg2 | ||
| 65 | * | ||
| 66 | * Restore registers with the values previously saved with the | ||
| 67 | * 'preserv' macro. Called upon code termination. | ||
| 68 | */ | ||
| 69 | |||
| 70 | |||
| 71 | enter r4, lr | ||
| 72 | |||
| 73 | subs r2, r2, #4 | ||
| 74 | blt 8f | ||
| 75 | ands ip, r0, #3 | ||
| 76 | PLD( pld [r1, #0] ) | ||
| 77 | bne 9f | ||
| 78 | ands ip, r1, #3 | ||
| 79 | bne 10f | ||
| 80 | |||
| 81 | 1: subs r2, r2, #(28) | ||
| 82 | stmfd sp!, {r5 - r8} | ||
| 83 | blt 5f | ||
| 84 | |||
| 85 | CALGN( ands ip, r1, #31 ) | ||
| 86 | CALGN( rsb r3, ip, #32 ) | ||
| 87 | CALGN( sbcnes r4, r3, r2 ) @ C is always set here | ||
| 88 | CALGN( bcs 2f ) | ||
| 89 | CALGN( adr r4, 6f ) | ||
| 90 | CALGN( subs r2, r2, r3 ) @ C gets set | ||
| 91 | CALGN( add pc, r4, ip ) | ||
| 92 | |||
| 93 | PLD( pld [r1, #0] ) | ||
| 94 | 2: PLD( subs r2, r2, #96 ) | ||
| 95 | PLD( pld [r1, #28] ) | ||
| 96 | PLD( blt 4f ) | ||
| 97 | PLD( pld [r1, #60] ) | ||
| 98 | PLD( pld [r1, #92] ) | ||
| 99 | |||
| 100 | 3: PLD( pld [r1, #124] ) | ||
| 101 | 4: ldr8w r1, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f | ||
| 102 | subs r2, r2, #32 | ||
| 103 | str8w r0, r3, r4, r5, r6, r7, r8, ip, lr, abort=20f | ||
| 104 | bge 3b | ||
| 105 | PLD( cmn r2, #96 ) | ||
| 106 | PLD( bge 4b ) | ||
| 107 | |||
| 108 | 5: ands ip, r2, #28 | ||
| 109 | rsb ip, ip, #32 | ||
| 110 | addne pc, pc, ip @ C is always clear here | ||
| 111 | b 7f | ||
| 112 | 6: nop | ||
| 113 | ldr1w r1, r3, abort=20f | ||
| 114 | ldr1w r1, r4, abort=20f | ||
| 115 | ldr1w r1, r5, abort=20f | ||
| 116 | ldr1w r1, r6, abort=20f | ||
| 117 | ldr1w r1, r7, abort=20f | ||
| 118 | ldr1w r1, r8, abort=20f | ||
| 119 | ldr1w r1, lr, abort=20f | ||
| 120 | |||
| 121 | add pc, pc, ip | ||
| 122 | nop | ||
| 123 | nop | ||
| 124 | str1w r0, r3, abort=20f | ||
| 125 | str1w r0, r4, abort=20f | ||
| 126 | str1w r0, r5, abort=20f | ||
| 127 | str1w r0, r6, abort=20f | ||
| 128 | str1w r0, r7, abort=20f | ||
| 129 | str1w r0, r8, abort=20f | ||
| 130 | str1w r0, lr, abort=20f | ||
| 131 | |||
| 132 | CALGN( bcs 2b ) | ||
| 133 | |||
| 134 | 7: ldmfd sp!, {r5 - r8} | ||
| 135 | |||
| 136 | 8: movs r2, r2, lsl #31 | ||
| 137 | ldr1b r1, r3, ne, abort=21f | ||
| 138 | ldr1b r1, r4, cs, abort=21f | ||
| 139 | ldr1b r1, ip, cs, abort=21f | ||
| 140 | str1b r0, r3, ne, abort=21f | ||
| 141 | str1b r0, r4, cs, abort=21f | ||
| 142 | str1b r0, ip, cs, abort=21f | ||
| 143 | |||
| 144 | exit r4, pc | ||
| 145 | |||
| 146 | 9: rsb ip, ip, #4 | ||
| 147 | cmp ip, #2 | ||
| 148 | ldr1b r1, r3, gt, abort=21f | ||
| 149 | ldr1b r1, r4, ge, abort=21f | ||
| 150 | ldr1b r1, lr, abort=21f | ||
| 151 | str1b r0, r3, gt, abort=21f | ||
| 152 | str1b r0, r4, ge, abort=21f | ||
| 153 | subs r2, r2, ip | ||
| 154 | str1b r0, lr, abort=21f | ||
| 155 | blt 8b | ||
| 156 | ands ip, r1, #3 | ||
| 157 | beq 1b | ||
| 158 | |||
| 159 | 10: bic r1, r1, #3 | ||
| 160 | cmp ip, #2 | ||
| 161 | ldr1w r1, lr, abort=21f | ||
| 162 | beq 17f | ||
| 163 | bgt 18f | ||
| 164 | |||
| 165 | |||
| 166 | .macro forward_copy_shift pull push | ||
| 167 | |||
| 168 | subs r2, r2, #28 | ||
| 169 | blt 14f | ||
| 170 | |||
| 171 | CALGN( ands ip, r1, #31 ) | ||
| 172 | CALGN( rsb ip, ip, #32 ) | ||
| 173 | CALGN( sbcnes r4, ip, r2 ) @ C is always set here | ||
| 174 | CALGN( subcc r2, r2, ip ) | ||
| 175 | CALGN( bcc 15f ) | ||
| 176 | |||
| 177 | 11: stmfd sp!, {r5 - r9} | ||
| 178 | |||
| 179 | PLD( pld [r1, #0] ) | ||
| 180 | PLD( subs r2, r2, #96 ) | ||
| 181 | PLD( pld [r1, #28] ) | ||
| 182 | PLD( blt 13f ) | ||
| 183 | PLD( pld [r1, #60] ) | ||
| 184 | PLD( pld [r1, #92] ) | ||
| 185 | |||
| 186 | 12: PLD( pld [r1, #124] ) | ||
| 187 | 13: ldr4w r1, r4, r5, r6, r7, abort=19f | ||
| 188 | mov r3, lr, pull #\pull | ||
| 189 | subs r2, r2, #32 | ||
| 190 | ldr4w r1, r8, r9, ip, lr, abort=19f | ||
| 191 | orr r3, r3, r4, push #\push | ||
| 192 | mov r4, r4, pull #\pull | ||
| 193 | orr r4, r4, r5, push #\push | ||
| 194 | mov r5, r5, pull #\pull | ||
| 195 | orr r5, r5, r6, push #\push | ||
| 196 | mov r6, r6, pull #\pull | ||
| 197 | orr r6, r6, r7, push #\push | ||
| 198 | mov r7, r7, pull #\pull | ||
| 199 | orr r7, r7, r8, push #\push | ||
| 200 | mov r8, r8, pull #\pull | ||
| 201 | orr r8, r8, r9, push #\push | ||
| 202 | mov r9, r9, pull #\pull | ||
| 203 | orr r9, r9, ip, push #\push | ||
| 204 | mov ip, ip, pull #\pull | ||
| 205 | orr ip, ip, lr, push #\push | ||
| 206 | str8w r0, r3, r4, r5, r6, r7, r8, r9, ip, , abort=19f | ||
| 207 | bge 12b | ||
| 208 | PLD( cmn r2, #96 ) | ||
| 209 | PLD( bge 13b ) | ||
| 210 | |||
| 211 | ldmfd sp!, {r5 - r9} | ||
| 212 | |||
| 213 | 14: ands ip, r2, #28 | ||
| 214 | beq 16f | ||
| 215 | |||
| 216 | 15: mov r3, lr, pull #\pull | ||
| 217 | ldr1w r1, lr, abort=21f | ||
| 218 | subs ip, ip, #4 | ||
| 219 | orr r3, r3, lr, push #\push | ||
| 220 | str1w r0, r3, abort=21f | ||
| 221 | bgt 15b | ||
| 222 | CALGN( cmp r2, #0 ) | ||
| 223 | CALGN( bge 11b ) | ||
| 224 | |||
| 225 | 16: sub r1, r1, #(\push / 8) | ||
| 226 | b 8b | ||
| 227 | |||
| 228 | .endm | ||
| 229 | |||
| 230 | |||
| 231 | forward_copy_shift pull=8 push=24 | ||
| 232 | |||
| 233 | 17: forward_copy_shift pull=16 push=16 | ||
| 234 | |||
| 235 | 18: forward_copy_shift pull=24 push=8 | ||
| 236 | |||
| 237 | |||
| 238 | /* | ||
| 239 | * Abort preanble and completion macros. | ||
| 240 | * If a fixup handler is required then those macros must surround it. | ||
| 241 | * It is assumed that the fixup code will handle the private part of | ||
| 242 | * the exit macro. | ||
| 243 | */ | ||
| 244 | |||
| 245 | .macro copy_abort_preamble | ||
| 246 | 19: ldmfd sp!, {r5 - r9} | ||
| 247 | b 21f | ||
| 248 | 20: ldmfd sp!, {r5 - r8} | ||
| 249 | 21: | ||
| 250 | .endm | ||
| 251 | |||
| 252 | .macro copy_abort_end | ||
| 253 | ldmfd sp!, {r4, pc} | ||
| 254 | .endm | ||
| 255 | |||
diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S new file mode 100644 index 000000000000..4a6d8ea14022 --- /dev/null +++ b/arch/arm/lib/copy_to_user.S | |||
| @@ -0,0 +1,101 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/copy_to_user.S | ||
| 3 | * | ||
| 4 | * Author: Nicolas Pitre | ||
| 5 | * Created: Sep 29, 2005 | ||
| 6 | * Copyright: MontaVista Software, Inc. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/linkage.h> | ||
| 14 | #include <asm/assembler.h> | ||
| 15 | |||
| 16 | /* | ||
| 17 | * Prototype: | ||
| 18 | * | ||
| 19 | * size_t __arch_copy_to_user(void *to, const void *from, size_t n) | ||
| 20 | * | ||
| 21 | * Purpose: | ||
| 22 | * | ||
| 23 | * copy a block to user memory from kernel memory | ||
| 24 | * | ||
| 25 | * Params: | ||
| 26 | * | ||
| 27 | * to = user memory | ||
| 28 | * from = kernel memory | ||
| 29 | * n = number of bytes to copy | ||
| 30 | * | ||
| 31 | * Return value: | ||
| 32 | * | ||
| 33 | * Number of bytes NOT copied. | ||
| 34 | */ | ||
| 35 | |||
| 36 | .macro ldr1w ptr reg abort | ||
| 37 | ldr \reg, [\ptr], #4 | ||
| 38 | .endm | ||
| 39 | |||
| 40 | .macro ldr4w ptr reg1 reg2 reg3 reg4 abort | ||
| 41 | ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4} | ||
| 42 | .endm | ||
| 43 | |||
| 44 | .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
| 45 | ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} | ||
| 46 | .endm | ||
| 47 | |||
| 48 | .macro ldr1b ptr reg cond=al abort | ||
| 49 | ldr\cond\()b \reg, [\ptr], #1 | ||
| 50 | .endm | ||
| 51 | |||
| 52 | .macro str1w ptr reg abort | ||
| 53 | 100: strt \reg, [\ptr], #4 | ||
| 54 | .section __ex_table, "a" | ||
| 55 | .long 100b, \abort | ||
| 56 | .previous | ||
| 57 | .endm | ||
| 58 | |||
| 59 | .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort | ||
| 60 | str1w \ptr, \reg1, \abort | ||
| 61 | str1w \ptr, \reg2, \abort | ||
| 62 | str1w \ptr, \reg3, \abort | ||
| 63 | str1w \ptr, \reg4, \abort | ||
| 64 | str1w \ptr, \reg5, \abort | ||
| 65 | str1w \ptr, \reg6, \abort | ||
| 66 | str1w \ptr, \reg7, \abort | ||
| 67 | str1w \ptr, \reg8, \abort | ||
| 68 | .endm | ||
| 69 | |||
| 70 | .macro str1b ptr reg cond=al abort | ||
| 71 | 100: str\cond\()bt \reg, [\ptr], #1 | ||
| 72 | .section __ex_table, "a" | ||
| 73 | .long 100b, \abort | ||
| 74 | .previous | ||
| 75 | .endm | ||
| 76 | |||
| 77 | .macro enter reg1 reg2 | ||
| 78 | mov r3, #0 | ||
| 79 | stmdb sp!, {r0, r2, r3, \reg1, \reg2} | ||
| 80 | .endm | ||
| 81 | |||
| 82 | .macro exit reg1 reg2 | ||
| 83 | add sp, sp, #8 | ||
| 84 | ldmfd sp!, {r0, \reg1, \reg2} | ||
| 85 | .endm | ||
| 86 | |||
| 87 | .text | ||
| 88 | |||
| 89 | ENTRY(__arch_copy_to_user) | ||
| 90 | |||
| 91 | #include "copy_template.S" | ||
| 92 | |||
| 93 | .section .fixup,"ax" | ||
| 94 | .align 0 | ||
| 95 | copy_abort_preamble | ||
| 96 | ldmfd sp!, {r1, r2, r3} | ||
| 97 | sub r0, r0, r1 | ||
| 98 | rsb r0, r0, r2 | ||
| 99 | copy_abort_end | ||
| 100 | .previous | ||
| 101 | |||
diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S index f5a593ceb8cc..7e71d6708a8d 100644 --- a/arch/arm/lib/memcpy.S +++ b/arch/arm/lib/memcpy.S | |||
| @@ -1,393 +1,59 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * linux/arch/arm/lib/memcpy.S | 2 | * linux/arch/arm/lib/memcpy.S |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 1995-1999 Russell King | 4 | * Author: Nicolas Pitre |
| 5 | * Created: Sep 28, 2005 | ||
| 6 | * Copyright: MontaVista Software, Inc. | ||
| 5 | * | 7 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
| 8 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
| 9 | * | ||
| 10 | * ASM optimised string functions | ||
| 11 | */ | 11 | */ |
| 12 | |||
| 12 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
| 13 | #include <asm/assembler.h> | 14 | #include <asm/assembler.h> |
| 14 | 15 | ||
| 15 | .text | 16 | .macro ldr1w ptr reg abort |
| 16 | 17 | ldr \reg, [\ptr], #4 | |
| 17 | #define ENTER \ | 18 | .endm |
| 18 | mov ip,sp ;\ | ||
| 19 | stmfd sp!,{r0,r4-r9,fp,ip,lr,pc} ;\ | ||
| 20 | sub fp,ip,#4 | ||
| 21 | |||
| 22 | #define EXIT \ | ||
| 23 | LOADREGS(ea, fp, {r0, r4 - r9, fp, sp, pc}) | ||
| 24 | |||
| 25 | #define EXITEQ \ | ||
| 26 | LOADREGS(eqea, fp, {r0, r4 - r9, fp, sp, pc}) | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Prototype: void memcpy(void *to,const void *from,unsigned long n); | ||
| 30 | */ | ||
| 31 | ENTRY(memcpy) | ||
| 32 | ENTRY(memmove) | ||
| 33 | ENTER | ||
| 34 | cmp r1, r0 | ||
| 35 | bcc 23f | ||
| 36 | subs r2, r2, #4 | ||
| 37 | blt 6f | ||
| 38 | PLD( pld [r1, #0] ) | ||
| 39 | ands ip, r0, #3 | ||
| 40 | bne 7f | ||
| 41 | ands ip, r1, #3 | ||
| 42 | bne 8f | ||
| 43 | 19 | ||
| 44 | 1: subs r2, r2, #8 | 20 | .macro ldr4w ptr reg1 reg2 reg3 reg4 abort |
| 45 | blt 5f | 21 | ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4} |
| 46 | subs r2, r2, #20 | 22 | .endm |
| 47 | blt 4f | ||
| 48 | PLD( pld [r1, #28] ) | ||
| 49 | PLD( subs r2, r2, #64 ) | ||
| 50 | PLD( blt 3f ) | ||
| 51 | 2: PLD( pld [r1, #60] ) | ||
| 52 | PLD( pld [r1, #92] ) | ||
| 53 | ldmia r1!, {r3 - r9, ip} | ||
| 54 | subs r2, r2, #32 | ||
| 55 | stmgeia r0!, {r3 - r9, ip} | ||
| 56 | ldmgeia r1!, {r3 - r9, ip} | ||
| 57 | subges r2, r2, #32 | ||
| 58 | stmia r0!, {r3 - r9, ip} | ||
| 59 | bge 2b | ||
| 60 | 3: PLD( ldmia r1!, {r3 - r9, ip} ) | ||
| 61 | PLD( adds r2, r2, #32 ) | ||
| 62 | PLD( stmgeia r0!, {r3 - r9, ip} ) | ||
| 63 | PLD( ldmgeia r1!, {r3 - r9, ip} ) | ||
| 64 | PLD( subges r2, r2, #32 ) | ||
| 65 | PLD( stmia r0!, {r3 - r9, ip} ) | ||
| 66 | 4: cmn r2, #16 | ||
| 67 | ldmgeia r1!, {r3 - r6} | ||
| 68 | subge r2, r2, #16 | ||
| 69 | stmgeia r0!, {r3 - r6} | ||
| 70 | adds r2, r2, #20 | ||
| 71 | ldmgeia r1!, {r3 - r5} | ||
| 72 | subge r2, r2, #12 | ||
| 73 | stmgeia r0!, {r3 - r5} | ||
| 74 | 5: adds r2, r2, #8 | ||
| 75 | blt 6f | ||
| 76 | subs r2, r2, #4 | ||
| 77 | ldrlt r3, [r1], #4 | ||
| 78 | ldmgeia r1!, {r4, r5} | ||
| 79 | subge r2, r2, #4 | ||
| 80 | strlt r3, [r0], #4 | ||
| 81 | stmgeia r0!, {r4, r5} | ||
| 82 | 23 | ||
| 83 | 6: adds r2, r2, #4 | 24 | .macro ldr8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort |
| 84 | EXITEQ | 25 | ldmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} |
| 85 | cmp r2, #2 | 26 | .endm |
| 86 | ldrb r3, [r1], #1 | ||
| 87 | ldrgeb r4, [r1], #1 | ||
| 88 | ldrgtb r5, [r1], #1 | ||
| 89 | strb r3, [r0], #1 | ||
| 90 | strgeb r4, [r0], #1 | ||
| 91 | strgtb r5, [r0], #1 | ||
| 92 | EXIT | ||
| 93 | 27 | ||
| 94 | 7: rsb ip, ip, #4 | 28 | .macro ldr1b ptr reg cond=al abort |
| 95 | cmp ip, #2 | 29 | ldr\cond\()b \reg, [\ptr], #1 |
| 96 | ldrb r3, [r1], #1 | 30 | .endm |
| 97 | ldrgeb r4, [r1], #1 | ||
| 98 | ldrgtb r5, [r1], #1 | ||
| 99 | strb r3, [r0], #1 | ||
| 100 | strgeb r4, [r0], #1 | ||
| 101 | strgtb r5, [r0], #1 | ||
| 102 | subs r2, r2, ip | ||
| 103 | blt 6b | ||
| 104 | ands ip, r1, #3 | ||
| 105 | beq 1b | ||
| 106 | 31 | ||
| 107 | 8: bic r1, r1, #3 | 32 | .macro str1w ptr reg abort |
| 108 | ldr r7, [r1], #4 | 33 | str \reg, [\ptr], #4 |
| 109 | cmp ip, #2 | 34 | .endm |
| 110 | bgt 18f | ||
| 111 | beq 13f | ||
| 112 | cmp r2, #12 | ||
| 113 | blt 11f | ||
| 114 | PLD( pld [r1, #12] ) | ||
| 115 | sub r2, r2, #12 | ||
| 116 | PLD( subs r2, r2, #32 ) | ||
| 117 | PLD( blt 10f ) | ||
| 118 | PLD( pld [r1, #28] ) | ||
| 119 | 9: PLD( pld [r1, #44] ) | ||
| 120 | 10: mov r3, r7, pull #8 | ||
| 121 | ldmia r1!, {r4 - r7} | ||
| 122 | subs r2, r2, #16 | ||
| 123 | orr r3, r3, r4, push #24 | ||
| 124 | mov r4, r4, pull #8 | ||
| 125 | orr r4, r4, r5, push #24 | ||
| 126 | mov r5, r5, pull #8 | ||
| 127 | orr r5, r5, r6, push #24 | ||
| 128 | mov r6, r6, pull #8 | ||
| 129 | orr r6, r6, r7, push #24 | ||
| 130 | stmia r0!, {r3 - r6} | ||
| 131 | bge 9b | ||
| 132 | PLD( cmn r2, #32 ) | ||
| 133 | PLD( bge 10b ) | ||
| 134 | PLD( add r2, r2, #32 ) | ||
| 135 | adds r2, r2, #12 | ||
| 136 | blt 12f | ||
| 137 | 11: mov r3, r7, pull #8 | ||
| 138 | ldr r7, [r1], #4 | ||
| 139 | subs r2, r2, #4 | ||
| 140 | orr r3, r3, r7, push #24 | ||
| 141 | str r3, [r0], #4 | ||
| 142 | bge 11b | ||
| 143 | 12: sub r1, r1, #3 | ||
| 144 | b 6b | ||
| 145 | 35 | ||
| 146 | 13: cmp r2, #12 | 36 | .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort |
| 147 | blt 16f | 37 | stmia \ptr!, {\reg1, \reg2, \reg3, \reg4, \reg5, \reg6, \reg7, \reg8} |
| 148 | PLD( pld [r1, #12] ) | 38 | .endm |
| 149 | sub r2, r2, #12 | ||
| 150 | PLD( subs r2, r2, #32 ) | ||
| 151 | PLD( blt 15f ) | ||
| 152 | PLD( pld [r1, #28] ) | ||
| 153 | 14: PLD( pld [r1, #44] ) | ||
| 154 | 15: mov r3, r7, pull #16 | ||
| 155 | ldmia r1!, {r4 - r7} | ||
| 156 | subs r2, r2, #16 | ||
| 157 | orr r3, r3, r4, push #16 | ||
| 158 | mov r4, r4, pull #16 | ||
| 159 | orr r4, r4, r5, push #16 | ||
| 160 | mov r5, r5, pull #16 | ||
| 161 | orr r5, r5, r6, push #16 | ||
| 162 | mov r6, r6, pull #16 | ||
| 163 | orr r6, r6, r7, push #16 | ||
| 164 | stmia r0!, {r3 - r6} | ||
| 165 | bge 14b | ||
| 166 | PLD( cmn r2, #32 ) | ||
| 167 | PLD( bge 15b ) | ||
| 168 | PLD( add r2, r2, #32 ) | ||
| 169 | adds r2, r2, #12 | ||
| 170 | blt 17f | ||
| 171 | 16: mov r3, r7, pull #16 | ||
| 172 | ldr r7, [r1], #4 | ||
| 173 | subs r2, r2, #4 | ||
| 174 | orr r3, r3, r7, push #16 | ||
| 175 | str r3, [r0], #4 | ||
| 176 | bge 16b | ||
| 177 | 17: sub r1, r1, #2 | ||
| 178 | b 6b | ||
| 179 | 39 | ||
| 180 | 18: cmp r2, #12 | 40 | .macro str1b ptr reg cond=al abort |
| 181 | blt 21f | 41 | str\cond\()b \reg, [\ptr], #1 |
| 182 | PLD( pld [r1, #12] ) | 42 | .endm |
| 183 | sub r2, r2, #12 | ||
| 184 | PLD( subs r2, r2, #32 ) | ||
| 185 | PLD( blt 20f ) | ||
| 186 | PLD( pld [r1, #28] ) | ||
| 187 | 19: PLD( pld [r1, #44] ) | ||
| 188 | 20: mov r3, r7, pull #24 | ||
| 189 | ldmia r1!, {r4 - r7} | ||
| 190 | subs r2, r2, #16 | ||
| 191 | orr r3, r3, r4, push #8 | ||
| 192 | mov r4, r4, pull #24 | ||
| 193 | orr r4, r4, r5, push #8 | ||
| 194 | mov r5, r5, pull #24 | ||
| 195 | orr r5, r5, r6, push #8 | ||
| 196 | mov r6, r6, pull #24 | ||
| 197 | orr r6, r6, r7, push #8 | ||
| 198 | stmia r0!, {r3 - r6} | ||
| 199 | bge 19b | ||
| 200 | PLD( cmn r2, #32 ) | ||
| 201 | PLD( bge 20b ) | ||
| 202 | PLD( add r2, r2, #32 ) | ||
| 203 | adds r2, r2, #12 | ||
| 204 | blt 22f | ||
| 205 | 21: mov r3, r7, pull #24 | ||
| 206 | ldr r7, [r1], #4 | ||
| 207 | subs r2, r2, #4 | ||
| 208 | orr r3, r3, r7, push #8 | ||
| 209 | str r3, [r0], #4 | ||
| 210 | bge 21b | ||
| 211 | 22: sub r1, r1, #1 | ||
| 212 | b 6b | ||
| 213 | 43 | ||
| 44 | .macro enter reg1 reg2 | ||
| 45 | stmdb sp!, {r0, \reg1, \reg2} | ||
| 46 | .endm | ||
| 214 | 47 | ||
| 215 | 23: add r1, r1, r2 | 48 | .macro exit reg1 reg2 |
| 216 | add r0, r0, r2 | 49 | ldmfd sp!, {r0, \reg1, \reg2} |
| 217 | subs r2, r2, #4 | 50 | .endm |
| 218 | blt 29f | ||
| 219 | PLD( pld [r1, #-4] ) | ||
| 220 | ands ip, r0, #3 | ||
| 221 | bne 30f | ||
| 222 | ands ip, r1, #3 | ||
| 223 | bne 31f | ||
| 224 | 51 | ||
| 225 | 24: subs r2, r2, #8 | 52 | .text |
| 226 | blt 28f | ||
| 227 | subs r2, r2, #20 | ||
| 228 | blt 27f | ||
| 229 | PLD( pld [r1, #-32] ) | ||
| 230 | PLD( subs r2, r2, #64 ) | ||
| 231 | PLD( blt 26f ) | ||
| 232 | 25: PLD( pld [r1, #-64] ) | ||
| 233 | PLD( pld [r1, #-96] ) | ||
| 234 | ldmdb r1!, {r3 - r9, ip} | ||
| 235 | subs r2, r2, #32 | ||
| 236 | stmgedb r0!, {r3 - r9, ip} | ||
| 237 | ldmgedb r1!, {r3 - r9, ip} | ||
| 238 | subges r2, r2, #32 | ||
| 239 | stmdb r0!, {r3 - r9, ip} | ||
| 240 | bge 25b | ||
| 241 | 26: PLD( ldmdb r1!, {r3 - r9, ip} ) | ||
| 242 | PLD( adds r2, r2, #32 ) | ||
| 243 | PLD( stmgedb r0!, {r3 - r9, ip} ) | ||
| 244 | PLD( ldmgedb r1!, {r3 - r9, ip} ) | ||
| 245 | PLD( subges r2, r2, #32 ) | ||
| 246 | PLD( stmdb r0!, {r3 - r9, ip} ) | ||
| 247 | 27: cmn r2, #16 | ||
| 248 | ldmgedb r1!, {r3 - r6} | ||
| 249 | subge r2, r2, #16 | ||
| 250 | stmgedb r0!, {r3 - r6} | ||
| 251 | adds r2, r2, #20 | ||
| 252 | ldmgedb r1!, {r3 - r5} | ||
| 253 | subge r2, r2, #12 | ||
| 254 | stmgedb r0!, {r3 - r5} | ||
| 255 | 28: adds r2, r2, #8 | ||
| 256 | blt 29f | ||
| 257 | subs r2, r2, #4 | ||
| 258 | ldrlt r3, [r1, #-4]! | ||
| 259 | ldmgedb r1!, {r4, r5} | ||
| 260 | subge r2, r2, #4 | ||
| 261 | strlt r3, [r0, #-4]! | ||
| 262 | stmgedb r0!, {r4, r5} | ||
| 263 | 53 | ||
| 264 | 29: adds r2, r2, #4 | 54 | /* Prototype: void *memcpy(void *dest, const void *src, size_t n); */ |
| 265 | EXITEQ | ||
| 266 | cmp r2, #2 | ||
| 267 | ldrb r3, [r1, #-1]! | ||
| 268 | ldrgeb r4, [r1, #-1]! | ||
| 269 | ldrgtb r5, [r1, #-1]! | ||
| 270 | strb r3, [r0, #-1]! | ||
| 271 | strgeb r4, [r0, #-1]! | ||
| 272 | strgtb r5, [r0, #-1]! | ||
| 273 | EXIT | ||
| 274 | 55 | ||
| 275 | 30: cmp ip, #2 | 56 | ENTRY(memcpy) |
| 276 | ldrb r3, [r1, #-1]! | ||
| 277 | ldrgeb r4, [r1, #-1]! | ||
| 278 | ldrgtb r5, [r1, #-1]! | ||
| 279 | strb r3, [r0, #-1]! | ||
| 280 | strgeb r4, [r0, #-1]! | ||
| 281 | strgtb r5, [r0, #-1]! | ||
| 282 | subs r2, r2, ip | ||
| 283 | blt 29b | ||
| 284 | ands ip, r1, #3 | ||
| 285 | beq 24b | ||
| 286 | |||
| 287 | 31: bic r1, r1, #3 | ||
| 288 | ldr r3, [r1], #0 | ||
| 289 | cmp ip, #2 | ||
| 290 | blt 41f | ||
| 291 | beq 36f | ||
| 292 | cmp r2, #12 | ||
| 293 | blt 34f | ||
| 294 | PLD( pld [r1, #-16] ) | ||
| 295 | sub r2, r2, #12 | ||
| 296 | PLD( subs r2, r2, #32 ) | ||
| 297 | PLD( blt 33f ) | ||
| 298 | PLD( pld [r1, #-32] ) | ||
| 299 | 32: PLD( pld [r1, #-48] ) | ||
| 300 | 33: mov r7, r3, push #8 | ||
| 301 | ldmdb r1!, {r3, r4, r5, r6} | ||
| 302 | subs r2, r2, #16 | ||
| 303 | orr r7, r7, r6, pull #24 | ||
| 304 | mov r6, r6, push #8 | ||
| 305 | orr r6, r6, r5, pull #24 | ||
| 306 | mov r5, r5, push #8 | ||
| 307 | orr r5, r5, r4, pull #24 | ||
| 308 | mov r4, r4, push #8 | ||
| 309 | orr r4, r4, r3, pull #24 | ||
| 310 | stmdb r0!, {r4, r5, r6, r7} | ||
| 311 | bge 32b | ||
| 312 | PLD( cmn r2, #32 ) | ||
| 313 | PLD( bge 33b ) | ||
| 314 | PLD( add r2, r2, #32 ) | ||
| 315 | adds r2, r2, #12 | ||
| 316 | blt 35f | ||
| 317 | 34: mov ip, r3, push #8 | ||
| 318 | ldr r3, [r1, #-4]! | ||
| 319 | subs r2, r2, #4 | ||
| 320 | orr ip, ip, r3, pull #24 | ||
| 321 | str ip, [r0, #-4]! | ||
| 322 | bge 34b | ||
| 323 | 35: add r1, r1, #3 | ||
| 324 | b 29b | ||
| 325 | |||
| 326 | 36: cmp r2, #12 | ||
| 327 | blt 39f | ||
| 328 | PLD( pld [r1, #-16] ) | ||
| 329 | sub r2, r2, #12 | ||
| 330 | PLD( subs r2, r2, #32 ) | ||
| 331 | PLD( blt 38f ) | ||
| 332 | PLD( pld [r1, #-32] ) | ||
| 333 | 37: PLD( pld [r1, #-48] ) | ||
| 334 | 38: mov r7, r3, push #16 | ||
| 335 | ldmdb r1!, {r3, r4, r5, r6} | ||
| 336 | subs r2, r2, #16 | ||
| 337 | orr r7, r7, r6, pull #16 | ||
| 338 | mov r6, r6, push #16 | ||
| 339 | orr r6, r6, r5, pull #16 | ||
| 340 | mov r5, r5, push #16 | ||
| 341 | orr r5, r5, r4, pull #16 | ||
| 342 | mov r4, r4, push #16 | ||
| 343 | orr r4, r4, r3, pull #16 | ||
| 344 | stmdb r0!, {r4, r5, r6, r7} | ||
| 345 | bge 37b | ||
| 346 | PLD( cmn r2, #32 ) | ||
| 347 | PLD( bge 38b ) | ||
| 348 | PLD( add r2, r2, #32 ) | ||
| 349 | adds r2, r2, #12 | ||
| 350 | blt 40f | ||
| 351 | 39: mov ip, r3, push #16 | ||
| 352 | ldr r3, [r1, #-4]! | ||
| 353 | subs r2, r2, #4 | ||
| 354 | orr ip, ip, r3, pull #16 | ||
| 355 | str ip, [r0, #-4]! | ||
| 356 | bge 39b | ||
| 357 | 40: add r1, r1, #2 | ||
| 358 | b 29b | ||
| 359 | 57 | ||
| 360 | 41: cmp r2, #12 | 58 | #include "copy_template.S" |
| 361 | blt 44f | ||
| 362 | PLD( pld [r1, #-16] ) | ||
| 363 | sub r2, r2, #12 | ||
| 364 | PLD( subs r2, r2, #32 ) | ||
| 365 | PLD( blt 43f ) | ||
| 366 | PLD( pld [r1, #-32] ) | ||
| 367 | 42: PLD( pld [r1, #-48] ) | ||
| 368 | 43: mov r7, r3, push #24 | ||
| 369 | ldmdb r1!, {r3, r4, r5, r6} | ||
| 370 | subs r2, r2, #16 | ||
| 371 | orr r7, r7, r6, pull #8 | ||
| 372 | mov r6, r6, push #24 | ||
| 373 | orr r6, r6, r5, pull #8 | ||
| 374 | mov r5, r5, push #24 | ||
| 375 | orr r5, r5, r4, pull #8 | ||
| 376 | mov r4, r4, push #24 | ||
| 377 | orr r4, r4, r3, pull #8 | ||
| 378 | stmdb r0!, {r4, r5, r6, r7} | ||
| 379 | bge 42b | ||
| 380 | PLD( cmn r2, #32 ) | ||
| 381 | PLD( bge 43b ) | ||
| 382 | PLD( add r2, r2, #32 ) | ||
| 383 | adds r2, r2, #12 | ||
| 384 | blt 45f | ||
| 385 | 44: mov ip, r3, push #24 | ||
| 386 | ldr r3, [r1, #-4]! | ||
| 387 | subs r2, r2, #4 | ||
| 388 | orr ip, ip, r3, pull #8 | ||
| 389 | str ip, [r0, #-4]! | ||
| 390 | bge 44b | ||
| 391 | 45: add r1, r1, #1 | ||
| 392 | b 29b | ||
| 393 | 59 | ||
diff --git a/arch/arm/lib/memmove.S b/arch/arm/lib/memmove.S new file mode 100644 index 000000000000..ef7fddc14ac9 --- /dev/null +++ b/arch/arm/lib/memmove.S | |||
| @@ -0,0 +1,206 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/lib/memmove.S | ||
| 3 | * | ||
| 4 | * Author: Nicolas Pitre | ||
| 5 | * Created: Sep 28, 2005 | ||
| 6 | * Copyright: (C) MontaVista Software Inc. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/linkage.h> | ||
| 14 | #include <asm/assembler.h> | ||
| 15 | |||
| 16 | /* | ||
| 17 | * This can be used to enable code to cacheline align the source pointer. | ||
| 18 | * Experiments on tested architectures (StrongARM and XScale) didn't show | ||
| 19 | * this a worthwhile thing to do. That might be different in the future. | ||
| 20 | */ | ||
| 21 | //#define CALGN(code...) code | ||
| 22 | #define CALGN(code...) | ||
| 23 | |||
| 24 | .text | ||
| 25 | |||
| 26 | /* | ||
| 27 | * Prototype: void *memmove(void *dest, const void *src, size_t n); | ||
| 28 | * | ||
| 29 | * Note: | ||
| 30 | * | ||
| 31 | * If the memory regions don't overlap, we simply branch to memcpy which is | ||
| 32 | * normally a bit faster. Otherwise the copy is done going downwards. This | ||
| 33 | * is a transposition of the code from copy_template.S but with the copy | ||
| 34 | * occurring in the opposite direction. | ||
| 35 | */ | ||
| 36 | |||
| 37 | ENTRY(memmove) | ||
| 38 | |||
| 39 | subs ip, r0, r1 | ||
| 40 | cmphi r2, ip | ||
| 41 | bls memcpy | ||
| 42 | |||
| 43 | stmfd sp!, {r0, r4, lr} | ||
| 44 | add r1, r1, r2 | ||
| 45 | add r0, r0, r2 | ||
| 46 | subs r2, r2, #4 | ||
| 47 | blt 8f | ||
| 48 | ands ip, r0, #3 | ||
| 49 | PLD( pld [r1, #-4] ) | ||
| 50 | bne 9f | ||
| 51 | ands ip, r1, #3 | ||
| 52 | bne 10f | ||
| 53 | |||
| 54 | 1: subs r2, r2, #(28) | ||
| 55 | stmfd sp!, {r5 - r8} | ||
| 56 | blt 5f | ||
| 57 | |||
| 58 | CALGN( ands ip, r1, #31 ) | ||
| 59 | CALGN( sbcnes r4, ip, r2 ) @ C is always set here | ||
| 60 | CALGN( bcs 2f ) | ||
| 61 | CALGN( adr r4, 6f ) | ||
| 62 | CALGN( subs r2, r2, ip ) @ C is set here | ||
| 63 | CALGN( add pc, r4, ip ) | ||
| 64 | |||
| 65 | PLD( pld [r1, #-4] ) | ||
| 66 | 2: PLD( subs r2, r2, #96 ) | ||
| 67 | PLD( pld [r1, #-32] ) | ||
| 68 | PLD( blt 4f ) | ||
| 69 | PLD( pld [r1, #-64] ) | ||
| 70 | PLD( pld [r1, #-96] ) | ||
| 71 | |||
| 72 | 3: PLD( pld [r1, #-128] ) | ||
| 73 | 4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr} | ||
| 74 | subs r2, r2, #32 | ||
| 75 | stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr} | ||
| 76 | bge 3b | ||
| 77 | PLD( cmn r2, #96 ) | ||
| 78 | PLD( bge 4b ) | ||
| 79 | |||
| 80 | 5: ands ip, r2, #28 | ||
| 81 | rsb ip, ip, #32 | ||
| 82 | addne pc, pc, ip @ C is always clear here | ||
| 83 | b 7f | ||
| 84 | 6: nop | ||
| 85 | ldr r3, [r1, #-4]! | ||
| 86 | ldr r4, [r1, #-4]! | ||
| 87 | ldr r5, [r1, #-4]! | ||
| 88 | ldr r6, [r1, #-4]! | ||
| 89 | ldr r7, [r1, #-4]! | ||
| 90 | ldr r8, [r1, #-4]! | ||
| 91 | ldr lr, [r1, #-4]! | ||
| 92 | |||
| 93 | add pc, pc, ip | ||
| 94 | nop | ||
| 95 | nop | ||
| 96 | str r3, [r0, #-4]! | ||
| 97 | str r4, [r0, #-4]! | ||
| 98 | str r5, [r0, #-4]! | ||
| 99 | str r6, [r0, #-4]! | ||
| 100 | str r7, [r0, #-4]! | ||
| 101 | str r8, [r0, #-4]! | ||
| 102 | str lr, [r0, #-4]! | ||
| 103 | |||
| 104 | CALGN( bcs 2b ) | ||
| 105 | |||
| 106 | 7: ldmfd sp!, {r5 - r8} | ||
| 107 | |||
| 108 | 8: movs r2, r2, lsl #31 | ||
| 109 | ldrneb r3, [r1, #-1]! | ||
| 110 | ldrcsb r4, [r1, #-1]! | ||
| 111 | ldrcsb ip, [r1, #-1] | ||
| 112 | strneb r3, [r0, #-1]! | ||
| 113 | strcsb r4, [r0, #-1]! | ||
| 114 | strcsb ip, [r0, #-1] | ||
| 115 | ldmfd sp!, {r0, r4, pc} | ||
| 116 | |||
| 117 | 9: cmp ip, #2 | ||
| 118 | ldrgtb r3, [r1, #-1]! | ||
| 119 | ldrgeb r4, [r1, #-1]! | ||
| 120 | ldrb lr, [r1, #-1]! | ||
| 121 | strgtb r3, [r0, #-1]! | ||
| 122 | strgeb r4, [r0, #-1]! | ||
| 123 | subs r2, r2, ip | ||
| 124 | strb lr, [r0, #-1]! | ||
| 125 | blt 8b | ||
| 126 | ands ip, r1, #3 | ||
| 127 | beq 1b | ||
| 128 | |||
| 129 | 10: bic r1, r1, #3 | ||
| 130 | cmp ip, #2 | ||
| 131 | ldr r3, [r1, #0] | ||
| 132 | beq 17f | ||
| 133 | blt 18f | ||
| 134 | |||
| 135 | |||
| 136 | .macro backward_copy_shift push pull | ||
| 137 | |||
| 138 | subs r2, r2, #28 | ||
| 139 | blt 14f | ||
| 140 | |||
| 141 | CALGN( ands ip, r1, #31 ) | ||
| 142 | CALGN( rsb ip, ip, #32 ) | ||
| 143 | CALGN( sbcnes r4, ip, r2 ) @ C is always set here | ||
| 144 | CALGN( subcc r2, r2, ip ) | ||
| 145 | CALGN( bcc 15f ) | ||
| 146 | |||
| 147 | 11: stmfd sp!, {r5 - r9} | ||
| 148 | |||
| 149 | PLD( pld [r1, #-4] ) | ||
| 150 | PLD( subs r2, r2, #96 ) | ||
| 151 | PLD( pld [r1, #-32] ) | ||
| 152 | PLD( blt 13f ) | ||
| 153 | PLD( pld [r1, #-64] ) | ||
| 154 | PLD( pld [r1, #-96] ) | ||
| 155 | |||
| 156 | 12: PLD( pld [r1, #-128] ) | ||
| 157 | 13: ldmdb r1!, {r7, r8, r9, ip} | ||
| 158 | mov lr, r3, push #\push | ||
| 159 | subs r2, r2, #32 | ||
| 160 | ldmdb r1!, {r3, r4, r5, r6} | ||
| 161 | orr lr, lr, ip, pull #\pull | ||
| 162 | mov ip, ip, push #\push | ||
| 163 | orr ip, ip, r9, pull #\pull | ||
| 164 | mov r9, r9, push #\push | ||
| 165 | orr r9, r9, r8, pull #\pull | ||
| 166 | mov r8, r8, push #\push | ||
| 167 | orr r8, r8, r7, pull #\pull | ||
| 168 | mov r7, r7, push #\push | ||
| 169 | orr r7, r7, r6, pull #\pull | ||
| 170 | mov r6, r6, push #\push | ||
| 171 | orr r6, r6, r5, pull #\pull | ||
| 172 | mov r5, r5, push #\push | ||
| 173 | orr r5, r5, r4, pull #\pull | ||
| 174 | mov r4, r4, push #\push | ||
| 175 | orr r4, r4, r3, pull #\pull | ||
| 176 | stmdb r0!, {r4 - r9, ip, lr} | ||
| 177 | bge 12b | ||
| 178 | PLD( cmn r2, #96 ) | ||
| 179 | PLD( bge 13b ) | ||
| 180 | |||
| 181 | ldmfd sp!, {r5 - r9} | ||
| 182 | |||
| 183 | 14: ands ip, r2, #28 | ||
| 184 | beq 16f | ||
| 185 | |||
| 186 | 15: mov lr, r3, push #\push | ||
| 187 | ldr r3, [r1, #-4]! | ||
| 188 | subs ip, ip, #4 | ||
| 189 | orr lr, lr, r3, pull #\pull | ||
| 190 | str lr, [r0, #-4]! | ||
| 191 | bgt 15b | ||
| 192 | CALGN( cmp r2, #0 ) | ||
| 193 | CALGN( bge 11b ) | ||
| 194 | |||
| 195 | 16: add r1, r1, #(\pull / 8) | ||
| 196 | b 8b | ||
| 197 | |||
| 198 | .endm | ||
| 199 | |||
| 200 | |||
| 201 | backward_copy_shift push=8 pull=24 | ||
| 202 | |||
| 203 | 17: backward_copy_shift push=16 pull=16 | ||
| 204 | |||
| 205 | 18: backward_copy_shift push=24 pull=8 | ||
| 206 | |||
diff --git a/arch/arm/lib/uaccess.S b/arch/arm/lib/uaccess.S index d3ed0636c008..c28449157bea 100644 --- a/arch/arm/lib/uaccess.S +++ b/arch/arm/lib/uaccess.S | |||
| @@ -657,41 +657,3 @@ USER( ldrgtbt r3, [r1], #1) @ May fault | |||
| 657 | LOADREGS(fd,sp!, {r4 - r7, pc}) | 657 | LOADREGS(fd,sp!, {r4 - r7, pc}) |
| 658 | .previous | 658 | .previous |
| 659 | 659 | ||
| 660 | /* Prototype: int __arch_clear_user(void *addr, size_t sz) | ||
| 661 | * Purpose : clear some user memory | ||
| 662 | * Params : addr - user memory address to clear | ||
| 663 | * : sz - number of bytes to clear | ||
| 664 | * Returns : number of bytes NOT cleared | ||
| 665 | */ | ||
| 666 | ENTRY(__arch_clear_user) | ||
| 667 | stmfd sp!, {r1, lr} | ||
| 668 | mov r2, #0 | ||
| 669 | cmp r1, #4 | ||
| 670 | blt 2f | ||
| 671 | ands ip, r0, #3 | ||
| 672 | beq 1f | ||
| 673 | cmp ip, #2 | ||
| 674 | USER( strbt r2, [r0], #1) | ||
| 675 | USER( strlebt r2, [r0], #1) | ||
| 676 | USER( strltbt r2, [r0], #1) | ||
| 677 | rsb ip, ip, #4 | ||
| 678 | sub r1, r1, ip @ 7 6 5 4 3 2 1 | ||
| 679 | 1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 | ||
| 680 | USER( strplt r2, [r0], #4) | ||
| 681 | USER( strplt r2, [r0], #4) | ||
| 682 | bpl 1b | ||
| 683 | adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 | ||
| 684 | USER( strplt r2, [r0], #4) | ||
| 685 | 2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x | ||
| 686 | USER( strnebt r2, [r0], #1) | ||
| 687 | USER( strnebt r2, [r0], #1) | ||
| 688 | tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 | ||
| 689 | USER( strnebt r2, [r0], #1) | ||
| 690 | mov r0, #0 | ||
| 691 | LOADREGS(fd,sp!, {r1, pc}) | ||
| 692 | |||
| 693 | .section .fixup,"ax" | ||
| 694 | .align 0 | ||
| 695 | 9001: LOADREGS(fd,sp!, {r0, pc}) | ||
| 696 | .previous | ||
| 697 | |||
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c index 15261646dcdd..ed4614983adb 100644 --- a/arch/arm/mach-ebsa110/core.c +++ b/arch/arm/mach-ebsa110/core.c | |||
| @@ -251,9 +251,33 @@ static struct platform_device serial_device = { | |||
| 251 | }, | 251 | }, |
| 252 | }; | 252 | }; |
| 253 | 253 | ||
| 254 | static struct resource am79c961_resources[] = { | ||
| 255 | { | ||
| 256 | .start = 0x220, | ||
| 257 | .end = 0x238, | ||
| 258 | .flags = IORESOURCE_IO, | ||
| 259 | }, { | ||
| 260 | .start = IRQ_EBSA110_ETHERNET, | ||
| 261 | .end = IRQ_EBSA110_ETHERNET, | ||
| 262 | .flags = IORESOURCE_IRQ, | ||
| 263 | }, | ||
| 264 | }; | ||
| 265 | |||
| 266 | static struct platform_device am79c961_device = { | ||
| 267 | .name = "am79c961", | ||
| 268 | .id = -1, | ||
| 269 | .num_resources = ARRAY_SIZE(am79c961_resources), | ||
| 270 | .resource = am79c961_resources, | ||
| 271 | }; | ||
| 272 | |||
| 273 | static struct platform_device *ebsa110_devices[] = { | ||
| 274 | &serial_device, | ||
| 275 | &am79c961_device, | ||
| 276 | }; | ||
| 277 | |||
| 254 | static int __init ebsa110_init(void) | 278 | static int __init ebsa110_init(void) |
| 255 | { | 279 | { |
| 256 | return platform_device_register(&serial_device); | 280 | return platform_add_devices(ebsa110_devices, ARRAY_SIZE(ebsa110_devices)); |
| 257 | } | 281 | } |
| 258 | 282 | ||
| 259 | arch_initcall(ebsa110_init); | 283 | arch_initcall(ebsa110_init); |
diff --git a/arch/arm/mach-ixp2000/Makefile b/arch/arm/mach-ixp2000/Makefile index 1e6139d42a92..9621aeb61f46 100644 --- a/arch/arm/mach-ixp2000/Makefile +++ b/arch/arm/mach-ixp2000/Makefile | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | # | 1 | # |
| 2 | # Makefile for the linux kernel. | 2 | # Makefile for the linux kernel. |
| 3 | # | 3 | # |
| 4 | obj-y := core.o pci.o | 4 | obj-y := core.o pci.o uengine.o |
| 5 | obj-m := | 5 | obj-m := |
| 6 | obj-n := | 6 | obj-n := |
| 7 | obj- := | 7 | obj- := |
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c index 01c393c504d0..c93a98b2a32c 100644 --- a/arch/arm/mach-ixp2000/core.c +++ b/arch/arm/mach-ixp2000/core.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * arch/arm/mach-ixp2000/common.c | 2 | * arch/arm/mach-ixp2000/core.c |
| 3 | * | 3 | * |
| 4 | * Common routines used by all IXP2400/2800 based platforms. | 4 | * Common routines used by all IXP2400/2800 based platforms. |
| 5 | * | 5 | * |
| @@ -49,7 +49,6 @@ static unsigned long ixp2000_slowport_irq_flags; | |||
| 49 | *************************************************************************/ | 49 | *************************************************************************/ |
| 50 | void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg) | 50 | void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg *old_cfg) |
| 51 | { | 51 | { |
| 52 | |||
| 53 | spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags); | 52 | spin_lock_irqsave(&ixp2000_slowport_lock, ixp2000_slowport_irq_flags); |
| 54 | 53 | ||
| 55 | old_cfg->CCR = *IXP2000_SLOWPORT_CCR; | 54 | old_cfg->CCR = *IXP2000_SLOWPORT_CCR; |
| @@ -62,7 +61,7 @@ void ixp2000_acquire_slowport(struct slowport_cfg *new_cfg, struct slowport_cfg | |||
| 62 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC); | 61 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, new_cfg->WTC); |
| 63 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC); | 62 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, new_cfg->RTC); |
| 64 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR); | 63 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, new_cfg->PCR); |
| 65 | ixp2000_reg_write(IXP2000_SLOWPORT_ADC, new_cfg->ADC); | 64 | ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, new_cfg->ADC); |
| 66 | } | 65 | } |
| 67 | 66 | ||
| 68 | void ixp2000_release_slowport(struct slowport_cfg *old_cfg) | 67 | void ixp2000_release_slowport(struct slowport_cfg *old_cfg) |
| @@ -71,7 +70,7 @@ void ixp2000_release_slowport(struct slowport_cfg *old_cfg) | |||
| 71 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC); | 70 | ixp2000_reg_write(IXP2000_SLOWPORT_WTC2, old_cfg->WTC); |
| 72 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC); | 71 | ixp2000_reg_write(IXP2000_SLOWPORT_RTC2, old_cfg->RTC); |
| 73 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR); | 72 | ixp2000_reg_write(IXP2000_SLOWPORT_PCR, old_cfg->PCR); |
| 74 | ixp2000_reg_write(IXP2000_SLOWPORT_ADC, old_cfg->ADC); | 73 | ixp2000_reg_wrb(IXP2000_SLOWPORT_ADC, old_cfg->ADC); |
| 75 | 74 | ||
| 76 | spin_unlock_irqrestore(&ixp2000_slowport_lock, | 75 | spin_unlock_irqrestore(&ixp2000_slowport_lock, |
| 77 | ixp2000_slowport_irq_flags); | 76 | ixp2000_slowport_irq_flags); |
| @@ -145,7 +144,7 @@ void __init ixp2000_map_io(void) | |||
| 145 | iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); | 144 | iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc)); |
| 146 | 145 | ||
| 147 | /* Set slowport to 8-bit mode. */ | 146 | /* Set slowport to 8-bit mode. */ |
| 148 | ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1); | 147 | ixp2000_reg_wrb(IXP2000_SLOWPORT_FRM, 1); |
| 149 | } | 148 | } |
| 150 | 149 | ||
| 151 | 150 | ||
| @@ -209,7 +208,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
| 209 | write_seqlock(&xtime_lock); | 208 | write_seqlock(&xtime_lock); |
| 210 | 209 | ||
| 211 | /* clear timer 1 */ | 210 | /* clear timer 1 */ |
| 212 | ixp2000_reg_write(IXP2000_T1_CLR, 1); | 211 | ixp2000_reg_wrb(IXP2000_T1_CLR, 1); |
| 213 | 212 | ||
| 214 | while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { | 213 | while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) { |
| 215 | timer_tick(regs); | 214 | timer_tick(regs); |
| @@ -252,12 +251,12 @@ void __init ixp2000_init_time(unsigned long tick_rate) | |||
| 252 | 251 | ||
| 253 | ixp2000_reg_write(IXP2000_T4_CLR, 0); | 252 | ixp2000_reg_write(IXP2000_T4_CLR, 0); |
| 254 | ixp2000_reg_write(IXP2000_T4_CLD, -1); | 253 | ixp2000_reg_write(IXP2000_T4_CLD, -1); |
| 255 | ixp2000_reg_write(IXP2000_T4_CTL, (1 << 7)); | 254 | ixp2000_reg_wrb(IXP2000_T4_CTL, (1 << 7)); |
| 256 | missing_jiffy_timer_csr = IXP2000_T4_CSR; | 255 | missing_jiffy_timer_csr = IXP2000_T4_CSR; |
| 257 | } else { | 256 | } else { |
| 258 | ixp2000_reg_write(IXP2000_T2_CLR, 0); | 257 | ixp2000_reg_write(IXP2000_T2_CLR, 0); |
| 259 | ixp2000_reg_write(IXP2000_T2_CLD, -1); | 258 | ixp2000_reg_write(IXP2000_T2_CLD, -1); |
| 260 | ixp2000_reg_write(IXP2000_T2_CTL, (1 << 7)); | 259 | ixp2000_reg_wrb(IXP2000_T2_CTL, (1 << 7)); |
| 261 | missing_jiffy_timer_csr = IXP2000_T2_CSR; | 260 | missing_jiffy_timer_csr = IXP2000_T2_CSR; |
| 262 | } | 261 | } |
| 263 | next_jiffy_time = 0xffffffff; | 262 | next_jiffy_time = 0xffffffff; |
| @@ -279,7 +278,7 @@ static void update_gpio_int_csrs(void) | |||
| 279 | ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); | 278 | ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge); |
| 280 | ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); | 279 | ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge); |
| 281 | ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); | 280 | ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low); |
| 282 | ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); | 281 | ixp2000_reg_wrb(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high); |
| 283 | } | 282 | } |
| 284 | 283 | ||
| 285 | void gpio_line_config(int line, int direction) | 284 | void gpio_line_config(int line, int direction) |
| @@ -297,9 +296,9 @@ void gpio_line_config(int line, int direction) | |||
| 297 | GPIO_IRQ_level_high &= ~(1 << line); | 296 | GPIO_IRQ_level_high &= ~(1 << line); |
| 298 | update_gpio_int_csrs(); | 297 | update_gpio_int_csrs(); |
| 299 | 298 | ||
| 300 | ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line); | 299 | ixp2000_reg_wrb(IXP2000_GPIO_PDSR, 1 << line); |
| 301 | } else if (direction == GPIO_IN) { | 300 | } else if (direction == GPIO_IN) { |
| 302 | ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line); | 301 | ixp2000_reg_wrb(IXP2000_GPIO_PDCR, 1 << line); |
| 303 | } | 302 | } |
| 304 | local_irq_restore(flags); | 303 | local_irq_restore(flags); |
| 305 | } | 304 | } |
| @@ -365,12 +364,12 @@ static void ixp2000_GPIO_irq_mask_ack(unsigned int irq) | |||
| 365 | 364 | ||
| 366 | ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 365 | ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 367 | ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 366 | ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 368 | ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); | 367 | ixp2000_reg_wrb(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 369 | } | 368 | } |
| 370 | 369 | ||
| 371 | static void ixp2000_GPIO_irq_mask(unsigned int irq) | 370 | static void ixp2000_GPIO_irq_mask(unsigned int irq) |
| 372 | { | 371 | { |
| 373 | ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); | 372 | ixp2000_reg_wrb(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0))); |
| 374 | } | 373 | } |
| 375 | 374 | ||
| 376 | static void ixp2000_GPIO_irq_unmask(unsigned int irq) | 375 | static void ixp2000_GPIO_irq_unmask(unsigned int irq) |
| @@ -389,9 +388,9 @@ static void ixp2000_pci_irq_mask(unsigned int irq) | |||
| 389 | { | 388 | { |
| 390 | unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE; | 389 | unsigned long temp = *IXP2000_PCI_XSCALE_INT_ENABLE; |
| 391 | if (irq == IRQ_IXP2000_PCIA) | 390 | if (irq == IRQ_IXP2000_PCIA) |
| 392 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26))); | 391 | ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 26))); |
| 393 | else if (irq == IRQ_IXP2000_PCIB) | 392 | else if (irq == IRQ_IXP2000_PCIB) |
| 394 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27))); | 393 | ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, (temp & ~(1 << 27))); |
| 395 | } | 394 | } |
| 396 | 395 | ||
| 397 | static void ixp2000_pci_irq_unmask(unsigned int irq) | 396 | static void ixp2000_pci_irq_unmask(unsigned int irq) |
| @@ -411,7 +410,7 @@ static struct irqchip ixp2000_pci_irq_chip = { | |||
| 411 | 410 | ||
| 412 | static void ixp2000_irq_mask(unsigned int irq) | 411 | static void ixp2000_irq_mask(unsigned int irq) |
| 413 | { | 412 | { |
| 414 | ixp2000_reg_write(IXP2000_IRQ_ENABLE_CLR, (1 << irq)); | 413 | ixp2000_reg_wrb(IXP2000_IRQ_ENABLE_CLR, (1 << irq)); |
| 415 | } | 414 | } |
| 416 | 415 | ||
| 417 | static void ixp2000_irq_unmask(unsigned int irq) | 416 | static void ixp2000_irq_unmask(unsigned int irq) |
| @@ -443,7 +442,7 @@ void __init ixp2000_init_irq(void) | |||
| 443 | ixp2000_reg_write(IXP2000_GPIO_INCR, -1); | 442 | ixp2000_reg_write(IXP2000_GPIO_INCR, -1); |
| 444 | 443 | ||
| 445 | /* clear PCI interrupt sources */ | 444 | /* clear PCI interrupt sources */ |
| 446 | ixp2000_reg_write(IXP2000_PCI_XSCALE_INT_ENABLE, 0); | 445 | ixp2000_reg_wrb(IXP2000_PCI_XSCALE_INT_ENABLE, 0); |
| 447 | 446 | ||
| 448 | /* | 447 | /* |
| 449 | * Certain bits in the IRQ status register of the | 448 | * Certain bits in the IRQ status register of the |
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c index 643f5e1c3d93..7719c478aa84 100644 --- a/arch/arm/mach-ixp2000/enp2611.c +++ b/arch/arm/mach-ixp2000/enp2611.c | |||
| @@ -64,6 +64,35 @@ static struct sys_timer enp2611_timer = { | |||
| 64 | 64 | ||
| 65 | 65 | ||
| 66 | /************************************************************************* | 66 | /************************************************************************* |
| 67 | * ENP-2611 I/O | ||
| 68 | *************************************************************************/ | ||
| 69 | static struct map_desc enp2611_io_desc[] __initdata = { | ||
| 70 | { | ||
| 71 | .virtual = ENP2611_CALEB_VIRT_BASE, | ||
| 72 | .physical = ENP2611_CALEB_PHYS_BASE, | ||
| 73 | .length = ENP2611_CALEB_SIZE, | ||
| 74 | .type = MT_IXP2000_DEVICE | ||
| 75 | }, { | ||
| 76 | .virtual = ENP2611_PM3386_0_VIRT_BASE, | ||
| 77 | .physical = ENP2611_PM3386_0_PHYS_BASE, | ||
| 78 | .length = ENP2611_PM3386_0_SIZE, | ||
| 79 | .type = MT_IXP2000_DEVICE | ||
| 80 | }, { | ||
| 81 | .virtual = ENP2611_PM3386_1_VIRT_BASE, | ||
| 82 | .physical = ENP2611_PM3386_1_PHYS_BASE, | ||
| 83 | .length = ENP2611_PM3386_1_SIZE, | ||
| 84 | .type = MT_IXP2000_DEVICE | ||
| 85 | } | ||
| 86 | }; | ||
| 87 | |||
| 88 | void __init enp2611_map_io(void) | ||
| 89 | { | ||
| 90 | ixp2000_map_io(); | ||
| 91 | iotable_init(enp2611_io_desc, ARRAY_SIZE(enp2611_io_desc)); | ||
| 92 | } | ||
| 93 | |||
| 94 | |||
| 95 | /************************************************************************* | ||
| 67 | * ENP-2611 PCI | 96 | * ENP-2611 PCI |
| 68 | *************************************************************************/ | 97 | *************************************************************************/ |
| 69 | static int enp2611_pci_setup(int nr, struct pci_sys_data *sys) | 98 | static int enp2611_pci_setup(int nr, struct pci_sys_data *sys) |
| @@ -229,7 +258,7 @@ MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board") | |||
| 229 | .phys_io = IXP2000_UART_PHYS_BASE, | 258 | .phys_io = IXP2000_UART_PHYS_BASE, |
| 230 | .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc, | 259 | .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc, |
| 231 | .boot_params = 0x00000100, | 260 | .boot_params = 0x00000100, |
| 232 | .map_io = ixp2000_map_io, | 261 | .map_io = enp2611_map_io, |
| 233 | .init_irq = ixp2000_init_irq, | 262 | .init_irq = ixp2000_init_irq, |
| 234 | .timer = &enp2611_timer, | 263 | .timer = &enp2611_timer, |
| 235 | .init_machine = enp2611_init_machine, | 264 | .init_machine = enp2611_init_machine, |
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c index 05dfcb48c2b6..d628da56b4bc 100644 --- a/arch/arm/mach-ixp2000/ixdp2x00.c +++ b/arch/arm/mach-ixp2000/ixdp2x00.c | |||
| @@ -81,7 +81,7 @@ static void ixdp2x00_irq_mask(unsigned int irq) | |||
| 81 | 81 | ||
| 82 | dummy = *board_irq_mask; | 82 | dummy = *board_irq_mask; |
| 83 | dummy |= IXP2000_BOARD_IRQ_MASK(irq); | 83 | dummy |= IXP2000_BOARD_IRQ_MASK(irq); |
| 84 | ixp2000_reg_write(board_irq_mask, dummy); | 84 | ixp2000_reg_wrb(board_irq_mask, dummy); |
| 85 | 85 | ||
| 86 | #ifdef CONFIG_ARCH_IXDP2400 | 86 | #ifdef CONFIG_ARCH_IXDP2400 |
| 87 | if (machine_is_ixdp2400()) | 87 | if (machine_is_ixdp2400()) |
| @@ -101,7 +101,7 @@ static void ixdp2x00_irq_unmask(unsigned int irq) | |||
| 101 | 101 | ||
| 102 | dummy = *board_irq_mask; | 102 | dummy = *board_irq_mask; |
| 103 | dummy &= ~IXP2000_BOARD_IRQ_MASK(irq); | 103 | dummy &= ~IXP2000_BOARD_IRQ_MASK(irq); |
| 104 | ixp2000_reg_write(board_irq_mask, dummy); | 104 | ixp2000_reg_wrb(board_irq_mask, dummy); |
| 105 | 105 | ||
| 106 | if (machine_is_ixdp2400()) | 106 | if (machine_is_ixdp2400()) |
| 107 | ixp2000_release_slowport(&old_cfg); | 107 | ixp2000_release_slowport(&old_cfg); |
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c index b21249908ae4..e6a882f35da2 100644 --- a/arch/arm/mach-ixp2000/ixdp2x01.c +++ b/arch/arm/mach-ixp2000/ixdp2x01.c | |||
| @@ -51,7 +51,7 @@ | |||
| 51 | *************************************************************************/ | 51 | *************************************************************************/ |
| 52 | static void ixdp2x01_irq_mask(unsigned int irq) | 52 | static void ixdp2x01_irq_mask(unsigned int irq) |
| 53 | { | 53 | { |
| 54 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, | 54 | ixp2000_reg_wrb(IXDP2X01_INT_MASK_SET_REG, |
| 55 | IXP2000_BOARD_IRQ_MASK(irq)); | 55 | IXP2000_BOARD_IRQ_MASK(irq)); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| @@ -114,7 +114,7 @@ void __init ixdp2x01_init_irq(void) | |||
| 114 | 114 | ||
| 115 | /* Mask all interrupts from CPLD, disable simulation */ | 115 | /* Mask all interrupts from CPLD, disable simulation */ |
| 116 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff); | 116 | ixp2000_reg_write(IXDP2X01_INT_MASK_SET_REG, 0xffffffff); |
| 117 | ixp2000_reg_write(IXDP2X01_INT_SIM_REG, 0); | 117 | ixp2000_reg_wrb(IXDP2X01_INT_SIM_REG, 0); |
| 118 | 118 | ||
| 119 | for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) { | 119 | for (irq = NR_IXP2000_IRQS; irq < NR_IXDP2X01_IRQS; irq++) { |
| 120 | if (irq & valid_irq_mask) { | 120 | if (irq & valid_irq_mask) { |
| @@ -299,7 +299,6 @@ struct hw_pci ixdp2x01_pci __initdata = { | |||
| 299 | 299 | ||
| 300 | int __init ixdp2x01_pci_init(void) | 300 | int __init ixdp2x01_pci_init(void) |
| 301 | { | 301 | { |
| 302 | |||
| 303 | pci_common_init(&ixdp2x01_pci); | 302 | pci_common_init(&ixdp2x01_pci); |
| 304 | return 0; | 303 | return 0; |
| 305 | } | 304 | } |
| @@ -316,7 +315,7 @@ static struct flash_platform_data ixdp2x01_flash_platform_data = { | |||
| 316 | 315 | ||
| 317 | static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs) | 316 | static unsigned long ixdp2x01_flash_bank_setup(unsigned long ofs) |
| 318 | { | 317 | { |
| 319 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, | 318 | ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG, |
| 320 | ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN)); | 319 | ((ofs >> IXDP2X01_FLASH_WINDOW_BITS) | IXDP2X01_CPLD_FLASH_INTERN)); |
| 321 | return (ofs & IXDP2X01_FLASH_WINDOW_MASK); | 320 | return (ofs & IXDP2X01_FLASH_WINDOW_MASK); |
| 322 | } | 321 | } |
| @@ -363,7 +362,7 @@ static struct platform_device *ixdp2x01_devices[] __initdata = { | |||
| 363 | 362 | ||
| 364 | static void __init ixdp2x01_init_machine(void) | 363 | static void __init ixdp2x01_init_machine(void) |
| 365 | { | 364 | { |
| 366 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, | 365 | ixp2000_reg_wrb(IXDP2X01_CPLD_FLASH_REG, |
| 367 | (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN)); | 366 | (IXDP2X01_CPLD_FLASH_BANK_MASK | IXDP2X01_CPLD_FLASH_INTERN)); |
| 368 | 367 | ||
| 369 | ixdp2x01_flash_data.nr_banks = | 368 | ixdp2x01_flash_data.nr_banks = |
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c index 522205acb316..d4bf1e1c0031 100644 --- a/arch/arm/mach-ixp2000/pci.c +++ b/arch/arm/mach-ixp2000/pci.c | |||
| @@ -148,7 +148,7 @@ int ixp2000_pci_abort_handler(unsigned long addr, unsigned int fsr, struct pt_re | |||
| 148 | local_irq_save(flags); | 148 | local_irq_save(flags); |
| 149 | temp = *(IXP2000_PCI_CONTROL); | 149 | temp = *(IXP2000_PCI_CONTROL); |
| 150 | if (temp & ((1 << 8) | (1 << 5))) { | 150 | if (temp & ((1 << 8) | (1 << 5))) { |
| 151 | ixp2000_reg_write(IXP2000_PCI_CONTROL, temp); | 151 | ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp); |
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | temp = *(IXP2000_PCI_CMDSTAT); | 154 | temp = *(IXP2000_PCI_CMDSTAT); |
| @@ -178,8 +178,8 @@ clear_master_aborts(void) | |||
| 178 | 178 | ||
| 179 | local_irq_save(flags); | 179 | local_irq_save(flags); |
| 180 | temp = *(IXP2000_PCI_CONTROL); | 180 | temp = *(IXP2000_PCI_CONTROL); |
| 181 | if (temp & ((1 << 8) | (1 << 5))) { | 181 | if (temp & ((1 << 8) | (1 << 5))) { |
| 182 | ixp2000_reg_write(IXP2000_PCI_CONTROL, temp); | 182 | ixp2000_reg_wrb(IXP2000_PCI_CONTROL, temp); |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | temp = *(IXP2000_PCI_CMDSTAT); | 185 | temp = *(IXP2000_PCI_CMDSTAT); |
diff --git a/arch/arm/mach-ixp2000/uengine.c b/arch/arm/mach-ixp2000/uengine.c new file mode 100644 index 000000000000..43e234349d4a --- /dev/null +++ b/arch/arm/mach-ixp2000/uengine.c | |||
| @@ -0,0 +1,474 @@ | |||
| 1 | /* | ||
| 2 | * Generic library functions for the microengines found on the Intel | ||
| 3 | * IXP2000 series of network processors. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org> | ||
| 6 | * Dedicated to Marija Kulikova. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU Lesser General Public License as | ||
| 10 | * published by the Free Software Foundation; either version 2.1 of the | ||
| 11 | * License, or (at your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/config.h> | ||
| 15 | #include <linux/kernel.h> | ||
| 16 | #include <linux/init.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/string.h> | ||
| 20 | #include <asm/hardware.h> | ||
| 21 | #include <asm/arch/ixp2000-regs.h> | ||
| 22 | #include <asm/arch/uengine.h> | ||
| 23 | #include <asm/io.h> | ||
| 24 | |||
| 25 | #define USTORE_ADDRESS 0x000 | ||
| 26 | #define USTORE_DATA_LOWER 0x004 | ||
| 27 | #define USTORE_DATA_UPPER 0x008 | ||
| 28 | #define CTX_ENABLES 0x018 | ||
| 29 | #define CC_ENABLE 0x01c | ||
| 30 | #define CSR_CTX_POINTER 0x020 | ||
| 31 | #define INDIRECT_CTX_STS 0x040 | ||
| 32 | #define ACTIVE_CTX_STS 0x044 | ||
| 33 | #define INDIRECT_CTX_SIG_EVENTS 0x048 | ||
| 34 | #define INDIRECT_CTX_WAKEUP_EVENTS 0x050 | ||
| 35 | #define NN_PUT 0x080 | ||
| 36 | #define NN_GET 0x084 | ||
| 37 | #define TIMESTAMP_LOW 0x0c0 | ||
| 38 | #define TIMESTAMP_HIGH 0x0c4 | ||
| 39 | #define T_INDEX_BYTE_INDEX 0x0f4 | ||
| 40 | #define LOCAL_CSR_STATUS 0x180 | ||
| 41 | |||
| 42 | u32 ixp2000_uengine_mask; | ||
| 43 | |||
| 44 | static void *ixp2000_uengine_csr_area(int uengine) | ||
| 45 | { | ||
| 46 | return ((void *)IXP2000_UENGINE_CSR_VIRT_BASE) + (uengine << 10); | ||
| 47 | } | ||
| 48 | |||
| 49 | /* | ||
| 50 | * LOCAL_CSR_STATUS=1 after a read or write to a microengine's CSR | ||
| 51 | * space means that the microengine we tried to access was also trying | ||
| 52 | * to access its own CSR space on the same clock cycle as we did. When | ||
| 53 | * this happens, we lose the arbitration process by default, and the | ||
| 54 | * read or write we tried to do was not actually performed, so we try | ||
| 55 | * again until it succeeds. | ||
| 56 | */ | ||
| 57 | u32 ixp2000_uengine_csr_read(int uengine, int offset) | ||
| 58 | { | ||
| 59 | void *uebase; | ||
| 60 | u32 *local_csr_status; | ||
| 61 | u32 *reg; | ||
| 62 | u32 value; | ||
| 63 | |||
| 64 | uebase = ixp2000_uengine_csr_area(uengine); | ||
| 65 | |||
| 66 | local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS); | ||
| 67 | reg = (u32 *)(uebase + offset); | ||
| 68 | do { | ||
| 69 | value = ixp2000_reg_read(reg); | ||
| 70 | } while (ixp2000_reg_read(local_csr_status) & 1); | ||
| 71 | |||
| 72 | return value; | ||
| 73 | } | ||
| 74 | EXPORT_SYMBOL(ixp2000_uengine_csr_read); | ||
| 75 | |||
| 76 | void ixp2000_uengine_csr_write(int uengine, int offset, u32 value) | ||
| 77 | { | ||
| 78 | void *uebase; | ||
| 79 | u32 *local_csr_status; | ||
| 80 | u32 *reg; | ||
| 81 | |||
| 82 | uebase = ixp2000_uengine_csr_area(uengine); | ||
| 83 | |||
| 84 | local_csr_status = (u32 *)(uebase + LOCAL_CSR_STATUS); | ||
| 85 | reg = (u32 *)(uebase + offset); | ||
| 86 | do { | ||
| 87 | ixp2000_reg_write(reg, value); | ||
| 88 | } while (ixp2000_reg_read(local_csr_status) & 1); | ||
| 89 | } | ||
| 90 | EXPORT_SYMBOL(ixp2000_uengine_csr_write); | ||
| 91 | |||
| 92 | void ixp2000_uengine_reset(u32 uengine_mask) | ||
| 93 | { | ||
| 94 | ixp2000_reg_write(IXP2000_RESET1, uengine_mask & ixp2000_uengine_mask); | ||
| 95 | ixp2000_reg_write(IXP2000_RESET1, 0); | ||
| 96 | } | ||
| 97 | EXPORT_SYMBOL(ixp2000_uengine_reset); | ||
| 98 | |||
| 99 | void ixp2000_uengine_set_mode(int uengine, u32 mode) | ||
| 100 | { | ||
| 101 | /* | ||
| 102 | * CTL_STR_PAR_EN: unconditionally enable parity checking on | ||
| 103 | * control store. | ||
| 104 | */ | ||
| 105 | mode |= 0x10000000; | ||
| 106 | ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mode); | ||
| 107 | |||
| 108 | /* | ||
| 109 | * Enable updating of condition codes. | ||
| 110 | */ | ||
| 111 | ixp2000_uengine_csr_write(uengine, CC_ENABLE, 0x00002000); | ||
| 112 | |||
| 113 | /* | ||
| 114 | * Initialise other per-microengine registers. | ||
| 115 | */ | ||
| 116 | ixp2000_uengine_csr_write(uengine, NN_PUT, 0x00); | ||
| 117 | ixp2000_uengine_csr_write(uengine, NN_GET, 0x00); | ||
| 118 | ixp2000_uengine_csr_write(uengine, T_INDEX_BYTE_INDEX, 0); | ||
| 119 | } | ||
| 120 | EXPORT_SYMBOL(ixp2000_uengine_set_mode); | ||
| 121 | |||
| 122 | static int make_even_parity(u32 x) | ||
| 123 | { | ||
| 124 | return hweight32(x) & 1; | ||
| 125 | } | ||
| 126 | |||
| 127 | static void ustore_write(int uengine, u64 insn) | ||
| 128 | { | ||
| 129 | /* | ||
| 130 | * Generate even parity for top and bottom 20 bits. | ||
| 131 | */ | ||
| 132 | insn |= (u64)make_even_parity((insn >> 20) & 0x000fffff) << 41; | ||
| 133 | insn |= (u64)make_even_parity(insn & 0x000fffff) << 40; | ||
| 134 | |||
| 135 | /* | ||
| 136 | * Write to microstore. The second write auto-increments | ||
| 137 | * the USTORE_ADDRESS index register. | ||
| 138 | */ | ||
| 139 | ixp2000_uengine_csr_write(uengine, USTORE_DATA_LOWER, (u32)insn); | ||
| 140 | ixp2000_uengine_csr_write(uengine, USTORE_DATA_UPPER, (u32)(insn >> 32)); | ||
| 141 | } | ||
| 142 | |||
| 143 | void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns) | ||
| 144 | { | ||
| 145 | int i; | ||
| 146 | |||
| 147 | /* | ||
| 148 | * Start writing to microstore at address 0. | ||
| 149 | */ | ||
| 150 | ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x80000000); | ||
| 151 | for (i = 0; i < insns; i++) { | ||
| 152 | u64 insn; | ||
| 153 | |||
| 154 | insn = (((u64)ucode[0]) << 32) | | ||
| 155 | (((u64)ucode[1]) << 24) | | ||
| 156 | (((u64)ucode[2]) << 16) | | ||
| 157 | (((u64)ucode[3]) << 8) | | ||
| 158 | ((u64)ucode[4]); | ||
| 159 | ucode += 5; | ||
| 160 | |||
| 161 | ustore_write(uengine, insn); | ||
| 162 | } | ||
| 163 | |||
| 164 | /* | ||
| 165 | * Pad with a few NOPs at the end (to avoid the microengine | ||
| 166 | * aborting as it prefetches beyond the last instruction), unless | ||
| 167 | * we run off the end of the instruction store first, at which | ||
| 168 | * point the address register will wrap back to zero. | ||
| 169 | */ | ||
| 170 | for (i = 0; i < 4; i++) { | ||
| 171 | u32 addr; | ||
| 172 | |||
| 173 | addr = ixp2000_uengine_csr_read(uengine, USTORE_ADDRESS); | ||
| 174 | if (addr == 0x80000000) | ||
| 175 | break; | ||
| 176 | ustore_write(uengine, 0xf0000c0300ULL); | ||
| 177 | } | ||
| 178 | |||
| 179 | /* | ||
| 180 | * End programming. | ||
| 181 | */ | ||
| 182 | ixp2000_uengine_csr_write(uengine, USTORE_ADDRESS, 0x00000000); | ||
| 183 | } | ||
| 184 | EXPORT_SYMBOL(ixp2000_uengine_load_microcode); | ||
| 185 | |||
| 186 | void ixp2000_uengine_init_context(int uengine, int context, int pc) | ||
| 187 | { | ||
| 188 | /* | ||
| 189 | * Select the right context for indirect access. | ||
| 190 | */ | ||
| 191 | ixp2000_uengine_csr_write(uengine, CSR_CTX_POINTER, context); | ||
| 192 | |||
| 193 | /* | ||
| 194 | * Initialise signal masks to immediately go to Ready state. | ||
| 195 | */ | ||
| 196 | ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_SIG_EVENTS, 1); | ||
| 197 | ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_WAKEUP_EVENTS, 1); | ||
| 198 | |||
| 199 | /* | ||
| 200 | * Set program counter. | ||
| 201 | */ | ||
| 202 | ixp2000_uengine_csr_write(uengine, INDIRECT_CTX_STS, pc); | ||
| 203 | } | ||
| 204 | EXPORT_SYMBOL(ixp2000_uengine_init_context); | ||
| 205 | |||
| 206 | void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask) | ||
| 207 | { | ||
| 208 | u32 mask; | ||
| 209 | |||
| 210 | /* | ||
| 211 | * Enable the specified context to go to Executing state. | ||
| 212 | */ | ||
| 213 | mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES); | ||
| 214 | mask |= ctx_mask << 8; | ||
| 215 | ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask); | ||
| 216 | } | ||
| 217 | EXPORT_SYMBOL(ixp2000_uengine_start_contexts); | ||
| 218 | |||
| 219 | void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask) | ||
| 220 | { | ||
| 221 | u32 mask; | ||
| 222 | |||
| 223 | /* | ||
| 224 | * Disable the Ready->Executing transition. Note that this | ||
| 225 | * does not stop the context until it voluntarily yields. | ||
| 226 | */ | ||
| 227 | mask = ixp2000_uengine_csr_read(uengine, CTX_ENABLES); | ||
| 228 | mask &= ~(ctx_mask << 8); | ||
| 229 | ixp2000_uengine_csr_write(uengine, CTX_ENABLES, mask); | ||
| 230 | } | ||
| 231 | EXPORT_SYMBOL(ixp2000_uengine_stop_contexts); | ||
| 232 | |||
| 233 | static int check_ixp_type(struct ixp2000_uengine_code *c) | ||
| 234 | { | ||
| 235 | u32 product_id; | ||
| 236 | u32 rev; | ||
| 237 | |||
| 238 | product_id = ixp2000_reg_read(IXP2000_PRODUCT_ID); | ||
| 239 | if (((product_id >> 16) & 0x1f) != 0) | ||
| 240 | return 0; | ||
| 241 | |||
| 242 | switch ((product_id >> 8) & 0xff) { | ||
| 243 | case 0: /* IXP2800 */ | ||
| 244 | if (!(c->cpu_model_bitmask & 4)) | ||
| 245 | return 0; | ||
| 246 | break; | ||
| 247 | |||
| 248 | case 1: /* IXP2850 */ | ||
| 249 | if (!(c->cpu_model_bitmask & 8)) | ||
| 250 | return 0; | ||
| 251 | break; | ||
| 252 | |||
| 253 | case 2: /* IXP2400 */ | ||
| 254 | if (!(c->cpu_model_bitmask & 2)) | ||
| 255 | return 0; | ||
| 256 | break; | ||
| 257 | |||
| 258 | default: | ||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | rev = product_id & 0xff; | ||
| 263 | if (rev < c->cpu_min_revision || rev > c->cpu_max_revision) | ||
| 264 | return 0; | ||
| 265 | |||
| 266 | return 1; | ||
| 267 | } | ||
| 268 | |||
| 269 | static void generate_ucode(u8 *ucode, u32 *gpr_a, u32 *gpr_b) | ||
| 270 | { | ||
| 271 | int offset; | ||
| 272 | int i; | ||
| 273 | |||
| 274 | offset = 0; | ||
| 275 | |||
| 276 | for (i = 0; i < 128; i++) { | ||
| 277 | u8 b3; | ||
| 278 | u8 b2; | ||
| 279 | u8 b1; | ||
| 280 | u8 b0; | ||
| 281 | |||
| 282 | b3 = (gpr_a[i] >> 24) & 0xff; | ||
| 283 | b2 = (gpr_a[i] >> 16) & 0xff; | ||
| 284 | b1 = (gpr_a[i] >> 8) & 0xff; | ||
| 285 | b0 = gpr_a[i] & 0xff; | ||
| 286 | |||
| 287 | // immed[@ai, (b1 << 8) | b0] | ||
| 288 | // 11110000 0000VVVV VVVV11VV VVVVVV00 1IIIIIII | ||
| 289 | ucode[offset++] = 0xf0; | ||
| 290 | ucode[offset++] = (b1 >> 4); | ||
| 291 | ucode[offset++] = (b1 << 4) | 0x0c | (b0 >> 6); | ||
| 292 | ucode[offset++] = (b0 << 2); | ||
| 293 | ucode[offset++] = 0x80 | i; | ||
| 294 | |||
| 295 | // immed_w1[@ai, (b3 << 8) | b2] | ||
| 296 | // 11110100 0100VVVV VVVV11VV VVVVVV00 1IIIIIII | ||
| 297 | ucode[offset++] = 0xf4; | ||
| 298 | ucode[offset++] = 0x40 | (b3 >> 4); | ||
| 299 | ucode[offset++] = (b3 << 4) | 0x0c | (b2 >> 6); | ||
| 300 | ucode[offset++] = (b2 << 2); | ||
| 301 | ucode[offset++] = 0x80 | i; | ||
| 302 | } | ||
| 303 | |||
| 304 | for (i = 0; i < 128; i++) { | ||
| 305 | u8 b3; | ||
| 306 | u8 b2; | ||
| 307 | u8 b1; | ||
| 308 | u8 b0; | ||
| 309 | |||
| 310 | b3 = (gpr_b[i] >> 24) & 0xff; | ||
| 311 | b2 = (gpr_b[i] >> 16) & 0xff; | ||
| 312 | b1 = (gpr_b[i] >> 8) & 0xff; | ||
| 313 | b0 = gpr_b[i] & 0xff; | ||
| 314 | |||
| 315 | // immed[@bi, (b1 << 8) | b0] | ||
| 316 | // 11110000 0000VVVV VVVV001I IIIIII11 VVVVVVVV | ||
| 317 | ucode[offset++] = 0xf0; | ||
| 318 | ucode[offset++] = (b1 >> 4); | ||
| 319 | ucode[offset++] = (b1 << 4) | 0x02 | (i >> 6); | ||
| 320 | ucode[offset++] = (i << 2) | 0x03; | ||
| 321 | ucode[offset++] = b0; | ||
| 322 | |||
| 323 | // immed_w1[@bi, (b3 << 8) | b2] | ||
| 324 | // 11110100 0100VVVV VVVV001I IIIIII11 VVVVVVVV | ||
| 325 | ucode[offset++] = 0xf4; | ||
| 326 | ucode[offset++] = 0x40 | (b3 >> 4); | ||
| 327 | ucode[offset++] = (b3 << 4) | 0x02 | (i >> 6); | ||
| 328 | ucode[offset++] = (i << 2) | 0x03; | ||
| 329 | ucode[offset++] = b2; | ||
| 330 | } | ||
| 331 | |||
| 332 | // ctx_arb[kill] | ||
| 333 | ucode[offset++] = 0xe0; | ||
| 334 | ucode[offset++] = 0x00; | ||
| 335 | ucode[offset++] = 0x01; | ||
| 336 | ucode[offset++] = 0x00; | ||
| 337 | ucode[offset++] = 0x00; | ||
| 338 | } | ||
| 339 | |||
| 340 | static int set_initial_registers(int uengine, struct ixp2000_uengine_code *c) | ||
| 341 | { | ||
| 342 | int per_ctx_regs; | ||
| 343 | u32 *gpr_a; | ||
| 344 | u32 *gpr_b; | ||
| 345 | u8 *ucode; | ||
| 346 | int i; | ||
| 347 | |||
| 348 | gpr_a = kmalloc(128 * sizeof(u32), GFP_KERNEL); | ||
| 349 | gpr_b = kmalloc(128 * sizeof(u32), GFP_KERNEL); | ||
| 350 | ucode = kmalloc(513 * 5, GFP_KERNEL); | ||
| 351 | if (gpr_a == NULL || gpr_b == NULL || ucode == NULL) { | ||
| 352 | kfree(ucode); | ||
| 353 | kfree(gpr_b); | ||
| 354 | kfree(gpr_a); | ||
| 355 | return 1; | ||
| 356 | } | ||
| 357 | |||
| 358 | per_ctx_regs = 16; | ||
| 359 | if (c->uengine_parameters & IXP2000_UENGINE_4_CONTEXTS) | ||
| 360 | per_ctx_regs = 32; | ||
| 361 | |||
| 362 | memset(gpr_a, 0, sizeof(gpr_a)); | ||
| 363 | memset(gpr_b, 0, sizeof(gpr_b)); | ||
| 364 | for (i = 0; i < 256; i++) { | ||
| 365 | struct ixp2000_reg_value *r = c->initial_reg_values + i; | ||
| 366 | u32 *bank; | ||
| 367 | int inc; | ||
| 368 | int j; | ||
| 369 | |||
| 370 | if (r->reg == -1) | ||
| 371 | break; | ||
| 372 | |||
| 373 | bank = (r->reg & 0x400) ? gpr_b : gpr_a; | ||
| 374 | inc = (r->reg & 0x80) ? 128 : per_ctx_regs; | ||
| 375 | |||
| 376 | j = r->reg & 0x7f; | ||
| 377 | while (j < 128) { | ||
| 378 | bank[j] = r->value; | ||
| 379 | j += inc; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | generate_ucode(ucode, gpr_a, gpr_b); | ||
| 384 | ixp2000_uengine_load_microcode(uengine, ucode, 513); | ||
| 385 | ixp2000_uengine_init_context(uengine, 0, 0); | ||
| 386 | ixp2000_uengine_start_contexts(uengine, 0x01); | ||
| 387 | for (i = 0; i < 100; i++) { | ||
| 388 | u32 status; | ||
| 389 | |||
| 390 | status = ixp2000_uengine_csr_read(uengine, ACTIVE_CTX_STS); | ||
| 391 | if (!(status & 0x80000000)) | ||
| 392 | break; | ||
| 393 | } | ||
| 394 | ixp2000_uengine_stop_contexts(uengine, 0x01); | ||
| 395 | |||
| 396 | kfree(ucode); | ||
| 397 | kfree(gpr_b); | ||
| 398 | kfree(gpr_a); | ||
| 399 | |||
| 400 | return !!(i == 100); | ||
| 401 | } | ||
| 402 | |||
| 403 | int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c) | ||
| 404 | { | ||
| 405 | int ctx; | ||
| 406 | |||
| 407 | if (!check_ixp_type(c)) | ||
| 408 | return 1; | ||
| 409 | |||
| 410 | if (!(ixp2000_uengine_mask & (1 << uengine))) | ||
| 411 | return 1; | ||
| 412 | |||
| 413 | ixp2000_uengine_reset(1 << uengine); | ||
| 414 | ixp2000_uengine_set_mode(uengine, c->uengine_parameters); | ||
| 415 | if (set_initial_registers(uengine, c)) | ||
| 416 | return 1; | ||
| 417 | ixp2000_uengine_load_microcode(uengine, c->insns, c->num_insns); | ||
| 418 | |||
| 419 | for (ctx = 0; ctx < 8; ctx++) | ||
| 420 | ixp2000_uengine_init_context(uengine, ctx, 0); | ||
| 421 | |||
| 422 | return 0; | ||
| 423 | } | ||
| 424 | EXPORT_SYMBOL(ixp2000_uengine_load); | ||
| 425 | |||
| 426 | |||
| 427 | static int __init ixp2000_uengine_init(void) | ||
| 428 | { | ||
| 429 | int uengine; | ||
| 430 | u32 value; | ||
| 431 | |||
| 432 | /* | ||
| 433 | * Determine number of microengines present. | ||
| 434 | */ | ||
| 435 | switch ((ixp2000_reg_read(IXP2000_PRODUCT_ID) >> 8) & 0x1fff) { | ||
| 436 | case 0: /* IXP2800 */ | ||
| 437 | case 1: /* IXP2850 */ | ||
| 438 | ixp2000_uengine_mask = 0x00ff00ff; | ||
| 439 | break; | ||
| 440 | |||
| 441 | case 2: /* IXP2400 */ | ||
| 442 | ixp2000_uengine_mask = 0x000f000f; | ||
| 443 | break; | ||
| 444 | |||
| 445 | default: | ||
| 446 | printk(KERN_INFO "Detected unknown IXP2000 model (%.8x)\n", | ||
| 447 | (unsigned int)ixp2000_reg_read(IXP2000_PRODUCT_ID)); | ||
| 448 | ixp2000_uengine_mask = 0x00000000; | ||
| 449 | break; | ||
| 450 | } | ||
| 451 | |||
| 452 | /* | ||
| 453 | * Reset microengines. | ||
| 454 | */ | ||
| 455 | ixp2000_reg_write(IXP2000_RESET1, ixp2000_uengine_mask); | ||
| 456 | ixp2000_reg_write(IXP2000_RESET1, 0); | ||
| 457 | |||
| 458 | /* | ||
| 459 | * Synchronise timestamp counters across all microengines. | ||
| 460 | */ | ||
| 461 | value = ixp2000_reg_read(IXP2000_MISC_CONTROL); | ||
| 462 | ixp2000_reg_write(IXP2000_MISC_CONTROL, value & ~0x80); | ||
| 463 | for (uengine = 0; uengine < 32; uengine++) { | ||
| 464 | if (ixp2000_uengine_mask & (1 << uengine)) { | ||
| 465 | ixp2000_uengine_csr_write(uengine, TIMESTAMP_LOW, 0); | ||
| 466 | ixp2000_uengine_csr_write(uengine, TIMESTAMP_HIGH, 0); | ||
| 467 | } | ||
| 468 | } | ||
| 469 | ixp2000_reg_write(IXP2000_MISC_CONTROL, value | 0x80); | ||
| 470 | |||
| 471 | return 0; | ||
| 472 | } | ||
| 473 | |||
| 474 | subsys_initcall(ixp2000_uengine_init); | ||
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c index 1f6857d7747d..9c6e77faec5b 100644 --- a/arch/arm/mach-pxa/lubbock.c +++ b/arch/arm/mach-pxa/lubbock.c | |||
| @@ -175,7 +175,7 @@ static struct platform_device sa1111_device = { | |||
| 175 | static struct resource smc91x_resources[] = { | 175 | static struct resource smc91x_resources[] = { |
| 176 | [0] = { | 176 | [0] = { |
| 177 | .name = "smc91x-regs", | 177 | .name = "smc91x-regs", |
| 178 | .start = 0x0c000000, | 178 | .start = 0x0c000c00, |
| 179 | .end = 0x0c0fffff, | 179 | .end = 0x0c0fffff, |
| 180 | .flags = IORESOURCE_MEM, | 180 | .flags = IORESOURCE_MEM, |
| 181 | }, | 181 | }, |
| @@ -224,18 +224,75 @@ static struct pxafb_mach_info sharp_lm8v31 __initdata = { | |||
| 224 | .lccr3 = LCCR3_PCP | LCCR3_Acb(255), | 224 | .lccr3 = LCCR3_PCP | LCCR3_Acb(255), |
| 225 | }; | 225 | }; |
| 226 | 226 | ||
| 227 | static int lubbock_mci_init(struct device *dev, irqreturn_t (*lubbock_detect_int)(int, void *, struct pt_regs *), void *data) | 227 | #define MMC_POLL_RATE msecs_to_jiffies(1000) |
| 228 | |||
| 229 | static void lubbock_mmc_poll(unsigned long); | ||
| 230 | static irqreturn_t (*mmc_detect_int)(int, void *, struct pt_regs *); | ||
| 231 | |||
| 232 | static struct timer_list mmc_timer = { | ||
| 233 | .function = lubbock_mmc_poll, | ||
| 234 | }; | ||
| 235 | |||
| 236 | static void lubbock_mmc_poll(unsigned long data) | ||
| 237 | { | ||
| 238 | unsigned long flags; | ||
| 239 | |||
| 240 | /* clear any previous irq state, then ... */ | ||
| 241 | local_irq_save(flags); | ||
| 242 | LUB_IRQ_SET_CLR &= ~(1 << 0); | ||
| 243 | local_irq_restore(flags); | ||
| 244 | |||
| 245 | /* poll until mmc/sd card is removed */ | ||
| 246 | if (LUB_IRQ_SET_CLR & (1 << 0)) | ||
| 247 | mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE); | ||
| 248 | else { | ||
| 249 | (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data, NULL); | ||
| 250 | enable_irq(LUBBOCK_SD_IRQ); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | static irqreturn_t lubbock_detect_int(int irq, void *data, struct pt_regs *regs) | ||
| 255 | { | ||
| 256 | /* IRQ is level triggered; disable, and poll for removal */ | ||
| 257 | disable_irq(irq); | ||
| 258 | mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE); | ||
| 259 | |||
| 260 | return mmc_detect_int(irq, data, regs); | ||
| 261 | } | ||
| 262 | |||
| 263 | static int lubbock_mci_init(struct device *dev, | ||
| 264 | irqreturn_t (*detect_int)(int, void *, struct pt_regs *), | ||
| 265 | void *data) | ||
| 228 | { | 266 | { |
| 229 | /* setup GPIO for PXA25x MMC controller */ | 267 | /* setup GPIO for PXA25x MMC controller */ |
| 230 | pxa_gpio_mode(GPIO6_MMCCLK_MD); | 268 | pxa_gpio_mode(GPIO6_MMCCLK_MD); |
| 231 | pxa_gpio_mode(GPIO8_MMCCS0_MD); | 269 | pxa_gpio_mode(GPIO8_MMCCS0_MD); |
| 232 | 270 | ||
| 233 | return 0; | 271 | /* detect card insert/eject */ |
| 272 | mmc_detect_int = detect_int; | ||
| 273 | init_timer(&mmc_timer); | ||
| 274 | mmc_timer.data = (unsigned long) data; | ||
| 275 | return request_irq(LUBBOCK_SD_IRQ, lubbock_detect_int, | ||
| 276 | SA_SAMPLE_RANDOM, "lubbock-sd-detect", data); | ||
| 277 | } | ||
| 278 | |||
| 279 | static int lubbock_mci_get_ro(struct device *dev) | ||
| 280 | { | ||
| 281 | return (LUB_MISC_RD & (1 << 2)) != 0; | ||
| 282 | } | ||
| 283 | |||
| 284 | static void lubbock_mci_exit(struct device *dev, void *data) | ||
| 285 | { | ||
| 286 | free_irq(LUBBOCK_SD_IRQ, data); | ||
| 287 | del_timer_sync(&mmc_timer); | ||
| 234 | } | 288 | } |
| 235 | 289 | ||
| 236 | static struct pxamci_platform_data lubbock_mci_platform_data = { | 290 | static struct pxamci_platform_data lubbock_mci_platform_data = { |
| 237 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | 291 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, |
| 292 | .detect_delay = 1, | ||
| 238 | .init = lubbock_mci_init, | 293 | .init = lubbock_mci_init, |
| 294 | .get_ro = lubbock_mci_get_ro, | ||
| 295 | .exit = lubbock_mci_exit, | ||
| 239 | }; | 296 | }; |
| 240 | 297 | ||
| 241 | static void lubbock_irda_transceiver_mode(struct device *dev, int mode) | 298 | static void lubbock_irda_transceiver_mode(struct device *dev, int mode) |
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig new file mode 100644 index 000000000000..4b63dc9eabfe --- /dev/null +++ b/arch/arm/mach-realview/Kconfig | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | menu "RealView platform type" | ||
| 2 | depends on ARCH_REALVIEW | ||
| 3 | |||
| 4 | config MACH_REALVIEW_EB | ||
| 5 | bool "Support RealView/EB platform" | ||
| 6 | default n | ||
| 7 | select ARM_GIC | ||
| 8 | help | ||
| 9 | Include support for the ARM(R) RealView Emulation Baseboard platform. | ||
| 10 | |||
| 11 | endmenu | ||
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile new file mode 100644 index 000000000000..8d37ea1605fd --- /dev/null +++ b/arch/arm/mach-realview/Makefile | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the linux kernel. | ||
| 3 | # | ||
| 4 | |||
| 5 | obj-y := core.o clock.o | ||
| 6 | obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o | ||
diff --git a/arch/arm/mach-realview/Makefile.boot b/arch/arm/mach-realview/Makefile.boot new file mode 100644 index 000000000000..c7e75acfe6c9 --- /dev/null +++ b/arch/arm/mach-realview/Makefile.boot | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | zreladdr-y := 0x00008000 | ||
| 2 | params_phys-y := 0x00000100 | ||
| 3 | initrd_phys-y := 0x00800000 | ||
| 4 | |||
diff --git a/arch/arm/mach-realview/clock.c b/arch/arm/mach-realview/clock.c new file mode 100644 index 000000000000..002635c97bb6 --- /dev/null +++ b/arch/arm/mach-realview/clock.c | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-realview/clock.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2004 ARM Limited. | ||
| 5 | * Written by Deep Blue Solutions Limited. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/list.h> | ||
| 14 | #include <linux/errno.h> | ||
| 15 | #include <linux/err.h> | ||
| 16 | |||
| 17 | #include <asm/semaphore.h> | ||
| 18 | #include <asm/hardware/clock.h> | ||
| 19 | #include <asm/hardware/icst307.h> | ||
| 20 | |||
| 21 | #include "clock.h" | ||
| 22 | |||
| 23 | static LIST_HEAD(clocks); | ||
| 24 | static DECLARE_MUTEX(clocks_sem); | ||
| 25 | |||
| 26 | struct clk *clk_get(struct device *dev, const char *id) | ||
| 27 | { | ||
| 28 | struct clk *p, *clk = ERR_PTR(-ENOENT); | ||
| 29 | |||
| 30 | down(&clocks_sem); | ||
| 31 | list_for_each_entry(p, &clocks, node) { | ||
| 32 | if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { | ||
| 33 | clk = p; | ||
| 34 | break; | ||
| 35 | } | ||
| 36 | } | ||
| 37 | up(&clocks_sem); | ||
| 38 | |||
| 39 | return clk; | ||
| 40 | } | ||
| 41 | EXPORT_SYMBOL(clk_get); | ||
| 42 | |||
| 43 | void clk_put(struct clk *clk) | ||
| 44 | { | ||
| 45 | module_put(clk->owner); | ||
| 46 | } | ||
| 47 | EXPORT_SYMBOL(clk_put); | ||
| 48 | |||
| 49 | int clk_enable(struct clk *clk) | ||
| 50 | { | ||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | EXPORT_SYMBOL(clk_enable); | ||
| 54 | |||
| 55 | void clk_disable(struct clk *clk) | ||
| 56 | { | ||
| 57 | } | ||
| 58 | EXPORT_SYMBOL(clk_disable); | ||
| 59 | |||
| 60 | int clk_use(struct clk *clk) | ||
| 61 | { | ||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | EXPORT_SYMBOL(clk_use); | ||
| 65 | |||
| 66 | void clk_unuse(struct clk *clk) | ||
| 67 | { | ||
| 68 | } | ||
| 69 | EXPORT_SYMBOL(clk_unuse); | ||
| 70 | |||
| 71 | unsigned long clk_get_rate(struct clk *clk) | ||
| 72 | { | ||
| 73 | return clk->rate; | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL(clk_get_rate); | ||
| 76 | |||
| 77 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
| 78 | { | ||
| 79 | return rate; | ||
| 80 | } | ||
| 81 | EXPORT_SYMBOL(clk_round_rate); | ||
| 82 | |||
| 83 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
| 84 | { | ||
| 85 | int ret = -EIO; | ||
| 86 | |||
| 87 | if (clk->setvco) { | ||
| 88 | struct icst307_vco vco; | ||
| 89 | |||
| 90 | vco = icst307_khz_to_vco(clk->params, rate / 1000); | ||
| 91 | clk->rate = icst307_khz(clk->params, vco) * 1000; | ||
| 92 | |||
| 93 | printk("Clock %s: setting VCO reg params: S=%d R=%d V=%d\n", | ||
| 94 | clk->name, vco.s, vco.r, vco.v); | ||
| 95 | |||
| 96 | clk->setvco(clk, vco); | ||
| 97 | ret = 0; | ||
| 98 | } | ||
| 99 | return ret; | ||
| 100 | } | ||
| 101 | EXPORT_SYMBOL(clk_set_rate); | ||
| 102 | |||
| 103 | /* | ||
| 104 | * These are fixed clocks. | ||
| 105 | */ | ||
| 106 | static struct clk kmi_clk = { | ||
| 107 | .name = "KMIREFCLK", | ||
| 108 | .rate = 24000000, | ||
| 109 | }; | ||
| 110 | |||
| 111 | static struct clk uart_clk = { | ||
| 112 | .name = "UARTCLK", | ||
| 113 | .rate = 24000000, | ||
| 114 | }; | ||
| 115 | |||
| 116 | static struct clk mmci_clk = { | ||
| 117 | .name = "MCLK", | ||
| 118 | .rate = 33000000, | ||
| 119 | }; | ||
| 120 | |||
| 121 | int clk_register(struct clk *clk) | ||
| 122 | { | ||
| 123 | down(&clocks_sem); | ||
| 124 | list_add(&clk->node, &clocks); | ||
| 125 | up(&clocks_sem); | ||
| 126 | return 0; | ||
| 127 | } | ||
| 128 | EXPORT_SYMBOL(clk_register); | ||
| 129 | |||
| 130 | void clk_unregister(struct clk *clk) | ||
| 131 | { | ||
| 132 | down(&clocks_sem); | ||
| 133 | list_del(&clk->node); | ||
| 134 | up(&clocks_sem); | ||
| 135 | } | ||
| 136 | EXPORT_SYMBOL(clk_unregister); | ||
| 137 | |||
| 138 | static int __init clk_init(void) | ||
| 139 | { | ||
| 140 | clk_register(&kmi_clk); | ||
| 141 | clk_register(&uart_clk); | ||
| 142 | clk_register(&mmci_clk); | ||
| 143 | return 0; | ||
| 144 | } | ||
| 145 | arch_initcall(clk_init); | ||
diff --git a/arch/arm/mach-realview/clock.h b/arch/arm/mach-realview/clock.h new file mode 100644 index 000000000000..dadba695e181 --- /dev/null +++ b/arch/arm/mach-realview/clock.h | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-realview/clock.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2004 ARM Limited. | ||
| 5 | * Written by Deep Blue Solutions Limited. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | struct module; | ||
| 12 | struct icst307_params; | ||
| 13 | |||
| 14 | struct clk { | ||
| 15 | struct list_head node; | ||
| 16 | unsigned long rate; | ||
| 17 | struct module *owner; | ||
| 18 | const char *name; | ||
| 19 | const struct icst307_params *params; | ||
| 20 | void *data; | ||
| 21 | void (*setvco)(struct clk *, struct icst307_vco vco); | ||
| 22 | }; | ||
| 23 | |||
| 24 | int clk_register(struct clk *clk); | ||
| 25 | void clk_unregister(struct clk *clk); | ||
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c new file mode 100644 index 000000000000..482eb512ebe8 --- /dev/null +++ b/arch/arm/mach-realview/core.c | |||
| @@ -0,0 +1,605 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-realview/core.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1999 - 2003 ARM Limited | ||
| 5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | #include <linux/config.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/dma-mapping.h> | ||
| 25 | #include <linux/sysdev.h> | ||
| 26 | #include <linux/interrupt.h> | ||
| 27 | |||
| 28 | #include <asm/system.h> | ||
| 29 | #include <asm/hardware.h> | ||
| 30 | #include <asm/io.h> | ||
| 31 | #include <asm/irq.h> | ||
| 32 | #include <asm/leds.h> | ||
| 33 | #include <asm/mach-types.h> | ||
| 34 | #include <asm/hardware/amba.h> | ||
| 35 | #include <asm/hardware/amba_clcd.h> | ||
| 36 | #include <asm/hardware/arm_timer.h> | ||
| 37 | #include <asm/hardware/icst307.h> | ||
| 38 | |||
| 39 | #include <asm/mach/arch.h> | ||
| 40 | #include <asm/mach/flash.h> | ||
| 41 | #include <asm/mach/irq.h> | ||
| 42 | #include <asm/mach/time.h> | ||
| 43 | #include <asm/mach/map.h> | ||
| 44 | #include <asm/mach/mmc.h> | ||
| 45 | |||
| 46 | #include <asm/hardware/gic.h> | ||
| 47 | |||
| 48 | #include "core.h" | ||
| 49 | #include "clock.h" | ||
| 50 | |||
| 51 | #define REALVIEW_REFCOUNTER (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET) | ||
| 52 | |||
| 53 | /* | ||
| 54 | * This is the RealView sched_clock implementation. This has | ||
| 55 | * a resolution of 41.7ns, and a maximum value of about 179s. | ||
| 56 | */ | ||
| 57 | unsigned long long sched_clock(void) | ||
| 58 | { | ||
| 59 | unsigned long long v; | ||
| 60 | |||
| 61 | v = (unsigned long long)readl(REALVIEW_REFCOUNTER) * 125; | ||
| 62 | do_div(v, 3); | ||
| 63 | |||
| 64 | return v; | ||
| 65 | } | ||
| 66 | |||
| 67 | |||
| 68 | #define REALVIEW_FLASHCTRL (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_FLASH_OFFSET) | ||
| 69 | |||
| 70 | static int realview_flash_init(void) | ||
| 71 | { | ||
| 72 | u32 val; | ||
| 73 | |||
| 74 | val = __raw_readl(REALVIEW_FLASHCTRL); | ||
| 75 | val &= ~REALVIEW_FLASHPROG_FLVPPEN; | ||
| 76 | __raw_writel(val, REALVIEW_FLASHCTRL); | ||
| 77 | |||
| 78 | return 0; | ||
| 79 | } | ||
| 80 | |||
| 81 | static void realview_flash_exit(void) | ||
| 82 | { | ||
| 83 | u32 val; | ||
| 84 | |||
| 85 | val = __raw_readl(REALVIEW_FLASHCTRL); | ||
| 86 | val &= ~REALVIEW_FLASHPROG_FLVPPEN; | ||
| 87 | __raw_writel(val, REALVIEW_FLASHCTRL); | ||
| 88 | } | ||
| 89 | |||
| 90 | static void realview_flash_set_vpp(int on) | ||
| 91 | { | ||
| 92 | u32 val; | ||
| 93 | |||
| 94 | val = __raw_readl(REALVIEW_FLASHCTRL); | ||
| 95 | if (on) | ||
| 96 | val |= REALVIEW_FLASHPROG_FLVPPEN; | ||
| 97 | else | ||
| 98 | val &= ~REALVIEW_FLASHPROG_FLVPPEN; | ||
| 99 | __raw_writel(val, REALVIEW_FLASHCTRL); | ||
| 100 | } | ||
| 101 | |||
| 102 | static struct flash_platform_data realview_flash_data = { | ||
| 103 | .map_name = "cfi_probe", | ||
| 104 | .width = 4, | ||
| 105 | .init = realview_flash_init, | ||
| 106 | .exit = realview_flash_exit, | ||
| 107 | .set_vpp = realview_flash_set_vpp, | ||
| 108 | }; | ||
| 109 | |||
| 110 | static struct resource realview_flash_resource = { | ||
| 111 | .start = REALVIEW_FLASH_BASE, | ||
| 112 | .end = REALVIEW_FLASH_BASE + REALVIEW_FLASH_SIZE, | ||
| 113 | .flags = IORESOURCE_MEM, | ||
| 114 | }; | ||
| 115 | |||
| 116 | struct platform_device realview_flash_device = { | ||
| 117 | .name = "armflash", | ||
| 118 | .id = 0, | ||
| 119 | .dev = { | ||
| 120 | .platform_data = &realview_flash_data, | ||
| 121 | }, | ||
| 122 | .num_resources = 1, | ||
| 123 | .resource = &realview_flash_resource, | ||
| 124 | }; | ||
| 125 | |||
| 126 | static struct resource realview_smc91x_resources[] = { | ||
| 127 | [0] = { | ||
| 128 | .start = REALVIEW_ETH_BASE, | ||
| 129 | .end = REALVIEW_ETH_BASE + SZ_64K - 1, | ||
| 130 | .flags = IORESOURCE_MEM, | ||
| 131 | }, | ||
| 132 | [1] = { | ||
| 133 | .start = IRQ_ETH, | ||
| 134 | .end = IRQ_ETH, | ||
| 135 | .flags = IORESOURCE_IRQ, | ||
| 136 | }, | ||
| 137 | }; | ||
| 138 | |||
| 139 | struct platform_device realview_smc91x_device = { | ||
| 140 | .name = "smc91x", | ||
| 141 | .id = 0, | ||
| 142 | .num_resources = ARRAY_SIZE(realview_smc91x_resources), | ||
| 143 | .resource = realview_smc91x_resources, | ||
| 144 | }; | ||
| 145 | |||
| 146 | #define REALVIEW_SYSMCI (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_MCI_OFFSET) | ||
| 147 | |||
| 148 | static unsigned int realview_mmc_status(struct device *dev) | ||
| 149 | { | ||
| 150 | struct amba_device *adev = container_of(dev, struct amba_device, dev); | ||
| 151 | u32 mask; | ||
| 152 | |||
| 153 | if (adev->res.start == REALVIEW_MMCI0_BASE) | ||
| 154 | mask = 1; | ||
| 155 | else | ||
| 156 | mask = 2; | ||
| 157 | |||
| 158 | return readl(REALVIEW_SYSMCI) & mask; | ||
| 159 | } | ||
| 160 | |||
| 161 | struct mmc_platform_data realview_mmc0_plat_data = { | ||
| 162 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
| 163 | .status = realview_mmc_status, | ||
| 164 | }; | ||
| 165 | |||
| 166 | struct mmc_platform_data realview_mmc1_plat_data = { | ||
| 167 | .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, | ||
| 168 | .status = realview_mmc_status, | ||
| 169 | }; | ||
| 170 | |||
| 171 | /* | ||
| 172 | * Clock handling | ||
| 173 | */ | ||
| 174 | static const struct icst307_params realview_oscvco_params = { | ||
| 175 | .ref = 24000, | ||
| 176 | .vco_max = 200000, | ||
| 177 | .vd_min = 4 + 8, | ||
| 178 | .vd_max = 511 + 8, | ||
| 179 | .rd_min = 1 + 2, | ||
| 180 | .rd_max = 127 + 2, | ||
| 181 | }; | ||
| 182 | |||
| 183 | static void realview_oscvco_set(struct clk *clk, struct icst307_vco vco) | ||
| 184 | { | ||
| 185 | void __iomem *sys_lock = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LOCK_OFFSET; | ||
| 186 | void __iomem *sys_osc = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_OSC1_OFFSET; | ||
| 187 | u32 val; | ||
| 188 | |||
| 189 | val = readl(sys_osc) & ~0x7ffff; | ||
| 190 | val |= vco.v | (vco.r << 9) | (vco.s << 16); | ||
| 191 | |||
| 192 | writel(0xa05f, sys_lock); | ||
| 193 | writel(val, sys_osc); | ||
| 194 | writel(0, sys_lock); | ||
| 195 | } | ||
| 196 | |||
| 197 | struct clk realview_clcd_clk = { | ||
| 198 | .name = "CLCDCLK", | ||
| 199 | .params = &realview_oscvco_params, | ||
| 200 | .setvco = realview_oscvco_set, | ||
| 201 | }; | ||
| 202 | |||
| 203 | /* | ||
| 204 | * CLCD support. | ||
| 205 | */ | ||
| 206 | #define SYS_CLCD_MODE_MASK (3 << 0) | ||
| 207 | #define SYS_CLCD_MODE_888 (0 << 0) | ||
| 208 | #define SYS_CLCD_MODE_5551 (1 << 0) | ||
| 209 | #define SYS_CLCD_MODE_565_RLSB (2 << 0) | ||
| 210 | #define SYS_CLCD_MODE_565_BLSB (3 << 0) | ||
| 211 | #define SYS_CLCD_NLCDIOON (1 << 2) | ||
| 212 | #define SYS_CLCD_VDDPOSSWITCH (1 << 3) | ||
| 213 | #define SYS_CLCD_PWR3V5SWITCH (1 << 4) | ||
| 214 | #define SYS_CLCD_ID_MASK (0x1f << 8) | ||
| 215 | #define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8) | ||
| 216 | #define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8) | ||
| 217 | #define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8) | ||
| 218 | #define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8) | ||
| 219 | #define SYS_CLCD_ID_VGA (0x1f << 8) | ||
| 220 | |||
| 221 | static struct clcd_panel vga = { | ||
| 222 | .mode = { | ||
| 223 | .name = "VGA", | ||
| 224 | .refresh = 60, | ||
| 225 | .xres = 640, | ||
| 226 | .yres = 480, | ||
| 227 | .pixclock = 39721, | ||
| 228 | .left_margin = 40, | ||
| 229 | .right_margin = 24, | ||
| 230 | .upper_margin = 32, | ||
| 231 | .lower_margin = 11, | ||
| 232 | .hsync_len = 96, | ||
| 233 | .vsync_len = 2, | ||
| 234 | .sync = 0, | ||
| 235 | .vmode = FB_VMODE_NONINTERLACED, | ||
| 236 | }, | ||
| 237 | .width = -1, | ||
| 238 | .height = -1, | ||
| 239 | .tim2 = TIM2_BCD | TIM2_IPC, | ||
| 240 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
| 241 | .bpp = 16, | ||
| 242 | }; | ||
| 243 | |||
| 244 | static struct clcd_panel sanyo_3_8_in = { | ||
| 245 | .mode = { | ||
| 246 | .name = "Sanyo QVGA", | ||
| 247 | .refresh = 116, | ||
| 248 | .xres = 320, | ||
| 249 | .yres = 240, | ||
| 250 | .pixclock = 100000, | ||
| 251 | .left_margin = 6, | ||
| 252 | .right_margin = 6, | ||
| 253 | .upper_margin = 5, | ||
| 254 | .lower_margin = 5, | ||
| 255 | .hsync_len = 6, | ||
| 256 | .vsync_len = 6, | ||
| 257 | .sync = 0, | ||
| 258 | .vmode = FB_VMODE_NONINTERLACED, | ||
| 259 | }, | ||
| 260 | .width = -1, | ||
| 261 | .height = -1, | ||
| 262 | .tim2 = TIM2_BCD, | ||
| 263 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
| 264 | .bpp = 16, | ||
| 265 | }; | ||
| 266 | |||
| 267 | static struct clcd_panel sanyo_2_5_in = { | ||
| 268 | .mode = { | ||
| 269 | .name = "Sanyo QVGA Portrait", | ||
| 270 | .refresh = 116, | ||
| 271 | .xres = 240, | ||
| 272 | .yres = 320, | ||
| 273 | .pixclock = 100000, | ||
| 274 | .left_margin = 20, | ||
| 275 | .right_margin = 10, | ||
| 276 | .upper_margin = 2, | ||
| 277 | .lower_margin = 2, | ||
| 278 | .hsync_len = 10, | ||
| 279 | .vsync_len = 2, | ||
| 280 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
| 281 | .vmode = FB_VMODE_NONINTERLACED, | ||
| 282 | }, | ||
| 283 | .width = -1, | ||
| 284 | .height = -1, | ||
| 285 | .tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC, | ||
| 286 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
| 287 | .bpp = 16, | ||
| 288 | }; | ||
| 289 | |||
| 290 | static struct clcd_panel epson_2_2_in = { | ||
| 291 | .mode = { | ||
| 292 | .name = "Epson QCIF", | ||
| 293 | .refresh = 390, | ||
| 294 | .xres = 176, | ||
| 295 | .yres = 220, | ||
| 296 | .pixclock = 62500, | ||
| 297 | .left_margin = 3, | ||
| 298 | .right_margin = 2, | ||
| 299 | .upper_margin = 1, | ||
| 300 | .lower_margin = 0, | ||
| 301 | .hsync_len = 3, | ||
| 302 | .vsync_len = 2, | ||
| 303 | .sync = 0, | ||
| 304 | .vmode = FB_VMODE_NONINTERLACED, | ||
| 305 | }, | ||
| 306 | .width = -1, | ||
| 307 | .height = -1, | ||
| 308 | .tim2 = TIM2_BCD | TIM2_IPC, | ||
| 309 | .cntl = CNTL_LCDTFT | CNTL_LCDVCOMP(1), | ||
| 310 | .bpp = 16, | ||
| 311 | }; | ||
| 312 | |||
| 313 | /* | ||
| 314 | * Detect which LCD panel is connected, and return the appropriate | ||
| 315 | * clcd_panel structure. Note: we do not have any information on | ||
| 316 | * the required timings for the 8.4in panel, so we presently assume | ||
| 317 | * VGA timings. | ||
| 318 | */ | ||
| 319 | static struct clcd_panel *realview_clcd_panel(void) | ||
| 320 | { | ||
| 321 | void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET; | ||
| 322 | struct clcd_panel *panel = &vga; | ||
| 323 | u32 val; | ||
| 324 | |||
| 325 | val = readl(sys_clcd) & SYS_CLCD_ID_MASK; | ||
| 326 | if (val == SYS_CLCD_ID_SANYO_3_8) | ||
| 327 | panel = &sanyo_3_8_in; | ||
| 328 | else if (val == SYS_CLCD_ID_SANYO_2_5) | ||
| 329 | panel = &sanyo_2_5_in; | ||
| 330 | else if (val == SYS_CLCD_ID_EPSON_2_2) | ||
| 331 | panel = &epson_2_2_in; | ||
| 332 | else if (val == SYS_CLCD_ID_VGA) | ||
| 333 | panel = &vga; | ||
| 334 | else { | ||
| 335 | printk(KERN_ERR "CLCD: unknown LCD panel ID 0x%08x, using VGA\n", | ||
| 336 | val); | ||
| 337 | panel = &vga; | ||
| 338 | } | ||
| 339 | |||
| 340 | return panel; | ||
| 341 | } | ||
| 342 | |||
| 343 | /* | ||
| 344 | * Disable all display connectors on the interface module. | ||
| 345 | */ | ||
| 346 | static void realview_clcd_disable(struct clcd_fb *fb) | ||
| 347 | { | ||
| 348 | void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET; | ||
| 349 | u32 val; | ||
| 350 | |||
| 351 | val = readl(sys_clcd); | ||
| 352 | val &= ~SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; | ||
| 353 | writel(val, sys_clcd); | ||
| 354 | } | ||
| 355 | |||
| 356 | /* | ||
| 357 | * Enable the relevant connector on the interface module. | ||
| 358 | */ | ||
| 359 | static void realview_clcd_enable(struct clcd_fb *fb) | ||
| 360 | { | ||
| 361 | void __iomem *sys_clcd = __io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_CLCD_OFFSET; | ||
| 362 | u32 val; | ||
| 363 | |||
| 364 | val = readl(sys_clcd); | ||
| 365 | val &= ~SYS_CLCD_MODE_MASK; | ||
| 366 | |||
| 367 | switch (fb->fb.var.green.length) { | ||
| 368 | case 5: | ||
| 369 | val |= SYS_CLCD_MODE_5551; | ||
| 370 | break; | ||
| 371 | case 6: | ||
| 372 | val |= SYS_CLCD_MODE_565_RLSB; | ||
| 373 | break; | ||
| 374 | case 8: | ||
| 375 | val |= SYS_CLCD_MODE_888; | ||
| 376 | break; | ||
| 377 | } | ||
| 378 | |||
| 379 | /* | ||
| 380 | * Set the MUX | ||
| 381 | */ | ||
| 382 | writel(val, sys_clcd); | ||
| 383 | |||
| 384 | /* | ||
| 385 | * And now enable the PSUs | ||
| 386 | */ | ||
| 387 | val |= SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH; | ||
| 388 | writel(val, sys_clcd); | ||
| 389 | } | ||
| 390 | |||
| 391 | static unsigned long framesize = SZ_1M; | ||
| 392 | |||
| 393 | static int realview_clcd_setup(struct clcd_fb *fb) | ||
| 394 | { | ||
| 395 | dma_addr_t dma; | ||
| 396 | |||
| 397 | fb->panel = realview_clcd_panel(); | ||
| 398 | |||
| 399 | fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev, framesize, | ||
| 400 | &dma, GFP_KERNEL); | ||
| 401 | if (!fb->fb.screen_base) { | ||
| 402 | printk(KERN_ERR "CLCD: unable to map framebuffer\n"); | ||
| 403 | return -ENOMEM; | ||
| 404 | } | ||
| 405 | |||
| 406 | fb->fb.fix.smem_start = dma; | ||
| 407 | fb->fb.fix.smem_len = framesize; | ||
| 408 | |||
| 409 | return 0; | ||
| 410 | } | ||
| 411 | |||
| 412 | static int realview_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma) | ||
| 413 | { | ||
| 414 | return dma_mmap_writecombine(&fb->dev->dev, vma, | ||
| 415 | fb->fb.screen_base, | ||
| 416 | fb->fb.fix.smem_start, | ||
| 417 | fb->fb.fix.smem_len); | ||
| 418 | } | ||
| 419 | |||
| 420 | static void realview_clcd_remove(struct clcd_fb *fb) | ||
| 421 | { | ||
| 422 | dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len, | ||
| 423 | fb->fb.screen_base, fb->fb.fix.smem_start); | ||
| 424 | } | ||
| 425 | |||
| 426 | struct clcd_board clcd_plat_data = { | ||
| 427 | .name = "RealView", | ||
| 428 | .check = clcdfb_check, | ||
| 429 | .decode = clcdfb_decode, | ||
| 430 | .disable = realview_clcd_disable, | ||
| 431 | .enable = realview_clcd_enable, | ||
| 432 | .setup = realview_clcd_setup, | ||
| 433 | .mmap = realview_clcd_mmap, | ||
| 434 | .remove = realview_clcd_remove, | ||
| 435 | }; | ||
| 436 | |||
| 437 | #ifdef CONFIG_LEDS | ||
| 438 | #define VA_LEDS_BASE (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_LED_OFFSET) | ||
| 439 | |||
| 440 | void realview_leds_event(led_event_t ledevt) | ||
| 441 | { | ||
| 442 | unsigned long flags; | ||
| 443 | u32 val; | ||
| 444 | |||
| 445 | local_irq_save(flags); | ||
| 446 | val = readl(VA_LEDS_BASE); | ||
| 447 | |||
| 448 | switch (ledevt) { | ||
| 449 | case led_idle_start: | ||
| 450 | val = val & ~REALVIEW_SYS_LED0; | ||
| 451 | break; | ||
| 452 | |||
| 453 | case led_idle_end: | ||
| 454 | val = val | REALVIEW_SYS_LED0; | ||
| 455 | break; | ||
| 456 | |||
| 457 | case led_timer: | ||
| 458 | val = val ^ REALVIEW_SYS_LED1; | ||
| 459 | break; | ||
| 460 | |||
| 461 | case led_halted: | ||
| 462 | val = 0; | ||
| 463 | break; | ||
| 464 | |||
| 465 | default: | ||
| 466 | break; | ||
| 467 | } | ||
| 468 | |||
| 469 | writel(val, VA_LEDS_BASE); | ||
| 470 | local_irq_restore(flags); | ||
| 471 | } | ||
| 472 | #endif /* CONFIG_LEDS */ | ||
| 473 | |||
| 474 | /* | ||
| 475 | * Where is the timer (VA)? | ||
| 476 | */ | ||
| 477 | #define TIMER0_VA_BASE __io_address(REALVIEW_TIMER0_1_BASE) | ||
| 478 | #define TIMER1_VA_BASE (__io_address(REALVIEW_TIMER0_1_BASE) + 0x20) | ||
| 479 | #define TIMER2_VA_BASE __io_address(REALVIEW_TIMER2_3_BASE) | ||
| 480 | #define TIMER3_VA_BASE (__io_address(REALVIEW_TIMER2_3_BASE) + 0x20) | ||
| 481 | |||
| 482 | /* | ||
| 483 | * How long is the timer interval? | ||
| 484 | */ | ||
| 485 | #define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) | ||
| 486 | #if TIMER_INTERVAL >= 0x100000 | ||
| 487 | #define TIMER_RELOAD (TIMER_INTERVAL >> 8) | ||
| 488 | #define TIMER_DIVISOR (TIMER_CTRL_DIV256) | ||
| 489 | #define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) | ||
| 490 | #elif TIMER_INTERVAL >= 0x10000 | ||
| 491 | #define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */ | ||
| 492 | #define TIMER_DIVISOR (TIMER_CTRL_DIV16) | ||
| 493 | #define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) | ||
| 494 | #else | ||
| 495 | #define TIMER_RELOAD (TIMER_INTERVAL) | ||
| 496 | #define TIMER_DIVISOR (TIMER_CTRL_DIV1) | ||
| 497 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) | ||
| 498 | #endif | ||
| 499 | |||
| 500 | /* | ||
| 501 | * Returns number of ms since last clock interrupt. Note that interrupts | ||
| 502 | * will have been disabled by do_gettimeoffset() | ||
| 503 | */ | ||
| 504 | static unsigned long realview_gettimeoffset(void) | ||
| 505 | { | ||
| 506 | unsigned long ticks1, ticks2, status; | ||
| 507 | |||
| 508 | /* | ||
| 509 | * Get the current number of ticks. Note that there is a race | ||
| 510 | * condition between us reading the timer and checking for | ||
| 511 | * an interrupt. We get around this by ensuring that the | ||
| 512 | * counter has not reloaded between our two reads. | ||
| 513 | */ | ||
| 514 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | ||
| 515 | do { | ||
| 516 | ticks1 = ticks2; | ||
| 517 | status = __raw_readl(__io_address(REALVIEW_GIC_DIST_BASE + GIC_DIST_PENDING_SET) | ||
| 518 | + ((IRQ_TIMERINT0_1 >> 5) << 2)); | ||
| 519 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | ||
| 520 | } while (ticks2 > ticks1); | ||
| 521 | |||
| 522 | /* | ||
| 523 | * Number of ticks since last interrupt. | ||
| 524 | */ | ||
| 525 | ticks1 = TIMER_RELOAD - ticks2; | ||
| 526 | |||
| 527 | /* | ||
| 528 | * Interrupt pending? If so, we've reloaded once already. | ||
| 529 | * | ||
| 530 | * FIXME: Need to check this is effectively timer 0 that expires | ||
| 531 | */ | ||
| 532 | if (status & IRQMASK_TIMERINT0_1) | ||
| 533 | ticks1 += TIMER_RELOAD; | ||
| 534 | |||
| 535 | /* | ||
| 536 | * Convert the ticks to usecs | ||
| 537 | */ | ||
| 538 | return TICKS2USECS(ticks1); | ||
| 539 | } | ||
| 540 | |||
| 541 | /* | ||
| 542 | * IRQ handler for the timer | ||
| 543 | */ | ||
| 544 | static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
| 545 | { | ||
| 546 | write_seqlock(&xtime_lock); | ||
| 547 | |||
| 548 | // ...clear the interrupt | ||
| 549 | writel(1, TIMER0_VA_BASE + TIMER_INTCLR); | ||
| 550 | |||
| 551 | timer_tick(regs); | ||
| 552 | |||
| 553 | write_sequnlock(&xtime_lock); | ||
| 554 | |||
| 555 | return IRQ_HANDLED; | ||
| 556 | } | ||
| 557 | |||
| 558 | static struct irqaction realview_timer_irq = { | ||
| 559 | .name = "RealView Timer Tick", | ||
| 560 | .flags = SA_INTERRUPT | SA_TIMER, | ||
| 561 | .handler = realview_timer_interrupt, | ||
| 562 | }; | ||
| 563 | |||
| 564 | /* | ||
| 565 | * Set up timer interrupt, and return the current time in seconds. | ||
| 566 | */ | ||
| 567 | static void __init realview_timer_init(void) | ||
| 568 | { | ||
| 569 | u32 val; | ||
| 570 | |||
| 571 | /* | ||
| 572 | * set clock frequency: | ||
| 573 | * REALVIEW_REFCLK is 32KHz | ||
| 574 | * REALVIEW_TIMCLK is 1MHz | ||
| 575 | */ | ||
| 576 | val = readl(__io_address(REALVIEW_SCTL_BASE)); | ||
| 577 | writel((REALVIEW_TIMCLK << REALVIEW_TIMER1_EnSel) | | ||
| 578 | (REALVIEW_TIMCLK << REALVIEW_TIMER2_EnSel) | | ||
| 579 | (REALVIEW_TIMCLK << REALVIEW_TIMER3_EnSel) | | ||
| 580 | (REALVIEW_TIMCLK << REALVIEW_TIMER4_EnSel) | val, | ||
| 581 | __io_address(REALVIEW_SCTL_BASE)); | ||
| 582 | |||
| 583 | /* | ||
| 584 | * Initialise to a known state (all timers off) | ||
| 585 | */ | ||
| 586 | writel(0, TIMER0_VA_BASE + TIMER_CTRL); | ||
| 587 | writel(0, TIMER1_VA_BASE + TIMER_CTRL); | ||
| 588 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); | ||
| 589 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); | ||
| 590 | |||
| 591 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); | ||
| 592 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); | ||
| 593 | writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | | ||
| 594 | TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); | ||
| 595 | |||
| 596 | /* | ||
| 597 | * Make irqs happen for the system timer | ||
| 598 | */ | ||
| 599 | setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq); | ||
| 600 | } | ||
| 601 | |||
| 602 | struct sys_timer realview_timer = { | ||
| 603 | .init = realview_timer_init, | ||
| 604 | .offset = realview_gettimeoffset, | ||
| 605 | }; | ||
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h new file mode 100644 index 000000000000..575599db74db --- /dev/null +++ b/arch/arm/mach-realview/core.h | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-realview/core.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2004 ARM Limited | ||
| 5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #ifndef __ASM_ARCH_REALVIEW_H | ||
| 23 | #define __ASM_ARCH_REALVIEW_H | ||
| 24 | |||
| 25 | #include <asm/hardware/amba.h> | ||
| 26 | #include <asm/io.h> | ||
| 27 | |||
| 28 | #define __io_address(n) __io(IO_ADDRESS(n)) | ||
| 29 | |||
| 30 | extern struct sys_timer realview_timer; | ||
| 31 | |||
| 32 | #define AMBA_DEVICE(name,busid,base,plat) \ | ||
| 33 | static struct amba_device name##_device = { \ | ||
| 34 | .dev = { \ | ||
| 35 | .coherent_dma_mask = ~0, \ | ||
| 36 | .bus_id = busid, \ | ||
| 37 | .platform_data = plat, \ | ||
| 38 | }, \ | ||
| 39 | .res = { \ | ||
| 40 | .start = REALVIEW_##base##_BASE, \ | ||
| 41 | .end = (REALVIEW_##base##_BASE) + SZ_4K - 1,\ | ||
| 42 | .flags = IORESOURCE_MEM, \ | ||
| 43 | }, \ | ||
| 44 | .dma_mask = ~0, \ | ||
| 45 | .irq = base##_IRQ, \ | ||
| 46 | /* .dma = base##_DMA,*/ \ | ||
| 47 | } | ||
| 48 | |||
| 49 | /* | ||
| 50 | * These devices are connected via the core APB bridge | ||
| 51 | */ | ||
| 52 | #define GPIO2_IRQ { IRQ_GPIOINT2, NO_IRQ } | ||
| 53 | #define GPIO2_DMA { 0, 0 } | ||
| 54 | #define GPIO3_IRQ { IRQ_GPIOINT3, NO_IRQ } | ||
| 55 | #define GPIO3_DMA { 0, 0 } | ||
| 56 | |||
| 57 | #define AACI_IRQ { IRQ_AACI, NO_IRQ } | ||
| 58 | #define AACI_DMA { 0x80, 0x81 } | ||
| 59 | #define MMCI0_IRQ { IRQ_MMCI0A,IRQ_MMCI0B } | ||
| 60 | #define MMCI0_DMA { 0x84, 0 } | ||
| 61 | #define KMI0_IRQ { IRQ_KMI0, NO_IRQ } | ||
| 62 | #define KMI0_DMA { 0, 0 } | ||
| 63 | #define KMI1_IRQ { IRQ_KMI1, NO_IRQ } | ||
| 64 | #define KMI1_DMA { 0, 0 } | ||
| 65 | |||
| 66 | /* | ||
| 67 | * These devices are connected directly to the multi-layer AHB switch | ||
| 68 | */ | ||
| 69 | #define SMC_IRQ { NO_IRQ, NO_IRQ } | ||
| 70 | #define SMC_DMA { 0, 0 } | ||
| 71 | #define MPMC_IRQ { NO_IRQ, NO_IRQ } | ||
| 72 | #define MPMC_DMA { 0, 0 } | ||
| 73 | #define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ } | ||
| 74 | #define CLCD_DMA { 0, 0 } | ||
| 75 | #define DMAC_IRQ { IRQ_DMAINT, NO_IRQ } | ||
| 76 | #define DMAC_DMA { 0, 0 } | ||
| 77 | |||
| 78 | /* | ||
| 79 | * These devices are connected via the core APB bridge | ||
| 80 | */ | ||
| 81 | #define SCTL_IRQ { NO_IRQ, NO_IRQ } | ||
| 82 | #define SCTL_DMA { 0, 0 } | ||
| 83 | #define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ } | ||
| 84 | #define WATCHDOG_DMA { 0, 0 } | ||
| 85 | #define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ } | ||
| 86 | #define GPIO0_DMA { 0, 0 } | ||
| 87 | #define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ } | ||
| 88 | #define GPIO1_DMA { 0, 0 } | ||
| 89 | #define RTC_IRQ { IRQ_RTCINT, NO_IRQ } | ||
| 90 | #define RTC_DMA { 0, 0 } | ||
| 91 | |||
| 92 | /* | ||
| 93 | * These devices are connected via the DMA APB bridge | ||
| 94 | */ | ||
| 95 | #define SCI_IRQ { IRQ_SCIINT, NO_IRQ } | ||
| 96 | #define SCI_DMA { 7, 6 } | ||
| 97 | #define UART0_IRQ { IRQ_UARTINT0, NO_IRQ } | ||
| 98 | #define UART0_DMA { 15, 14 } | ||
| 99 | #define UART1_IRQ { IRQ_UARTINT1, NO_IRQ } | ||
| 100 | #define UART1_DMA { 13, 12 } | ||
| 101 | #define UART2_IRQ { IRQ_UARTINT2, NO_IRQ } | ||
| 102 | #define UART2_DMA { 11, 10 } | ||
| 103 | #define UART3_IRQ { IRQ_UART3, NO_IRQ } | ||
| 104 | #define UART3_DMA { 0x86, 0x87 } | ||
| 105 | #define SSP_IRQ { IRQ_SSPINT, NO_IRQ } | ||
| 106 | #define SSP_DMA { 9, 8 } | ||
| 107 | |||
| 108 | |||
| 109 | extern struct platform_device realview_flash_device; | ||
| 110 | extern struct platform_device realview_smc91x_device; | ||
| 111 | extern struct mmc_platform_data realview_mmc0_plat_data; | ||
| 112 | extern struct mmc_platform_data realview_mmc1_plat_data; | ||
| 113 | extern struct clk realview_clcd_clk; | ||
| 114 | extern struct clcd_board clcd_plat_data; | ||
| 115 | |||
| 116 | extern void realview_leds_event(led_event_t ledevt); | ||
| 117 | |||
| 118 | #endif | ||
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c new file mode 100644 index 000000000000..01b264be5029 --- /dev/null +++ b/arch/arm/mach-realview/realview_eb.c | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | /* | ||
| 2 | * linux/arch/arm/mach-realview/realview_eb.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2004 ARM Limited | ||
| 5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/config.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/platform_device.h> | ||
| 25 | #include <linux/sysdev.h> | ||
| 26 | |||
| 27 | #include <asm/hardware.h> | ||
| 28 | #include <asm/io.h> | ||
| 29 | #include <asm/irq.h> | ||
| 30 | #include <asm/leds.h> | ||
| 31 | #include <asm/mach-types.h> | ||
| 32 | #include <asm/hardware/gic.h> | ||
| 33 | #include <asm/hardware/amba.h> | ||
| 34 | #include <asm/hardware/icst307.h> | ||
| 35 | |||
| 36 | #include <asm/mach/arch.h> | ||
| 37 | #include <asm/mach/map.h> | ||
| 38 | #include <asm/mach/mmc.h> | ||
| 39 | |||
| 40 | #include <asm/arch/irqs.h> | ||
| 41 | |||
| 42 | #include "core.h" | ||
| 43 | #include "clock.h" | ||
| 44 | |||
| 45 | static struct map_desc realview_eb_io_desc[] __initdata = { | ||
| 46 | { IO_ADDRESS(REALVIEW_SYS_BASE), REALVIEW_SYS_BASE, SZ_4K, MT_DEVICE }, | ||
| 47 | { IO_ADDRESS(REALVIEW_GIC_CPU_BASE), REALVIEW_GIC_CPU_BASE, SZ_4K, MT_DEVICE }, | ||
| 48 | { IO_ADDRESS(REALVIEW_GIC_DIST_BASE), REALVIEW_GIC_DIST_BASE, SZ_4K, MT_DEVICE }, | ||
| 49 | { IO_ADDRESS(REALVIEW_SCTL_BASE), REALVIEW_SCTL_BASE, SZ_4K, MT_DEVICE }, | ||
| 50 | { IO_ADDRESS(REALVIEW_TIMER0_1_BASE), REALVIEW_TIMER0_1_BASE, SZ_4K, MT_DEVICE }, | ||
| 51 | { IO_ADDRESS(REALVIEW_TIMER2_3_BASE), REALVIEW_TIMER2_3_BASE, SZ_4K, MT_DEVICE }, | ||
| 52 | #ifdef CONFIG_DEBUG_LL | ||
| 53 | { IO_ADDRESS(REALVIEW_UART0_BASE), REALVIEW_UART0_BASE, SZ_4K, MT_DEVICE }, | ||
| 54 | #endif | ||
| 55 | }; | ||
| 56 | |||
| 57 | static void __init realview_eb_map_io(void) | ||
| 58 | { | ||
| 59 | iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc)); | ||
| 60 | } | ||
| 61 | |||
| 62 | /* FPGA Primecells */ | ||
| 63 | AMBA_DEVICE(aaci, "fpga:04", AACI, NULL); | ||
| 64 | AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &realview_mmc0_plat_data); | ||
| 65 | AMBA_DEVICE(kmi0, "fpga:06", KMI0, NULL); | ||
| 66 | AMBA_DEVICE(kmi1, "fpga:07", KMI1, NULL); | ||
| 67 | AMBA_DEVICE(uart3, "fpga:09", UART3, NULL); | ||
| 68 | |||
| 69 | /* DevChip Primecells */ | ||
| 70 | AMBA_DEVICE(smc, "dev:00", SMC, NULL); | ||
| 71 | AMBA_DEVICE(clcd, "dev:20", CLCD, &clcd_plat_data); | ||
| 72 | AMBA_DEVICE(dmac, "dev:30", DMAC, NULL); | ||
| 73 | AMBA_DEVICE(sctl, "dev:e0", SCTL, NULL); | ||
| 74 | AMBA_DEVICE(wdog, "dev:e1", WATCHDOG, NULL); | ||
| 75 | AMBA_DEVICE(gpio0, "dev:e4", GPIO0, NULL); | ||
| 76 | AMBA_DEVICE(gpio1, "dev:e5", GPIO1, NULL); | ||
| 77 | AMBA_DEVICE(gpio2, "dev:e6", GPIO2, NULL); | ||
| 78 | AMBA_DEVICE(rtc, "dev:e8", RTC, NULL); | ||
| 79 | AMBA_DEVICE(sci0, "dev:f0", SCI, NULL); | ||
| 80 | AMBA_DEVICE(uart0, "dev:f1", UART0, NULL); | ||
| 81 | AMBA_DEVICE(uart1, "dev:f2", UART1, NULL); | ||
| 82 | AMBA_DEVICE(uart2, "dev:f3", UART2, NULL); | ||
| 83 | AMBA_DEVICE(ssp0, "dev:f4", SSP, NULL); | ||
| 84 | |||
| 85 | static struct amba_device *amba_devs[] __initdata = { | ||
| 86 | &dmac_device, | ||
| 87 | &uart0_device, | ||
| 88 | &uart1_device, | ||
| 89 | &uart2_device, | ||
| 90 | &uart3_device, | ||
| 91 | &smc_device, | ||
| 92 | &clcd_device, | ||
| 93 | &sctl_device, | ||
| 94 | &wdog_device, | ||
| 95 | &gpio0_device, | ||
| 96 | &gpio1_device, | ||
| 97 | &gpio2_device, | ||
| 98 | &rtc_device, | ||
| 99 | &sci0_device, | ||
| 100 | &ssp0_device, | ||
| 101 | &aaci_device, | ||
| 102 | &mmc0_device, | ||
| 103 | &kmi0_device, | ||
| 104 | &kmi1_device, | ||
| 105 | }; | ||
| 106 | |||
| 107 | static void __init gic_init_irq(void) | ||
| 108 | { | ||
| 109 | gic_dist_init(__io_address(REALVIEW_GIC_DIST_BASE)); | ||
| 110 | gic_cpu_init(__io_address(REALVIEW_GIC_CPU_BASE)); | ||
| 111 | } | ||
| 112 | |||
| 113 | static void __init realview_eb_init(void) | ||
| 114 | { | ||
| 115 | int i; | ||
| 116 | |||
| 117 | clk_register(&realview_clcd_clk); | ||
| 118 | |||
| 119 | platform_device_register(&realview_flash_device); | ||
| 120 | platform_device_register(&realview_smc91x_device); | ||
| 121 | |||
| 122 | for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { | ||
| 123 | struct amba_device *d = amba_devs[i]; | ||
| 124 | amba_device_register(d, &iomem_resource); | ||
| 125 | } | ||
| 126 | |||
| 127 | #ifdef CONFIG_LEDS | ||
| 128 | leds_event = realview_leds_event; | ||
| 129 | #endif | ||
| 130 | } | ||
| 131 | |||
| 132 | MACHINE_START(REALVIEW_EB, "ARM-RealView EB") | ||
| 133 | /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */ | ||
| 134 | .phys_ram = 0x00000000, | ||
| 135 | .phys_io = REALVIEW_UART0_BASE, | ||
| 136 | .io_pg_offst = (IO_ADDRESS(REALVIEW_UART0_BASE) >> 18) & 0xfffc, | ||
| 137 | .boot_params = 0x00000100, | ||
| 138 | .map_io = realview_eb_map_io, | ||
| 139 | .init_irq = gic_init_irq, | ||
| 140 | .timer = &realview_timer, | ||
| 141 | .init_machine = realview_eb_init, | ||
| 142 | MACHINE_END | ||
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c index 8f2a90bf940b..24d69019a843 100644 --- a/arch/arm/mach-s3c2410/mach-rx3715.c +++ b/arch/arm/mach-s3c2410/mach-rx3715.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA | 17 | * 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA |
| 18 | * 14-Mar-2005 BJD Fixed __iomem warnings | 18 | * 14-Mar-2005 BJD Fixed __iomem warnings |
| 19 | * 20-Sep-2005 BJD Added static to non-exported items | 19 | * 20-Sep-2005 BJD Added static to non-exported items |
| 20 | * 31-Oct-2005 BJD Added LCD setup for framebuffer | ||
| 20 | */ | 21 | */ |
| 21 | 22 | ||
| 22 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
| @@ -43,6 +44,9 @@ | |||
| 43 | 44 | ||
| 44 | #include <asm/arch/regs-serial.h> | 45 | #include <asm/arch/regs-serial.h> |
| 45 | #include <asm/arch/regs-gpio.h> | 46 | #include <asm/arch/regs-gpio.h> |
| 47 | #include <asm/arch/regs-lcd.h> | ||
| 48 | |||
| 49 | #include <asm/arch/fb.h> | ||
| 46 | 50 | ||
| 47 | #include "clock.h" | 51 | #include "clock.h" |
| 48 | #include "devs.h" | 52 | #include "devs.h" |
| @@ -97,6 +101,66 @@ static struct s3c2410_uartcfg rx3715_uartcfgs[] = { | |||
| 97 | } | 101 | } |
| 98 | }; | 102 | }; |
| 99 | 103 | ||
| 104 | /* framebuffer lcd controller information */ | ||
| 105 | |||
| 106 | static struct s3c2410fb_mach_info rx3715_lcdcfg __initdata = { | ||
| 107 | .regs = { | ||
| 108 | .lcdcon1 = S3C2410_LCDCON1_TFT16BPP | \ | ||
| 109 | S3C2410_LCDCON1_TFT | \ | ||
| 110 | S3C2410_LCDCON1_CLKVAL(0x0C), | ||
| 111 | |||
| 112 | .lcdcon2 = S3C2410_LCDCON2_VBPD(5) | \ | ||
| 113 | S3C2410_LCDCON2_LINEVAL(319) | \ | ||
| 114 | S3C2410_LCDCON2_VFPD(6) | \ | ||
| 115 | S3C2410_LCDCON2_VSPW(2), | ||
| 116 | |||
| 117 | .lcdcon3 = S3C2410_LCDCON3_HBPD(35) | \ | ||
| 118 | S3C2410_LCDCON3_HOZVAL(239) | \ | ||
| 119 | S3C2410_LCDCON3_HFPD(35), | ||
| 120 | |||
| 121 | .lcdcon4 = S3C2410_LCDCON4_MVAL(0) | \ | ||
| 122 | S3C2410_LCDCON4_HSPW(7), | ||
| 123 | |||
| 124 | .lcdcon5 = S3C2410_LCDCON5_INVVLINE | | ||
| 125 | S3C2410_LCDCON5_FRM565 | | ||
| 126 | S3C2410_LCDCON5_HWSWP, | ||
| 127 | }, | ||
| 128 | |||
| 129 | .lpcsel = 0xf82, | ||
| 130 | |||
| 131 | .gpccon = 0xaa955699, | ||
| 132 | .gpccon_mask = 0xffc003cc, | ||
| 133 | .gpcup = 0x0000ffff, | ||
| 134 | .gpcup_mask = 0xffffffff, | ||
| 135 | |||
| 136 | .gpdcon = 0xaa95aaa1, | ||
| 137 | .gpdcon_mask = 0xffc0fff0, | ||
| 138 | .gpdup = 0x0000faff, | ||
| 139 | .gpdup_mask = 0xffffffff, | ||
| 140 | |||
| 141 | .fixed_syncs = 1, | ||
| 142 | .width = 240, | ||
| 143 | .height = 320, | ||
| 144 | |||
| 145 | .xres = { | ||
| 146 | .min = 240, | ||
| 147 | .max = 240, | ||
| 148 | .defval = 240, | ||
| 149 | }, | ||
| 150 | |||
| 151 | .yres = { | ||
| 152 | .max = 320, | ||
| 153 | .min = 320, | ||
| 154 | .defval = 320, | ||
| 155 | }, | ||
| 156 | |||
| 157 | .bpp = { | ||
| 158 | .min = 16, | ||
| 159 | .max = 16, | ||
| 160 | .defval = 16, | ||
| 161 | }, | ||
| 162 | }; | ||
| 163 | |||
| 100 | static struct platform_device *rx3715_devices[] __initdata = { | 164 | static struct platform_device *rx3715_devices[] __initdata = { |
| 101 | &s3c_device_usb, | 165 | &s3c_device_usb, |
| 102 | &s3c_device_lcd, | 166 | &s3c_device_lcd, |
| @@ -123,14 +187,12 @@ static void __init rx3715_init_irq(void) | |||
| 123 | s3c24xx_init_irq(); | 187 | s3c24xx_init_irq(); |
| 124 | } | 188 | } |
| 125 | 189 | ||
| 126 | #ifdef CONFIG_PM | ||
| 127 | static void __init rx3715_init_machine(void) | 190 | static void __init rx3715_init_machine(void) |
| 128 | { | 191 | { |
| 129 | s3c2410_pm_init(); | 192 | s3c2410_pm_init(); |
| 193 | s3c24xx_fb_set_platdata(&rx3715_lcdcfg); | ||
| 130 | } | 194 | } |
| 131 | #else | 195 | |
| 132 | #define rx3715_init_machine NULL | ||
| 133 | #endif | ||
| 134 | 196 | ||
| 135 | MACHINE_START(RX3715, "IPAQ-RX3715") | 197 | MACHINE_START(RX3715, "IPAQ-RX3715") |
| 136 | /* Maintainer: Ben Dooks <ben@fluff.org> */ | 198 | /* Maintainer: Ben Dooks <ben@fluff.org> */ |
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index c54e04c995ee..5568403e984d 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig | |||
| @@ -120,8 +120,8 @@ config CPU_ARM925T | |||
| 120 | 120 | ||
| 121 | # ARM926T | 121 | # ARM926T |
| 122 | config CPU_ARM926T | 122 | config CPU_ARM926T |
| 123 | bool "Support ARM926T processor" if ARCH_INTEGRATOR | 123 | bool "Support ARM926T processor" |
| 124 | depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX | 124 | depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB |
| 125 | default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX | 125 | default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX |
| 126 | select CPU_32v5 | 126 | select CPU_32v5 |
| 127 | select CPU_ABRT_EV5TJ | 127 | select CPU_ABRT_EV5TJ |
| @@ -242,7 +242,7 @@ config CPU_XSCALE | |||
| 242 | # ARMv6 | 242 | # ARMv6 |
| 243 | config CPU_V6 | 243 | config CPU_V6 |
| 244 | bool "Support ARM V6 processor" | 244 | bool "Support ARM V6 processor" |
| 245 | depends on ARCH_INTEGRATOR | 245 | depends on ARCH_INTEGRATOR || MACH_REALVIEW_EB |
| 246 | select CPU_32v6 | 246 | select CPU_32v6 |
| 247 | select CPU_ABRT_EV6 | 247 | select CPU_ABRT_EV6 |
| 248 | select CPU_CACHE_V6 | 248 | select CPU_CACHE_V6 |
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig index 5383e5e2d9b7..bac0da731ee3 100644 --- a/arch/i386/Kconfig +++ b/arch/i386/Kconfig | |||
| @@ -1042,8 +1042,3 @@ config X86_TRAMPOLINE | |||
| 1042 | bool | 1042 | bool |
| 1043 | depends on X86_SMP || (X86_VOYAGER && SMP) | 1043 | depends on X86_SMP || (X86_VOYAGER && SMP) |
| 1044 | default y | 1044 | default y |
| 1045 | |||
| 1046 | config PC | ||
| 1047 | bool | ||
| 1048 | depends on X86 && !EMBEDDED | ||
| 1049 | default y | ||
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index 9204be6eedb3..7c724ffa08bb 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c | |||
| @@ -803,7 +803,6 @@ no_apic: | |||
| 803 | 803 | ||
| 804 | void __init init_apic_mappings(void) | 804 | void __init init_apic_mappings(void) |
| 805 | { | 805 | { |
| 806 | unsigned int orig_apicid; | ||
| 807 | unsigned long apic_phys; | 806 | unsigned long apic_phys; |
| 808 | 807 | ||
| 809 | /* | 808 | /* |
| @@ -825,11 +824,8 @@ void __init init_apic_mappings(void) | |||
| 825 | * Fetch the APIC ID of the BSP in case we have a | 824 | * Fetch the APIC ID of the BSP in case we have a |
| 826 | * default configuration (or the MP table is broken). | 825 | * default configuration (or the MP table is broken). |
| 827 | */ | 826 | */ |
| 828 | orig_apicid = boot_cpu_physical_apicid; | 827 | if (boot_cpu_physical_apicid == -1U) |
| 829 | boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); | 828 | boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); |
| 830 | if ((orig_apicid != -1U) && (orig_apicid != boot_cpu_physical_apicid)) | ||
| 831 | printk(KERN_WARNING "Boot APIC ID in local APIC unexpected (%d vs %d)", | ||
| 832 | orig_apicid, boot_cpu_physical_apicid); | ||
| 833 | 829 | ||
| 834 | #ifdef CONFIG_X86_IO_APIC | 830 | #ifdef CONFIG_X86_IO_APIC |
| 835 | { | 831 | { |
| @@ -1259,81 +1255,40 @@ fastcall void smp_error_interrupt(struct pt_regs *regs) | |||
| 1259 | } | 1255 | } |
| 1260 | 1256 | ||
| 1261 | /* | 1257 | /* |
| 1262 | * This initializes the IO-APIC and APIC hardware. | 1258 | * This initializes the IO-APIC and APIC hardware if this is |
| 1259 | * a UP kernel. | ||
| 1263 | */ | 1260 | */ |
| 1264 | int __init APIC_init(void) | 1261 | int __init APIC_init_uniprocessor (void) |
| 1265 | { | 1262 | { |
| 1266 | if (enable_local_apic < 0) { | 1263 | if (enable_local_apic < 0) |
| 1267 | printk(KERN_INFO "APIC disabled\n"); | 1264 | clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); |
| 1268 | return -1; | ||
| 1269 | } | ||
| 1270 | 1265 | ||
| 1271 | /* See if we have a SMP configuration or have forced enabled | 1266 | if (!smp_found_config && !cpu_has_apic) |
| 1272 | * the local apic. | ||
| 1273 | */ | ||
| 1274 | if (!smp_found_config && !acpi_lapic && !cpu_has_apic) { | ||
| 1275 | enable_local_apic = -1; | ||
| 1276 | return -1; | 1267 | return -1; |
| 1277 | } | ||
| 1278 | 1268 | ||
| 1279 | /* | 1269 | /* |
| 1280 | * Complain if the BIOS pretends there is an apic. | 1270 | * Complain if the BIOS pretends there is one. |
| 1281 | * Then get out because we don't have an a local apic. | ||
| 1282 | */ | 1271 | */ |
| 1283 | if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { | 1272 | if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) { |
| 1284 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", | 1273 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", |
| 1285 | boot_cpu_physical_apicid); | 1274 | boot_cpu_physical_apicid); |
| 1286 | printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); | ||
| 1287 | enable_local_apic = -1; | ||
| 1288 | return -1; | 1275 | return -1; |
| 1289 | } | 1276 | } |
| 1290 | 1277 | ||
| 1291 | verify_local_APIC(); | 1278 | verify_local_APIC(); |
| 1292 | 1279 | ||
| 1293 | /* | ||
| 1294 | * Should not be necessary because the MP table should list the boot | ||
| 1295 | * CPU too, but we do it for the sake of robustness anyway. | ||
| 1296 | * Makes no sense to do this check in clustered apic mode, so skip it | ||
| 1297 | */ | ||
| 1298 | if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { | ||
| 1299 | printk("weird, boot CPU (#%d) not listed by the BIOS.\n", | ||
| 1300 | boot_cpu_physical_apicid); | ||
| 1301 | physid_set(boot_cpu_physical_apicid, phys_cpu_present_map); | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | /* | ||
| 1305 | * Switch from PIC to APIC mode. | ||
| 1306 | */ | ||
| 1307 | connect_bsp_APIC(); | 1280 | connect_bsp_APIC(); |
| 1308 | setup_local_APIC(); | ||
| 1309 | 1281 | ||
| 1310 | #ifdef CONFIG_X86_IO_APIC | 1282 | phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid); |
| 1311 | /* | ||
| 1312 | * Now start the IO-APICs | ||
| 1313 | */ | ||
| 1314 | if (smp_found_config && !skip_ioapic_setup && nr_ioapics) | ||
| 1315 | setup_IO_APIC(); | ||
| 1316 | #endif | ||
| 1317 | return 0; | ||
| 1318 | } | ||
| 1319 | 1283 | ||
| 1320 | void __init APIC_late_time_init(void) | 1284 | setup_local_APIC(); |
| 1321 | { | ||
| 1322 | /* Improve our loops per jiffy estimate */ | ||
| 1323 | loops_per_jiffy = ((1000 + HZ - 1)/HZ)*cpu_khz; | ||
| 1324 | boot_cpu_data.loops_per_jiffy = loops_per_jiffy; | ||
| 1325 | cpu_data[0].loops_per_jiffy = loops_per_jiffy; | ||
| 1326 | |||
| 1327 | /* setup_apic_nmi_watchdog doesn't work properly before cpu_khz is | ||
| 1328 | * initialized. So redo it here to ensure the boot cpu is setup | ||
| 1329 | * properly. | ||
| 1330 | */ | ||
| 1331 | if (nmi_watchdog == NMI_LOCAL_APIC) | ||
| 1332 | setup_apic_nmi_watchdog(); | ||
| 1333 | 1285 | ||
| 1334 | #ifdef CONFIG_X86_IO_APIC | 1286 | #ifdef CONFIG_X86_IO_APIC |
| 1335 | if (smp_found_config && !skip_ioapic_setup && nr_ioapics) | 1287 | if (smp_found_config) |
| 1336 | IO_APIC_late_time_init(); | 1288 | if (!skip_ioapic_setup && nr_ioapics) |
| 1289 | setup_IO_APIC(); | ||
| 1337 | #endif | 1290 | #endif |
| 1338 | setup_boot_APIC_clock(); | 1291 | setup_boot_APIC_clock(); |
| 1292 | |||
| 1293 | return 0; | ||
| 1339 | } | 1294 | } |
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c index d86f24909284..323ef8ab3244 100644 --- a/arch/i386/kernel/i8259.c +++ b/arch/i386/kernel/i8259.c | |||
| @@ -435,8 +435,4 @@ void __init init_IRQ(void) | |||
| 435 | setup_irq(FPU_IRQ, &fpu_irq); | 435 | setup_irq(FPU_IRQ, &fpu_irq); |
| 436 | 436 | ||
| 437 | irq_ctx_init(smp_processor_id()); | 437 | irq_ctx_init(smp_processor_id()); |
| 438 | |||
| 439 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 440 | APIC_init(); | ||
| 441 | #endif | ||
| 442 | } | 438 | } |
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 5a77c52b20a9..cc5d7ac5b2e7 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c | |||
| @@ -2387,15 +2387,11 @@ void __init setup_IO_APIC(void) | |||
| 2387 | sync_Arb_IDs(); | 2387 | sync_Arb_IDs(); |
| 2388 | setup_IO_APIC_irqs(); | 2388 | setup_IO_APIC_irqs(); |
| 2389 | init_IO_APIC_traps(); | 2389 | init_IO_APIC_traps(); |
| 2390 | check_timer(); | ||
| 2390 | if (!acpi_ioapic) | 2391 | if (!acpi_ioapic) |
| 2391 | print_IO_APIC(); | 2392 | print_IO_APIC(); |
| 2392 | } | 2393 | } |
| 2393 | 2394 | ||
| 2394 | void __init IO_APIC_late_time_init(void) | ||
| 2395 | { | ||
| 2396 | check_timer(); | ||
| 2397 | } | ||
| 2398 | |||
| 2399 | /* | 2395 | /* |
| 2400 | * Called after all the initialization is done. If we didnt find any | 2396 | * Called after all the initialization is done. If we didnt find any |
| 2401 | * APIC bugs then we can allow the modify fast path | 2397 | * APIC bugs then we can allow the modify fast path |
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index 5a2bbe0c4fff..01b618e73ecd 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c | |||
| @@ -1078,16 +1078,6 @@ void *xquad_portio; | |||
| 1078 | EXPORT_SYMBOL(xquad_portio); | 1078 | EXPORT_SYMBOL(xquad_portio); |
| 1079 | #endif | 1079 | #endif |
| 1080 | 1080 | ||
| 1081 | /* | ||
| 1082 | * Fall back to non SMP mode after errors. | ||
| 1083 | * | ||
| 1084 | */ | ||
| 1085 | static __init void disable_smp(void) | ||
| 1086 | { | ||
| 1087 | cpu_set(0, cpu_sibling_map[0]); | ||
| 1088 | cpu_set(0, cpu_core_map[0]); | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | static void __init smp_boot_cpus(unsigned int max_cpus) | 1081 | static void __init smp_boot_cpus(unsigned int max_cpus) |
| 1092 | { | 1082 | { |
| 1093 | int apicid, cpu, bit, kicked; | 1083 | int apicid, cpu, bit, kicked; |
| @@ -1100,6 +1090,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
| 1100 | printk("CPU%d: ", 0); | 1090 | printk("CPU%d: ", 0); |
| 1101 | print_cpu_info(&cpu_data[0]); | 1091 | print_cpu_info(&cpu_data[0]); |
| 1102 | 1092 | ||
| 1093 | boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID)); | ||
| 1103 | boot_cpu_logical_apicid = logical_smp_processor_id(); | 1094 | boot_cpu_logical_apicid = logical_smp_processor_id(); |
| 1104 | x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; | 1095 | x86_cpu_to_apicid[0] = boot_cpu_physical_apicid; |
| 1105 | 1096 | ||
| @@ -1111,27 +1102,68 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
| 1111 | cpus_clear(cpu_core_map[0]); | 1102 | cpus_clear(cpu_core_map[0]); |
| 1112 | cpu_set(0, cpu_core_map[0]); | 1103 | cpu_set(0, cpu_core_map[0]); |
| 1113 | 1104 | ||
| 1114 | map_cpu_to_logical_apicid(); | ||
| 1115 | |||
| 1116 | /* | 1105 | /* |
| 1117 | * If we couldn't find an SMP configuration at boot time, | 1106 | * If we couldn't find an SMP configuration at boot time, |
| 1118 | * get out of here now! | 1107 | * get out of here now! |
| 1119 | */ | 1108 | */ |
| 1120 | if (!smp_found_config && !acpi_lapic) { | 1109 | if (!smp_found_config && !acpi_lapic) { |
| 1121 | printk(KERN_NOTICE "SMP motherboard not detected.\n"); | 1110 | printk(KERN_NOTICE "SMP motherboard not detected.\n"); |
| 1122 | disable_smp(); | 1111 | smpboot_clear_io_apic_irqs(); |
| 1112 | phys_cpu_present_map = physid_mask_of_physid(0); | ||
| 1113 | if (APIC_init_uniprocessor()) | ||
| 1114 | printk(KERN_NOTICE "Local APIC not detected." | ||
| 1115 | " Using dummy APIC emulation.\n"); | ||
| 1116 | map_cpu_to_logical_apicid(); | ||
| 1117 | cpu_set(0, cpu_sibling_map[0]); | ||
| 1118 | cpu_set(0, cpu_core_map[0]); | ||
| 1119 | return; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | /* | ||
| 1123 | * Should not be necessary because the MP table should list the boot | ||
| 1124 | * CPU too, but we do it for the sake of robustness anyway. | ||
| 1125 | * Makes no sense to do this check in clustered apic mode, so skip it | ||
| 1126 | */ | ||
| 1127 | if (!check_phys_apicid_present(boot_cpu_physical_apicid)) { | ||
| 1128 | printk("weird, boot CPU (#%d) not listed by the BIOS.\n", | ||
| 1129 | boot_cpu_physical_apicid); | ||
| 1130 | physid_set(hard_smp_processor_id(), phys_cpu_present_map); | ||
| 1131 | } | ||
| 1132 | |||
| 1133 | /* | ||
| 1134 | * If we couldn't find a local APIC, then get out of here now! | ||
| 1135 | */ | ||
| 1136 | if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid]) && !cpu_has_apic) { | ||
| 1137 | printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", | ||
| 1138 | boot_cpu_physical_apicid); | ||
| 1139 | printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n"); | ||
| 1140 | smpboot_clear_io_apic_irqs(); | ||
| 1141 | phys_cpu_present_map = physid_mask_of_physid(0); | ||
| 1142 | cpu_set(0, cpu_sibling_map[0]); | ||
| 1143 | cpu_set(0, cpu_core_map[0]); | ||
| 1123 | return; | 1144 | return; |
| 1124 | } | 1145 | } |
| 1125 | 1146 | ||
| 1147 | verify_local_APIC(); | ||
| 1148 | |||
| 1126 | /* | 1149 | /* |
| 1127 | * If SMP should be disabled, then really disable it! | 1150 | * If SMP should be disabled, then really disable it! |
| 1128 | */ | 1151 | */ |
| 1129 | if (!max_cpus || (enable_local_apic < 0)) { | 1152 | if (!max_cpus) { |
| 1130 | printk(KERN_INFO "SMP mode deactivated.\n"); | 1153 | smp_found_config = 0; |
| 1131 | disable_smp(); | 1154 | printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n"); |
| 1155 | smpboot_clear_io_apic_irqs(); | ||
| 1156 | phys_cpu_present_map = physid_mask_of_physid(0); | ||
| 1157 | cpu_set(0, cpu_sibling_map[0]); | ||
| 1158 | cpu_set(0, cpu_core_map[0]); | ||
| 1132 | return; | 1159 | return; |
| 1133 | } | 1160 | } |
| 1134 | 1161 | ||
| 1162 | connect_bsp_APIC(); | ||
| 1163 | setup_local_APIC(); | ||
| 1164 | map_cpu_to_logical_apicid(); | ||
| 1165 | |||
| 1166 | |||
| 1135 | setup_portio_remap(); | 1167 | setup_portio_remap(); |
| 1136 | 1168 | ||
| 1137 | /* | 1169 | /* |
| @@ -1212,6 +1244,10 @@ static void __init smp_boot_cpus(unsigned int max_cpus) | |||
| 1212 | cpu_set(0, cpu_sibling_map[0]); | 1244 | cpu_set(0, cpu_sibling_map[0]); |
| 1213 | cpu_set(0, cpu_core_map[0]); | 1245 | cpu_set(0, cpu_core_map[0]); |
| 1214 | 1246 | ||
| 1247 | smpboot_setup_io_apic(); | ||
| 1248 | |||
| 1249 | setup_boot_APIC_clock(); | ||
| 1250 | |||
| 1215 | /* | 1251 | /* |
| 1216 | * Synchronize the TSC with the AP | 1252 | * Synchronize the TSC with the AP |
| 1217 | */ | 1253 | */ |
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c index 07471bba2dc6..41c5b2dc6200 100644 --- a/arch/i386/kernel/time.c +++ b/arch/i386/kernel/time.c | |||
| @@ -440,8 +440,8 @@ static int time_init_device(void) | |||
| 440 | 440 | ||
| 441 | device_initcall(time_init_device); | 441 | device_initcall(time_init_device); |
| 442 | 442 | ||
| 443 | extern void (*late_time_init)(void); | ||
| 444 | #ifdef CONFIG_HPET_TIMER | 443 | #ifdef CONFIG_HPET_TIMER |
| 444 | extern void (*late_time_init)(void); | ||
| 445 | /* Duplicate of time_init() below, with hpet_enable part added */ | 445 | /* Duplicate of time_init() below, with hpet_enable part added */ |
| 446 | static void __init hpet_time_init(void) | 446 | static void __init hpet_time_init(void) |
| 447 | { | 447 | { |
| @@ -458,11 +458,6 @@ static void __init hpet_time_init(void) | |||
| 458 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); | 458 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); |
| 459 | 459 | ||
| 460 | time_init_hook(); | 460 | time_init_hook(); |
| 461 | |||
| 462 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 463 | if (enable_local_apic >= 0) | ||
| 464 | APIC_late_time_init(); | ||
| 465 | #endif | ||
| 466 | } | 461 | } |
| 467 | #endif | 462 | #endif |
| 468 | 463 | ||
| @@ -487,9 +482,4 @@ void __init time_init(void) | |||
| 487 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); | 482 | printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name); |
| 488 | 483 | ||
| 489 | time_init_hook(); | 484 | time_init_hook(); |
| 490 | |||
| 491 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 492 | if (enable_local_apic >= 0) | ||
| 493 | late_time_init = APIC_late_time_init; | ||
| 494 | #endif | ||
| 495 | } | 485 | } |
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c index 330fd2b68075..3984226a8b98 100644 --- a/arch/i386/pci/fixup.c +++ b/arch/i386/pci/fixup.c | |||
| @@ -398,7 +398,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video); | |||
| 398 | */ | 398 | */ |
| 399 | static u16 toshiba_line_size; | 399 | static u16 toshiba_line_size; |
| 400 | 400 | ||
| 401 | static struct dmi_system_id __devinit toshiba_ohci1394_dmi_table[] = { | 401 | static struct dmi_system_id __devinitdata toshiba_ohci1394_dmi_table[] = { |
| 402 | { | 402 | { |
| 403 | .ident = "Toshiba PS5 based laptop", | 403 | .ident = "Toshiba PS5 based laptop", |
| 404 | .matches = { | 404 | .matches = { |
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c index 47a5f6ab4879..da631c114fd1 100644 --- a/drivers/char/watchdog/mpcore_wdt.c +++ b/drivers/char/watchdog/mpcore_wdt.c | |||
| @@ -396,6 +396,7 @@ static int __devexit mpcore_wdt_remove(struct device *dev) | |||
| 396 | } | 396 | } |
| 397 | 397 | ||
| 398 | static struct device_driver mpcore_wdt_driver = { | 398 | static struct device_driver mpcore_wdt_driver = { |
| 399 | .owner = THIS_MODULE, | ||
| 399 | .name = "mpcore_wdt", | 400 | .name = "mpcore_wdt", |
| 400 | .bus = &platform_bus_type, | 401 | .bus = &platform_bus_type, |
| 401 | .probe = mpcore_wdt_probe, | 402 | .probe = mpcore_wdt_probe, |
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c index 04e0d7e9680d..119b3c541d95 100644 --- a/drivers/char/watchdog/mv64x60_wdt.c +++ b/drivers/char/watchdog/mv64x60_wdt.c | |||
| @@ -213,6 +213,7 @@ static int __devexit mv64x60_wdt_remove(struct device *dev) | |||
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | static struct device_driver mv64x60_wdt_driver = { | 215 | static struct device_driver mv64x60_wdt_driver = { |
| 216 | .owner = THIS_MODULE, | ||
| 216 | .name = MV64x60_WDT_NAME, | 217 | .name = MV64x60_WDT_NAME, |
| 217 | .bus = &platform_bus_type, | 218 | .bus = &platform_bus_type, |
| 218 | .probe = mv64x60_wdt_probe, | 219 | .probe = mv64x60_wdt_probe, |
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c index 5308e5c8f29a..d9ef55bdf88a 100644 --- a/drivers/char/watchdog/pcwd_pci.c +++ b/drivers/char/watchdog/pcwd_pci.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Berkshire PCI-PC Watchdog Card Driver | 2 | * Berkshire PCI-PC Watchdog Card Driver |
| 3 | * | 3 | * |
| 4 | * (c) Copyright 2003 Wim Van Sebroeck <wim@iguana.be>. | 4 | * (c) Copyright 2003-2005 Wim Van Sebroeck <wim@iguana.be>. |
| 5 | * | 5 | * |
| 6 | * Based on source code of the following authors: | 6 | * Based on source code of the following authors: |
| 7 | * Ken Hollis <kenji@bitgate.com>, | 7 | * Ken Hollis <kenji@bitgate.com>, |
| @@ -21,7 +21,9 @@ | |||
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | /* | 23 | /* |
| 24 | * A bells and whistles driver is available from http://www.pcwd.de/ | 24 | * A bells and whistles driver is available from: |
| 25 | * http://www.kernel.org/pub/linux/kernel/people/wim/pcwd/pcwd_pci/ | ||
| 26 | * | ||
| 25 | * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ | 27 | * More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/ |
| 26 | */ | 28 | */ |
| 27 | 29 | ||
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c index e7e20a6d64b0..751cb77b0715 100644 --- a/drivers/char/watchdog/s3c2410_wdt.c +++ b/drivers/char/watchdog/s3c2410_wdt.c | |||
| @@ -497,6 +497,7 @@ static int s3c2410wdt_resume(struct device *dev) | |||
| 497 | 497 | ||
| 498 | 498 | ||
| 499 | static struct device_driver s3c2410wdt_driver = { | 499 | static struct device_driver s3c2410wdt_driver = { |
| 500 | .owner = THIS_MODULE, | ||
| 500 | .name = "s3c2410-wdt", | 501 | .name = "s3c2410-wdt", |
| 501 | .bus = &platform_bus_type, | 502 | .bus = &platform_bus_type, |
| 502 | .probe = s3c2410wdt_probe, | 503 | .probe = s3c2410wdt_probe, |
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index b5d821015421..d15ca9a3986f 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c | |||
| @@ -359,5 +359,5 @@ module_exit(wdt_exit); | |||
| 359 | 359 | ||
| 360 | MODULE_LICENSE("GPL"); | 360 | MODULE_LICENSE("GPL"); |
| 361 | MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>"); | 361 | MODULE_AUTHOR("Pádraig Brady <P@draigBrady.com>"); |
| 362 | MODULE_DESCRIPTION("w38627hf WDT driver"); | 362 | MODULE_DESCRIPTION("w83627hf WDT driver"); |
| 363 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 363 | MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 13752bcb2afd..cfae4ad00fae 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c | |||
| @@ -11,7 +11,7 @@ | |||
| 11 | * | 11 | * |
| 12 | * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund | 12 | * Copyright (C) 1995-1997 Simon G. Vogl, 1998-2000 Hans Berglund |
| 13 | * | 13 | * |
| 14 | * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>, | 14 | * And which acknowledged Kyösti Mälkki <kmalkki@cc.hut.fi>, |
| 15 | * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com> | 15 | * Frodo Looijaard <frodol@dds.nl>, Martin Bailey<mbailey@littlefeet-inc.com> |
| 16 | * | 16 | * |
| 17 | * Major cleanup by Deepak Saxena <dsaxena@plexity.net>, 01/2005: | 17 | * Major cleanup by Deepak Saxena <dsaxena@plexity.net>, 01/2005: |
| @@ -184,7 +184,7 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, | |||
| 184 | do { | 184 | do { |
| 185 | interrupted = wait_event_interruptible_timeout ( | 185 | interrupted = wait_event_interruptible_timeout ( |
| 186 | iop3xx_adap->waitq, | 186 | iop3xx_adap->waitq, |
| 187 | (done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )), | 187 | (done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )), |
| 188 | 1 * HZ; | 188 | 1 * HZ; |
| 189 | ); | 189 | ); |
| 190 | if ((rc = iop3xx_i2c_error(sr)) < 0) { | 190 | if ((rc = iop3xx_i2c_error(sr)) < 0) { |
| @@ -472,9 +472,10 @@ iop3xx_i2c_probe(struct device *dev) | |||
| 472 | goto release_region; | 472 | goto release_region; |
| 473 | } | 473 | } |
| 474 | 474 | ||
| 475 | res = request_irq(platform_get_irq(pdev, 0), iop3xx_i2c_irq_handler, 0, | 475 | ret = request_irq(platform_get_irq(pdev, 0), iop3xx_i2c_irq_handler, 0, |
| 476 | pdev->name, adapter_data); | 476 | pdev->name, adapter_data); |
| 477 | if (res) { | 477 | |
| 478 | if (ret) { | ||
| 478 | ret = -EIO; | 479 | ret = -EIO; |
| 479 | goto unmap; | 480 | goto unmap; |
| 480 | } | 481 | } |
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 571a68691a4a..4a917748fd9f 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig | |||
| @@ -13,11 +13,11 @@ menuconfig INPUT_KEYBOARD | |||
| 13 | if INPUT_KEYBOARD | 13 | if INPUT_KEYBOARD |
| 14 | 14 | ||
| 15 | config KEYBOARD_ATKBD | 15 | config KEYBOARD_ATKBD |
| 16 | tristate "AT keyboard" if !PC | 16 | tristate "AT keyboard" if !X86_PC |
| 17 | default y | 17 | default y |
| 18 | select SERIO | 18 | select SERIO |
| 19 | select SERIO_LIBPS2 | 19 | select SERIO_LIBPS2 |
| 20 | select SERIO_I8042 if PC | 20 | select SERIO_I8042 if X86_PC |
| 21 | select SERIO_GSCPS2 if GSC | 21 | select SERIO_GSCPS2 if GSC |
| 22 | help | 22 | help |
| 23 | Say Y here if you want to use a standard AT or PS/2 keyboard. Usually | 23 | Say Y here if you want to use a standard AT or PS/2 keyboard. Usually |
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 537154dd7a87..574b18a523af 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig | |||
| @@ -17,7 +17,7 @@ config MOUSE_PS2 | |||
| 17 | default y | 17 | default y |
| 18 | select SERIO | 18 | select SERIO |
| 19 | select SERIO_LIBPS2 | 19 | select SERIO_LIBPS2 |
| 20 | select SERIO_I8042 if PC | 20 | select SERIO_I8042 if X86_PC |
| 21 | select SERIO_GSCPS2 if GSC | 21 | select SERIO_GSCPS2 if GSC |
| 22 | ---help--- | 22 | ---help--- |
| 23 | Say Y here if you have a PS/2 mouse connected to your system. This | 23 | Say Y here if you have a PS/2 mouse connected to your system. This |
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 3d50e953faaa..877891a29aaa 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c | |||
| @@ -26,11 +26,11 @@ | |||
| 26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
| 27 | #include <linux/crc32.h> | 27 | #include <linux/crc32.h> |
| 28 | #include <linux/bitops.h> | 28 | #include <linux/bitops.h> |
| 29 | #include <linux/platform_device.h> | ||
| 29 | 30 | ||
| 30 | #include <asm/system.h> | ||
| 31 | #include <asm/irq.h> | ||
| 32 | #include <asm/hardware.h> | 31 | #include <asm/hardware.h> |
| 33 | #include <asm/io.h> | 32 | #include <asm/io.h> |
| 33 | #include <asm/system.h> | ||
| 34 | 34 | ||
| 35 | #define TX_BUFFERS 15 | 35 | #define TX_BUFFERS 15 |
| 36 | #define RX_BUFFERS 25 | 36 | #define RX_BUFFERS 25 |
| @@ -280,10 +280,13 @@ static void am79c961_timer(unsigned long data) | |||
| 280 | lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; | 280 | lnkstat = read_ireg(dev->base_addr, ISALED0) & ISALED0_LNKST; |
| 281 | carrier = netif_carrier_ok(dev); | 281 | carrier = netif_carrier_ok(dev); |
| 282 | 282 | ||
| 283 | if (lnkstat && !carrier) | 283 | if (lnkstat && !carrier) { |
| 284 | netif_carrier_on(dev); | 284 | netif_carrier_on(dev); |
| 285 | else if (!lnkstat && carrier) | 285 | printk("%s: link up\n", dev->name); |
| 286 | } else if (!lnkstat && carrier) { | ||
| 286 | netif_carrier_off(dev); | 287 | netif_carrier_off(dev); |
| 288 | printk("%s: link down\n", dev->name); | ||
| 289 | } | ||
| 287 | 290 | ||
| 288 | mod_timer(&priv->timer, jiffies + msecs_to_jiffies(500)); | 291 | mod_timer(&priv->timer, jiffies + msecs_to_jiffies(500)); |
| 289 | } | 292 | } |
| @@ -665,17 +668,25 @@ static void __init am79c961_banner(void) | |||
| 665 | printk(KERN_INFO "%s", version); | 668 | printk(KERN_INFO "%s", version); |
| 666 | } | 669 | } |
| 667 | 670 | ||
| 668 | static int __init am79c961_init(void) | 671 | static int __init am79c961_probe(struct device *_dev) |
| 669 | { | 672 | { |
| 673 | struct platform_device *pdev = to_platform_device(_dev); | ||
| 674 | struct resource *res; | ||
| 670 | struct net_device *dev; | 675 | struct net_device *dev; |
| 671 | struct dev_priv *priv; | 676 | struct dev_priv *priv; |
| 672 | int i, ret; | 677 | int i, ret; |
| 673 | 678 | ||
| 679 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
| 680 | if (!res) | ||
| 681 | return -ENODEV; | ||
| 682 | |||
| 674 | dev = alloc_etherdev(sizeof(struct dev_priv)); | 683 | dev = alloc_etherdev(sizeof(struct dev_priv)); |
| 675 | ret = -ENOMEM; | 684 | ret = -ENOMEM; |
| 676 | if (!dev) | 685 | if (!dev) |
| 677 | goto out; | 686 | goto out; |
| 678 | 687 | ||
| 688 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
| 689 | |||
| 679 | priv = netdev_priv(dev); | 690 | priv = netdev_priv(dev); |
| 680 | 691 | ||
| 681 | /* | 692 | /* |
| @@ -683,8 +694,8 @@ static int __init am79c961_init(void) | |||
| 683 | * The PNP initialisation should have been | 694 | * The PNP initialisation should have been |
| 684 | * done by the ether bootp loader. | 695 | * done by the ether bootp loader. |
| 685 | */ | 696 | */ |
| 686 | dev->base_addr = 0x220; | 697 | dev->base_addr = res->start; |
| 687 | dev->irq = IRQ_EBSA110_ETHERNET; | 698 | dev->irq = platform_get_irq(pdev, 0); |
| 688 | 699 | ||
| 689 | ret = -ENODEV; | 700 | ret = -ENODEV; |
| 690 | if (!request_region(dev->base_addr, 0x18, dev->name)) | 701 | if (!request_region(dev->base_addr, 0x18, dev->name)) |
| @@ -705,11 +716,11 @@ static int __init am79c961_init(void) | |||
| 705 | inb(dev->base_addr + 4) != 0x2b) | 716 | inb(dev->base_addr + 4) != 0x2b) |
| 706 | goto release; | 717 | goto release; |
| 707 | 718 | ||
| 708 | am79c961_banner(); | ||
| 709 | |||
| 710 | for (i = 0; i < 6; i++) | 719 | for (i = 0; i < 6; i++) |
| 711 | dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff; | 720 | dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff; |
| 712 | 721 | ||
| 722 | am79c961_banner(); | ||
| 723 | |||
| 713 | spin_lock_init(&priv->chip_lock); | 724 | spin_lock_init(&priv->chip_lock); |
| 714 | init_timer(&priv->timer); | 725 | init_timer(&priv->timer); |
| 715 | priv->timer.data = (unsigned long)dev; | 726 | priv->timer.data = (unsigned long)dev; |
| @@ -732,6 +743,7 @@ static int __init am79c961_init(void) | |||
| 732 | if (ret == 0) { | 743 | if (ret == 0) { |
| 733 | printk(KERN_INFO "%s: ether address ", dev->name); | 744 | printk(KERN_INFO "%s: ether address ", dev->name); |
| 734 | 745 | ||
| 746 | /* Retrive and print the ethernet address. */ | ||
| 735 | for (i = 0; i < 6; i++) | 747 | for (i = 0; i < 6; i++) |
| 736 | printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); | 748 | printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]); |
| 737 | 749 | ||
| @@ -746,4 +758,15 @@ out: | |||
| 746 | return ret; | 758 | return ret; |
| 747 | } | 759 | } |
| 748 | 760 | ||
| 761 | static struct device_driver am79c961_driver = { | ||
| 762 | .name = "am79c961", | ||
| 763 | .bus = &platform_bus_type, | ||
| 764 | .probe = am79c961_probe, | ||
| 765 | }; | ||
| 766 | |||
| 767 | static int __init am79c961_init(void) | ||
| 768 | { | ||
| 769 | return driver_register(&am79c961_driver); | ||
| 770 | } | ||
| 771 | |||
| 749 | __initcall(am79c961_init); | 772 | __initcall(am79c961_init); |
diff --git a/drivers/net/arm/am79c961a.h b/drivers/net/arm/am79c961a.h index 1e9b05050cbe..6a49ac7f6d46 100644 --- a/drivers/net/arm/am79c961a.h +++ b/drivers/net/arm/am79c961a.h | |||
| @@ -143,6 +143,4 @@ struct dev_priv { | |||
| 143 | struct timer_list timer; | 143 | struct timer_list timer; |
| 144 | }; | 144 | }; |
| 145 | 145 | ||
| 146 | extern int am79c961_probe (struct net_device *dev); | ||
| 147 | |||
| 148 | #endif | 146 | #endif |
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 00d6a6657ebc..a440ea38efaa 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c | |||
| @@ -180,12 +180,22 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne | |||
| 180 | return; | 180 | return; |
| 181 | } | 181 | } |
| 182 | count = min(pc->sg->length - pc->b_count, bcount); | 182 | count = min(pc->sg->length - pc->b_count, bcount); |
| 183 | buf = kmap_atomic(pc->sg->page, KM_IRQ0); | 183 | if (PageHighMem(pc->sg->page)) { |
| 184 | drive->hwif->atapi_input_bytes(drive, | 184 | unsigned long flags; |
| 185 | buf + pc->b_count + pc->sg->offset, count); | 185 | |
| 186 | kunmap_atomic(buf, KM_IRQ0); | 186 | local_irq_save(flags); |
| 187 | bcount -= count; | 187 | buf = kmap_atomic(pc->sg->page, KM_IRQ0) + |
| 188 | pc->b_count += count; | 188 | pc->sg->offset; |
| 189 | drive->hwif->atapi_input_bytes(drive, | ||
| 190 | buf + pc->b_count, count); | ||
| 191 | kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); | ||
| 192 | local_irq_restore(flags); | ||
| 193 | } else { | ||
| 194 | buf = page_address(pc->sg->page) + pc->sg->offset; | ||
| 195 | drive->hwif->atapi_input_bytes(drive, | ||
| 196 | buf + pc->b_count, count); | ||
| 197 | } | ||
| 198 | bcount -= count; pc->b_count += count; | ||
| 189 | if (pc->b_count == pc->sg->length) { | 199 | if (pc->b_count == pc->sg->length) { |
| 190 | pc->sg++; | 200 | pc->sg++; |
| 191 | pc->b_count = 0; | 201 | pc->b_count = 0; |
| @@ -205,12 +215,22 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign | |||
| 205 | return; | 215 | return; |
| 206 | } | 216 | } |
| 207 | count = min(pc->sg->length - pc->b_count, bcount); | 217 | count = min(pc->sg->length - pc->b_count, bcount); |
| 208 | buf = kmap_atomic(pc->sg->page, KM_IRQ0); | 218 | if (PageHighMem(pc->sg->page)) { |
| 209 | drive->hwif->atapi_output_bytes(drive, | 219 | unsigned long flags; |
| 210 | buf + pc->b_count + pc->sg->offset, count); | 220 | |
| 211 | kunmap_atomic(buf, KM_IRQ0); | 221 | local_irq_save(flags); |
| 212 | bcount -= count; | 222 | buf = kmap_atomic(pc->sg->page, KM_IRQ0) + |
| 213 | pc->b_count += count; | 223 | pc->sg->offset; |
| 224 | drive->hwif->atapi_output_bytes(drive, | ||
| 225 | buf + pc->b_count, count); | ||
| 226 | kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); | ||
| 227 | local_irq_restore(flags); | ||
| 228 | } else { | ||
| 229 | buf = page_address(pc->sg->page) + pc->sg->offset; | ||
| 230 | drive->hwif->atapi_output_bytes(drive, | ||
| 231 | buf + pc->b_count, count); | ||
| 232 | } | ||
| 233 | bcount -= count; pc->b_count += count; | ||
| 214 | if (pc->b_count == pc->sg->length) { | 234 | if (pc->b_count == pc->sg->length) { |
| 215 | pc->sg++; | 235 | pc->sg++; |
| 216 | pc->b_count = 0; | 236 | pc->b_count = 0; |
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 401d94a7fe2e..0745ce782974 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c | |||
| @@ -1967,7 +1967,9 @@ uart_report_port(struct uart_driver *drv, struct uart_port *port) | |||
| 1967 | break; | 1967 | break; |
| 1968 | } | 1968 | } |
| 1969 | 1969 | ||
| 1970 | printk(KERN_INFO "%s%d at %s (irq = %d) is a %s\n", | 1970 | printk(KERN_INFO "%s%s%s%d at %s (irq = %d) is a %s\n", |
| 1971 | port->dev ? port->dev->bus_id : "", | ||
| 1972 | port->dev ? ": " : "", | ||
| 1971 | drv->dev_name, port->line, address, port->irq, uart_type(port)); | 1973 | drv->dev_name, port->line, address, port->irq, uart_type(port)); |
| 1972 | } | 1974 | } |
| 1973 | 1975 | ||
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index b7fd3f644e1e..b1aa350fd32f 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c | |||
| @@ -138,11 +138,23 @@ reset_needed: | |||
| 138 | } | 138 | } |
| 139 | EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); | 139 | EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc); |
| 140 | 140 | ||
| 141 | static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask) | ||
| 142 | { | ||
| 143 | u16 cmd; | ||
| 144 | return !pci_read_config_word(pdev, PCI_COMMAND, &cmd) && (cmd & mask); | ||
| 145 | } | ||
| 146 | |||
| 147 | #define pio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_IO) | ||
| 148 | #define mmio_enabled(dev) io_type_enabled(dev, PCI_COMMAND_MEMORY) | ||
| 149 | |||
| 141 | static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) | 150 | static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) |
| 142 | { | 151 | { |
| 143 | unsigned long base = 0; | 152 | unsigned long base = 0; |
| 144 | int i; | 153 | int i; |
| 145 | 154 | ||
| 155 | if (!pio_enabled(pdev)) | ||
| 156 | return; | ||
| 157 | |||
| 146 | for (i = 0; i < PCI_ROM_RESOURCE; i++) | 158 | for (i = 0; i < PCI_ROM_RESOURCE; i++) |
| 147 | if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { | 159 | if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) { |
| 148 | base = pci_resource_start(pdev, i); | 160 | base = pci_resource_start(pdev, i); |
| @@ -153,12 +165,20 @@ static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev) | |||
| 153 | uhci_check_and_reset_hc(pdev, base); | 165 | uhci_check_and_reset_hc(pdev, base); |
| 154 | } | 166 | } |
| 155 | 167 | ||
| 168 | static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx) | ||
| 169 | { | ||
| 170 | return pci_resource_start(pdev, idx) && mmio_enabled(pdev); | ||
| 171 | } | ||
| 172 | |||
| 156 | static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) | 173 | static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) |
| 157 | { | 174 | { |
| 158 | void __iomem *base; | 175 | void __iomem *base; |
| 159 | int wait_time; | 176 | int wait_time; |
| 160 | u32 control; | 177 | u32 control; |
| 161 | 178 | ||
| 179 | if (!mmio_resource_enabled(pdev, 0)) | ||
| 180 | return; | ||
| 181 | |||
| 162 | base = ioremap_nocache(pci_resource_start(pdev, 0), | 182 | base = ioremap_nocache(pci_resource_start(pdev, 0), |
| 163 | pci_resource_len(pdev, 0)); | 183 | pci_resource_len(pdev, 0)); |
| 164 | if (base == NULL) return; | 184 | if (base == NULL) return; |
| @@ -201,6 +221,9 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) | |||
| 201 | u32 hcc_params, val, temp; | 221 | u32 hcc_params, val, temp; |
| 202 | u8 cap_length; | 222 | u8 cap_length; |
| 203 | 223 | ||
| 224 | if (!mmio_resource_enabled(pdev, 0)) | ||
| 225 | return; | ||
| 226 | |||
| 204 | base = ioremap_nocache(pci_resource_start(pdev, 0), | 227 | base = ioremap_nocache(pci_resource_start(pdev, 0), |
| 205 | pci_resource_len(pdev, 0)); | 228 | pci_resource_len(pdev, 0)); |
| 206 | if (base == NULL) return; | 229 | if (base == NULL) return; |
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS index 72fdc10dfdd7..8848e4dfa026 100644 --- a/fs/cifs/AUTHORS +++ b/fs/cifs/AUTHORS | |||
| @@ -32,6 +32,10 @@ Domen Puncer | |||
| 32 | Jesper Juhl (in particular for lots of whitespace/formatting cleanup) | 32 | Jesper Juhl (in particular for lots of whitespace/formatting cleanup) |
| 33 | Vince Negri and Dave Stahl (for finding an important caching bug) | 33 | Vince Negri and Dave Stahl (for finding an important caching bug) |
| 34 | Adrian Bunk (kcalloc cleanups) | 34 | Adrian Bunk (kcalloc cleanups) |
| 35 | Miklos Szeredi | ||
| 36 | Kazeon team for various fixes especially for 2.4 version. | ||
| 37 | Asser Ferno (Change Notify support) | ||
| 38 | Shaggy (Dave Kleikamp) for inumerable small fs suggestions and some good cleanup | ||
| 35 | 39 | ||
| 36 | Test case and Bug Report contributors | 40 | Test case and Bug Report contributors |
| 37 | ------------------------------------- | 41 | ------------------------------------- |
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 3196d4c4eed3..5bab24f59053 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES | |||
| @@ -1,8 +1,52 @@ | |||
| 1 | Version 1.39 | ||
| 2 | ------------ | ||
| 3 | Defer close of a file handle slightly if pending writes depend on that file handle | ||
| 4 | (this reduces the EBADF bad file handle errors that can be logged under heavy | ||
| 5 | stress on writes). | ||
| 6 | |||
| 7 | Version 1.38 | ||
| 8 | ------------ | ||
| 9 | Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket) | ||
| 10 | to be smaller at first (but increasing) so large write performance performance | ||
| 11 | over GigE is better. Do not hang thread on illegal byte range lock response | ||
| 12 | from Windows (Windows can send an RFC1001 size which does not match smb size) by | ||
| 13 | allowing an SMBs TCP length to be up to a few bytes longer than it should be. | ||
| 14 | wsize and rsize can now be larger than negotiated buffer size if server | ||
| 15 | supports large readx/writex, even when directio mount flag not specified. | ||
| 16 | Write size will in many cases now be 16K instead of 4K which greatly helps | ||
| 17 | file copy performance on lightly loaded networks. Fix oops in dnotify | ||
| 18 | when experimental config flag enabled. Make cifsFYI more granular. | ||
| 19 | |||
| 20 | Version 1.37 | ||
| 21 | ------------ | ||
| 22 | Fix readdir caching when unlink removes file in current search buffer, | ||
| 23 | and this is followed by a rewind search to just before the deleted entry. | ||
| 24 | Do not attempt to set ctime unless atime and/or mtime change requested | ||
| 25 | (most servers throw it away anyway). Fix length check of received smbs | ||
| 26 | to be more accurate. Fix big endian problem with mapchars mount option, | ||
| 27 | and with a field returned by statfs. | ||
| 28 | |||
| 29 | Version 1.36 | ||
| 30 | ------------ | ||
| 31 | Add support for mounting to older pre-CIFS servers such as Windows9x and ME. | ||
| 32 | For these older servers, add option for passing netbios name of server in | ||
| 33 | on mount (servernetbiosname). Add suspend support for power management, to | ||
| 34 | avoid cifsd thread preventing software suspend from working. | ||
| 35 | Add mount option for disabling the default behavior of sending byte range lock | ||
| 36 | requests to the server (necessary for certain applications which break with | ||
| 37 | mandatory lock behavior such as Evolution), and also mount option for | ||
| 38 | requesting case insensitive matching for path based requests (requesting | ||
| 39 | case sensitive is the default). | ||
| 40 | |||
| 1 | Version 1.35 | 41 | Version 1.35 |
| 2 | ------------ | 42 | ------------ |
| 3 | Add writepage performance improvements. Fix path name conversions | 43 | Add writepage performance improvements. Fix path name conversions |
| 4 | for long filenames on mounts which were done with "mapchars" mount option | 44 | for long filenames on mounts which were done with "mapchars" mount option |
| 5 | specified. | 45 | specified. Ensure multiplex ids do not collide. Fix case in which |
| 46 | rmmod can oops if done soon after last unmount. Fix truncated | ||
| 47 | search (readdir) output when resume filename was a long filename. | ||
| 48 | Fix filename conversion when mapchars mount option was specified and | ||
| 49 | filename was a long filename. | ||
| 6 | 50 | ||
| 7 | Version 1.34 | 51 | Version 1.34 |
| 8 | ------------ | 52 | ------------ |
| @@ -11,7 +55,7 @@ Do not oops if root user kills cifs oplock kernel thread or | |||
| 11 | kills the cifsd thread (NB: killing the cifs kernel threads is not | 55 | kills the cifsd thread (NB: killing the cifs kernel threads is not |
| 12 | recommended, unmount and rmmod cifs will kill them when they are | 56 | recommended, unmount and rmmod cifs will kill them when they are |
| 13 | no longer needed). Fix readdir to ASCII servers (ie older servers | 57 | no longer needed). Fix readdir to ASCII servers (ie older servers |
| 14 | which do not support Unicode) and also require asterik. | 58 | which do not support Unicode) and also require asterisk. |
| 15 | Fix out of memory case in which data could be written one page | 59 | Fix out of memory case in which data could be written one page |
| 16 | off in the page cache. | 60 | off in the page cache. |
| 17 | 61 | ||
| @@ -101,7 +145,7 @@ improperly zeroed buffer in CIFS Unix extensions set times call. | |||
| 101 | 145 | ||
| 102 | Version 1.25 | 146 | Version 1.25 |
| 103 | ------------ | 147 | ------------ |
| 104 | Fix internationlization problem in cifs readdir with filenames that map to | 148 | Fix internationalization problem in cifs readdir with filenames that map to |
| 105 | longer UTF8 strings than the string on the wire was in Unicode. Add workaround | 149 | longer UTF8 strings than the string on the wire was in Unicode. Add workaround |
| 106 | for readdir to netapp servers. Fix search rewind (seek into readdir to return | 150 | for readdir to netapp servers. Fix search rewind (seek into readdir to return |
| 107 | non-consecutive entries). Do not do readdir when server negotiates | 151 | non-consecutive entries). Do not do readdir when server negotiates |
| @@ -276,7 +320,7 @@ Fix caching problem when files opened by multiple clients in which | |||
| 276 | page cache could contain stale data, and write through did | 320 | page cache could contain stale data, and write through did |
| 277 | not occur often enough while file was still open when read ahead | 321 | not occur often enough while file was still open when read ahead |
| 278 | (read oplock) not allowed. Treat "sep=" when first mount option | 322 | (read oplock) not allowed. Treat "sep=" when first mount option |
| 279 | as an overrride of comma as the default separator between mount | 323 | as an override of comma as the default separator between mount |
| 280 | options. | 324 | options. |
| 281 | 325 | ||
| 282 | Version 1.01 | 326 | Version 1.01 |
| @@ -286,7 +330,7 @@ Allow passwords longer than 16 bytes. Allow null password string. | |||
| 286 | Version 1.00 | 330 | Version 1.00 |
| 287 | ------------ | 331 | ------------ |
| 288 | Gracefully clean up failed mounts when attempting to mount to servers such as | 332 | Gracefully clean up failed mounts when attempting to mount to servers such as |
| 289 | Windows 98 that terminate tcp sessions during prototocol negotiation. Handle | 333 | Windows 98 that terminate tcp sessions during protocol negotiation. Handle |
| 290 | embedded commas in mount parsing of passwords. | 334 | embedded commas in mount parsing of passwords. |
| 291 | 335 | ||
| 292 | Version 0.99 | 336 | Version 0.99 |
| @@ -295,7 +339,7 @@ Invalidate local inode cached pages on oplock break and when last file | |||
| 295 | instance is closed so that the client does not continue using stale local | 339 | instance is closed so that the client does not continue using stale local |
| 296 | copy rather than later modified server copy of file. Do not reconnect | 340 | copy rather than later modified server copy of file. Do not reconnect |
| 297 | when server drops the tcp session prematurely before negotiate | 341 | when server drops the tcp session prematurely before negotiate |
| 298 | protocol response. Fix oops in roepen_file when dentry freed. Allow | 342 | protocol response. Fix oops in reopen_file when dentry freed. Allow |
| 299 | the support for CIFS Unix Extensions to be disabled via proc interface. | 343 | the support for CIFS Unix Extensions to be disabled via proc interface. |
| 300 | 344 | ||
| 301 | Version 0.98 | 345 | Version 0.98 |
| @@ -637,7 +681,7 @@ versions of 2.4 kernel (now builds and works again on kernels at least as early | |||
| 637 | Version 0.41 | 681 | Version 0.41 |
| 638 | ------------ | 682 | ------------ |
| 639 | Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked | 683 | Various minor fixes for Connectathon Posix "basic" file i/o test suite. Directory caching fixed so hardlinked |
| 640 | files now return the correct rumber of links on fstat as they are repeatedly linked and unlinked. | 684 | files now return the correct number of links on fstat as they are repeatedly linked and unlinked. |
| 641 | 685 | ||
| 642 | Version 0.40 | 686 | Version 0.40 |
| 643 | ------------ | 687 | ------------ |
| @@ -704,7 +748,7 @@ session) | |||
| 704 | and cleaned them up and made them more consistent with other cifs functions. | 748 | and cleaned them up and made them more consistent with other cifs functions. |
| 705 | 749 | ||
| 706 | 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways | 750 | 7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways |
| 707 | (with or without Unix exentions) but FindNext and QueryPathInfo with the Unix extensions are not completed, | 751 | (with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed, |
| 708 | nor is the symlink support using the Unix extensions | 752 | nor is the symlink support using the Unix extensions |
| 709 | 753 | ||
| 710 | 8) Started adding the readlink and follow_link code | 754 | 8) Started adding the readlink and follow_link code |
diff --git a/fs/cifs/README b/fs/cifs/README index 34b0cf7111f3..bb90941826ad 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
| @@ -294,8 +294,10 @@ A partial list of the supported mount options follows: | |||
| 294 | during the local client kernel build will be used. | 294 | during the local client kernel build will be used. |
| 295 | If server does not support Unicode, this parameter is | 295 | If server does not support Unicode, this parameter is |
| 296 | unused. | 296 | unused. |
| 297 | rsize default read size | 297 | rsize default read size (usually 16K) |
| 298 | wsize default write size | 298 | wsize default write size (usually 16K, 32K is often better over GigE) |
| 299 | maximum wsize currently allowed by CIFS is 57344 (14 4096 byte | ||
| 300 | pages) | ||
| 299 | rw mount the network share read-write (note that the | 301 | rw mount the network share read-write (note that the |
| 300 | server may still consider the share read-only) | 302 | server may still consider the share read-only) |
| 301 | ro mount network share read-only | 303 | ro mount network share read-only |
| @@ -407,6 +409,13 @@ A partial list of the supported mount options follows: | |||
| 407 | This has no effect if the server does not support | 409 | This has no effect if the server does not support |
| 408 | Unicode on the wire. | 410 | Unicode on the wire. |
| 409 | nomapchars Do not translate any of these seven characters (default). | 411 | nomapchars Do not translate any of these seven characters (default). |
| 412 | nocase Request case insensitive path name matching (case | ||
| 413 | sensitive is the default if the server suports it). | ||
| 414 | nobrl Do not send byte range lock requests to the server. | ||
| 415 | This is necessary for certain applications that break | ||
| 416 | with cifs style mandatory byte range locks (and most | ||
| 417 | cifs servers do not yet support requesting advisory | ||
| 418 | byte range locks). | ||
| 410 | remount remount the share (often used to change from ro to rw mounts | 419 | remount remount the share (often used to change from ro to rw mounts |
| 411 | or vice versa) | 420 | or vice versa) |
| 412 | 421 | ||
| @@ -473,9 +482,16 @@ These experimental features and tracing can be enabled by changing flags in | |||
| 473 | kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable | 482 | kernel, e.g. insmod cifs). To enable a feature set it to 1 e.g. to enable |
| 474 | tracing to the kernel message log type: | 483 | tracing to the kernel message log type: |
| 475 | 484 | ||
| 476 | echo 1 > /proc/fs/cifs/cifsFYI | 485 | echo 7 > /proc/fs/cifs/cifsFYI |
| 477 | 486 | ||
| 478 | and for more extensive tracing including the start of smb requests and responses | 487 | cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel |
| 488 | logging of various informational messages. 2 enables logging of non-zero | ||
| 489 | SMB return codes while 4 enables logging of requests that take longer | ||
| 490 | than one second to complete (except for byte range lock requests). | ||
| 491 | Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the | ||
| 492 | source code (typically by setting it in the beginning of cifsglob.h), | ||
| 493 | and setting it to seven enables all three. Finally, tracing | ||
| 494 | the start of smb requests and responses can be enabled via: | ||
| 479 | 495 | ||
| 480 | echo 1 > /proc/fs/cifs/traceSMB | 496 | echo 1 > /proc/fs/cifs/traceSMB |
| 481 | 497 | ||
diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 8cc881694e29..c909298d11ed 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | version 1.34 April 29, 2005 | 1 | version 1.37 October 9, 2005 |
| 2 | 2 | ||
| 3 | A Partial List of Missing Features | 3 | A Partial List of Missing Features |
| 4 | ================================== | 4 | ================================== |
| @@ -7,14 +7,14 @@ Contributions are welcome. There are plenty of opportunities | |||
| 7 | for visible, important contributions to this module. Here | 7 | for visible, important contributions to this module. Here |
| 8 | is a partial list of the known problems and missing features: | 8 | is a partial list of the known problems and missing features: |
| 9 | 9 | ||
| 10 | a) Support for SecurityDescriptors for chmod/chgrp/chown so | 10 | a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown |
| 11 | these can be supported for Windows servers | 11 | so that these operations can be supported to Windows servers |
| 12 | 12 | ||
| 13 | b) Better pam/winbind integration (e.g. to handle uid mapping | 13 | b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS |
| 14 | better) | 14 | SecurityDescriptors |
| 15 | 15 | ||
| 16 | c) multi-user mounts - multiplexed sessionsetups over single vc | 16 | c) Better pam/winbind integration (e.g. to handle uid mapping |
| 17 | (ie tcp session) - more testing needed | 17 | better) |
| 18 | 18 | ||
| 19 | d) Kerberos/SPNEGO session setup support - (started) | 19 | d) Kerberos/SPNEGO session setup support - (started) |
| 20 | 20 | ||
| @@ -29,12 +29,17 @@ f) Directory entry caching relies on a 1 second timer, rather than | |||
| 29 | using FindNotify or equivalent. - (started) | 29 | using FindNotify or equivalent. - (started) |
| 30 | 30 | ||
| 31 | g) A few byte range testcases fail due to POSIX vs. Windows/CIFS | 31 | g) A few byte range testcases fail due to POSIX vs. Windows/CIFS |
| 32 | style byte range lock differences | 32 | style byte range lock differences. Save byte range locks so |
| 33 | reconnect can replay them. | ||
| 33 | 34 | ||
| 34 | h) quota support | 35 | h) Support unlock all (unlock 0,MAX_OFFSET) |
| 36 | by unlocking all known byte range locks that we locked on the file. | ||
| 35 | 37 | ||
| 36 | j) finish writepages support (multi-page write behind for improved | 38 | i) quota support (needs minor kernel change since quota calls |
| 37 | performance) and syncpage | 39 | to make it to network filesystems or deviceless filesystems) |
| 40 | |||
| 41 | j) investigate sync behavior (including syncpage) and check | ||
| 42 | for proper behavior of intr/nointr | ||
| 38 | 43 | ||
| 39 | k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the | 44 | k) hook lower into the sockets api (as NFS/SunRPC does) to avoid the |
| 40 | extra copy in/out of the socket buffers in some cases. | 45 | extra copy in/out of the socket buffers in some cases. |
| @@ -57,20 +62,18 @@ p) Add support for storing symlink and fifo info to Windows servers | |||
| 57 | in the Extended Attribute format their SFU clients would recognize. | 62 | in the Extended Attribute format their SFU clients would recognize. |
| 58 | 63 | ||
| 59 | q) Finish fcntl D_NOTIFY support so kde and gnome file list windows | 64 | q) Finish fcntl D_NOTIFY support so kde and gnome file list windows |
| 60 | will autorefresh (started) | 65 | will autorefresh (partially complete by Asser). Needs minor kernel |
| 66 | vfs change to support removing D_NOTIFY on a file. | ||
| 61 | 67 | ||
| 62 | r) Add GUI tool to configure /proc/fs/cifs settings and for display of | 68 | r) Add GUI tool to configure /proc/fs/cifs settings and for display of |
| 63 | the CIFS statistics (started) | 69 | the CIFS statistics (started) |
| 64 | 70 | ||
| 65 | q) implement support for security and trusted categories of xattrs | 71 | s) implement support for security and trusted categories of xattrs |
| 66 | (requires minor protocol extension) to enable better support for SELINUX | 72 | (requires minor protocol extension) to enable better support for SELINUX |
| 67 | 73 | ||
| 68 | r) Implement O_DIRECT flag on open (already supported on mount) | 74 | t) Implement O_DIRECT flag on open (already supported on mount) |
| 69 | |||
| 70 | s) Allow remapping of last remaining character (\) to +0xF000 which | ||
| 71 | (this character is valid for POSIX but not for Windows) | ||
| 72 | 75 | ||
| 73 | t) Create UID mapping facility so server UIDs can be mapped on a per | 76 | u) Create UID mapping facility so server UIDs can be mapped on a per |
| 74 | mount or a per server basis to client UIDs or nobody if no mapping | 77 | mount or a per server basis to client UIDs or nobody if no mapping |
| 75 | exists. This is helpful when Unix extensions are negotiated to | 78 | exists. This is helpful when Unix extensions are negotiated to |
| 76 | allow better permission checking when UIDs differ on the server | 79 | allow better permission checking when UIDs differ on the server |
| @@ -78,6 +81,17 @@ and client. Add new protocol request to the CIFS protocol | |||
| 78 | standard for asking the server for the corresponding name of a | 81 | standard for asking the server for the corresponding name of a |
| 79 | particular uid. | 82 | particular uid. |
| 80 | 83 | ||
| 84 | v) Add support for CIFS Unix and also the newer POSIX extensions to the | ||
| 85 | server side for Samba 4. | ||
| 86 | |||
| 87 | w) Finish up the dos time conversion routines needed to return old server | ||
| 88 | time to the client (default time, of now or time 0 is used now for these | ||
| 89 | very old servers) | ||
| 90 | |||
| 91 | x) Add support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) | ||
| 92 | |||
| 93 | y) Finish testing of Windows 9x/Windows ME server support (started). | ||
| 94 | |||
| 81 | KNOWN BUGS (updated April 29, 2005) | 95 | KNOWN BUGS (updated April 29, 2005) |
| 82 | ==================================== | 96 | ==================================== |
| 83 | See http://bugzilla.samba.org - search on product "CifsVFS" for | 97 | See http://bugzilla.samba.org - search on product "CifsVFS" for |
diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index e02010dd73ec..98539e2afe81 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c | |||
| @@ -191,7 +191,8 @@ asn1_header_decode(struct asn1_ctx *ctx, | |||
| 191 | unsigned char **eoc, | 191 | unsigned char **eoc, |
| 192 | unsigned int *cls, unsigned int *con, unsigned int *tag) | 192 | unsigned int *cls, unsigned int *con, unsigned int *tag) |
| 193 | { | 193 | { |
| 194 | unsigned int def, len; | 194 | unsigned int def = 0; |
| 195 | unsigned int len = 0; | ||
| 195 | 196 | ||
| 196 | if (!asn1_id_decode(ctx, cls, con, tag)) | 197 | if (!asn1_id_decode(ctx, cls, con, tag)) |
| 197 | return 0; | 198 | return 0; |
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 4061e43471c1..22a444a3fe4c 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
| @@ -81,6 +81,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 81 | buf += length; | 81 | buf += length; |
| 82 | length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION); | 82 | length = sprintf(buf,"CIFS Version %s\n",CIFS_VERSION); |
| 83 | buf += length; | 83 | buf += length; |
| 84 | length = sprintf(buf,"Active VFS Requests: %d\n", GlobalTotalActiveXid); | ||
| 85 | buf += length; | ||
| 84 | length = sprintf(buf, "Servers:"); | 86 | length = sprintf(buf, "Servers:"); |
| 85 | buf += length; | 87 | buf += length; |
| 86 | 88 | ||
| @@ -97,7 +99,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 97 | } else { | 99 | } else { |
| 98 | length = | 100 | length = |
| 99 | sprintf(buf, | 101 | sprintf(buf, |
| 100 | "\n%d) Name: %s Domain: %s Mounts: %d ServerOS: %s \n\tServerNOS: %s\tCapabilities: 0x%x\n\tSMB session status: %d\t", | 102 | "\n%d) Name: %s Domain: %s Mounts: %d OS: %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB session status: %d\t", |
| 101 | i, ses->serverName, ses->serverDomain, | 103 | i, ses->serverName, ses->serverDomain, |
| 102 | atomic_read(&ses->inUse), | 104 | atomic_read(&ses->inUse), |
| 103 | ses->serverOS, ses->serverNOS, | 105 | ses->serverOS, ses->serverNOS, |
| @@ -105,12 +107,18 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 105 | buf += length; | 107 | buf += length; |
| 106 | } | 108 | } |
| 107 | if(ses->server) { | 109 | if(ses->server) { |
| 108 | buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req Active: %d", | 110 | buf += sprintf(buf, "TCP status: %d\n\tLocal Users To Server: %d SecMode: 0x%x Req On Wire: %d", |
| 109 | ses->server->tcpStatus, | 111 | ses->server->tcpStatus, |
| 110 | atomic_read(&ses->server->socketUseCount), | 112 | atomic_read(&ses->server->socketUseCount), |
| 111 | ses->server->secMode, | 113 | ses->server->secMode, |
| 112 | atomic_read(&ses->server->inFlight)); | 114 | atomic_read(&ses->server->inFlight)); |
| 113 | 115 | ||
| 116 | #ifdef CONFIG_CIFS_STATS2 | ||
| 117 | buf += sprintf(buf, " In Send: %d In MaxReq Wait: %d", | ||
| 118 | atomic_read(&ses->server->inSend), | ||
| 119 | atomic_read(&ses->server->num_waiters)); | ||
| 120 | #endif | ||
| 121 | |||
| 114 | length = sprintf(buf, "\nMIDs:\n"); | 122 | length = sprintf(buf, "\nMIDs:\n"); |
| 115 | buf += length; | 123 | buf += length; |
| 116 | 124 | ||
| @@ -149,7 +157,7 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 149 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); | 157 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); |
| 150 | length = | 158 | length = |
| 151 | sprintf(buf, | 159 | sprintf(buf, |
| 152 | "\n%d) %s Uses: %d Type: %s Characteristics: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", | 160 | "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x Attributes: 0x%x\nPathComponentMax: %d Status: %d", |
| 153 | i, tcon->treeName, | 161 | i, tcon->treeName, |
| 154 | atomic_read(&tcon->useCount), | 162 | atomic_read(&tcon->useCount), |
| 155 | tcon->nativeFileSystem, | 163 | tcon->nativeFileSystem, |
| @@ -195,6 +203,49 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, | |||
| 195 | } | 203 | } |
| 196 | 204 | ||
| 197 | #ifdef CONFIG_CIFS_STATS | 205 | #ifdef CONFIG_CIFS_STATS |
| 206 | |||
| 207 | static int | ||
| 208 | cifs_stats_write(struct file *file, const char __user *buffer, | ||
| 209 | unsigned long count, void *data) | ||
| 210 | { | ||
| 211 | char c; | ||
| 212 | int rc; | ||
| 213 | struct list_head *tmp; | ||
| 214 | struct cifsTconInfo *tcon; | ||
| 215 | |||
| 216 | rc = get_user(c, buffer); | ||
| 217 | if (rc) | ||
| 218 | return rc; | ||
| 219 | |||
| 220 | if (c == '1' || c == 'y' || c == 'Y' || c == '0') { | ||
| 221 | read_lock(&GlobalSMBSeslock); | ||
| 222 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
| 223 | tcon = list_entry(tmp, struct cifsTconInfo, | ||
| 224 | cifsConnectionList); | ||
| 225 | atomic_set(&tcon->num_smbs_sent, 0); | ||
| 226 | atomic_set(&tcon->num_writes, 0); | ||
| 227 | atomic_set(&tcon->num_reads, 0); | ||
| 228 | atomic_set(&tcon->num_oplock_brks, 0); | ||
| 229 | atomic_set(&tcon->num_opens, 0); | ||
| 230 | atomic_set(&tcon->num_closes, 0); | ||
| 231 | atomic_set(&tcon->num_deletes, 0); | ||
| 232 | atomic_set(&tcon->num_mkdirs, 0); | ||
| 233 | atomic_set(&tcon->num_rmdirs, 0); | ||
| 234 | atomic_set(&tcon->num_renames, 0); | ||
| 235 | atomic_set(&tcon->num_t2renames, 0); | ||
| 236 | atomic_set(&tcon->num_ffirst, 0); | ||
| 237 | atomic_set(&tcon->num_fnext, 0); | ||
| 238 | atomic_set(&tcon->num_fclose, 0); | ||
| 239 | atomic_set(&tcon->num_hardlinks, 0); | ||
| 240 | atomic_set(&tcon->num_symlinks, 0); | ||
| 241 | atomic_set(&tcon->num_locks, 0); | ||
| 242 | } | ||
| 243 | read_unlock(&GlobalSMBSeslock); | ||
| 244 | } | ||
| 245 | |||
| 246 | return count; | ||
| 247 | } | ||
| 248 | |||
| 198 | static int | 249 | static int |
| 199 | cifs_stats_read(char *buf, char **beginBuffer, off_t offset, | 250 | cifs_stats_read(char *buf, char **beginBuffer, off_t offset, |
| 200 | int count, int *eof, void *data) | 251 | int count, int *eof, void *data) |
| @@ -254,35 +305,51 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, | |||
| 254 | buf += sprintf(buf, "\tDISCONNECTED "); | 305 | buf += sprintf(buf, "\tDISCONNECTED "); |
| 255 | length += 14; | 306 | length += 14; |
| 256 | } | 307 | } |
| 257 | item_length = sprintf(buf,"\nSMBs: %d Oplock Breaks: %d", | 308 | item_length = sprintf(buf, "\nSMBs: %d Oplock Breaks: %d", |
| 258 | atomic_read(&tcon->num_smbs_sent), | 309 | atomic_read(&tcon->num_smbs_sent), |
| 259 | atomic_read(&tcon->num_oplock_brks)); | 310 | atomic_read(&tcon->num_oplock_brks)); |
| 260 | buf += item_length; | 311 | buf += item_length; |
| 261 | length += item_length; | 312 | length += item_length; |
| 262 | item_length = sprintf(buf,"\nReads: %d Bytes %lld", | 313 | item_length = sprintf(buf, "\nReads: %d Bytes: %lld", |
| 263 | atomic_read(&tcon->num_reads), | 314 | atomic_read(&tcon->num_reads), |
| 264 | (long long)(tcon->bytes_read)); | 315 | (long long)(tcon->bytes_read)); |
| 265 | buf += item_length; | 316 | buf += item_length; |
| 266 | length += item_length; | 317 | length += item_length; |
| 267 | item_length = sprintf(buf,"\nWrites: %d Bytes: %lld", | 318 | item_length = sprintf(buf, "\nWrites: %d Bytes: %lld", |
| 268 | atomic_read(&tcon->num_writes), | 319 | atomic_read(&tcon->num_writes), |
| 269 | (long long)(tcon->bytes_written)); | 320 | (long long)(tcon->bytes_written)); |
| 321 | buf += item_length; | ||
| 322 | length += item_length; | ||
| 323 | item_length = sprintf(buf, | ||
| 324 | "\nLocks: %d HardLinks: %d Symlinks: %d", | ||
| 325 | atomic_read(&tcon->num_locks), | ||
| 326 | atomic_read(&tcon->num_hardlinks), | ||
| 327 | atomic_read(&tcon->num_symlinks)); | ||
| 328 | buf += item_length; | ||
| 329 | length += item_length; | ||
| 330 | |||
| 331 | item_length = sprintf(buf, "\nOpens: %d Closes: %d Deletes: %d", | ||
| 332 | atomic_read(&tcon->num_opens), | ||
| 333 | atomic_read(&tcon->num_closes), | ||
| 334 | atomic_read(&tcon->num_deletes)); | ||
| 270 | buf += item_length; | 335 | buf += item_length; |
| 271 | length += item_length; | 336 | length += item_length; |
| 272 | item_length = sprintf(buf, | 337 | item_length = sprintf(buf, "\nMkdirs: %d Rmdirs: %d", |
| 273 | "\nOpens: %d Deletes: %d\nMkdirs: %d Rmdirs: %d", | ||
| 274 | atomic_read(&tcon->num_opens), | ||
| 275 | atomic_read(&tcon->num_deletes), | ||
| 276 | atomic_read(&tcon->num_mkdirs), | 338 | atomic_read(&tcon->num_mkdirs), |
| 277 | atomic_read(&tcon->num_rmdirs)); | 339 | atomic_read(&tcon->num_rmdirs)); |
| 278 | buf += item_length; | 340 | buf += item_length; |
| 279 | length += item_length; | 341 | length += item_length; |
| 280 | item_length = sprintf(buf, | 342 | item_length = sprintf(buf, "\nRenames: %d T2 Renames %d", |
| 281 | "\nRenames: %d T2 Renames %d", | ||
| 282 | atomic_read(&tcon->num_renames), | 343 | atomic_read(&tcon->num_renames), |
| 283 | atomic_read(&tcon->num_t2renames)); | 344 | atomic_read(&tcon->num_t2renames)); |
| 284 | buf += item_length; | 345 | buf += item_length; |
| 285 | length += item_length; | 346 | length += item_length; |
| 347 | item_length = sprintf(buf, "\nFindFirst: %d FNext %d FClose %d", | ||
| 348 | atomic_read(&tcon->num_ffirst), | ||
| 349 | atomic_read(&tcon->num_fnext), | ||
| 350 | atomic_read(&tcon->num_fclose)); | ||
| 351 | buf += item_length; | ||
| 352 | length += item_length; | ||
| 286 | } | 353 | } |
| 287 | read_unlock(&GlobalSMBSeslock); | 354 | read_unlock(&GlobalSMBSeslock); |
| 288 | 355 | ||
| @@ -341,8 +408,10 @@ cifs_proc_init(void) | |||
| 341 | cifs_debug_data_read, NULL); | 408 | cifs_debug_data_read, NULL); |
| 342 | 409 | ||
| 343 | #ifdef CONFIG_CIFS_STATS | 410 | #ifdef CONFIG_CIFS_STATS |
| 344 | create_proc_read_entry("Stats", 0, proc_fs_cifs, | 411 | pde = create_proc_read_entry("Stats", 0, proc_fs_cifs, |
| 345 | cifs_stats_read, NULL); | 412 | cifs_stats_read, NULL); |
| 413 | if (pde) | ||
| 414 | pde->write_proc = cifs_stats_write; | ||
| 346 | #endif | 415 | #endif |
| 347 | pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, | 416 | pde = create_proc_read_entry("cifsFYI", 0, proc_fs_cifs, |
| 348 | cifsFYI_read, NULL); | 417 | cifsFYI_read, NULL); |
| @@ -360,7 +429,7 @@ cifs_proc_init(void) | |||
| 360 | if (pde) | 429 | if (pde) |
| 361 | pde->write_proc = oplockEnabled_write; | 430 | pde->write_proc = oplockEnabled_write; |
| 362 | 431 | ||
| 363 | pde = create_proc_read_entry("ReenableOldCifsReaddirCode", 0, proc_fs_cifs, | 432 | pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, |
| 364 | quotaEnabled_read, NULL); | 433 | quotaEnabled_read, NULL); |
| 365 | if (pde) | 434 | if (pde) |
| 366 | pde->write_proc = quotaEnabled_write; | 435 | pde->write_proc = quotaEnabled_write; |
| @@ -419,7 +488,7 @@ cifs_proc_clean(void) | |||
| 419 | remove_proc_entry("ExtendedSecurity",proc_fs_cifs); | 488 | remove_proc_entry("ExtendedSecurity",proc_fs_cifs); |
| 420 | remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); | 489 | remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); |
| 421 | remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); | 490 | remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); |
| 422 | remove_proc_entry("ReenableOldCifsReaddirCode",proc_fs_cifs); | 491 | remove_proc_entry("Experimental",proc_fs_cifs); |
| 423 | remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); | 492 | remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); |
| 424 | remove_proc_entry("cifs", proc_root_fs); | 493 | remove_proc_entry("cifs", proc_root_fs); |
| 425 | } | 494 | } |
| @@ -459,6 +528,8 @@ cifsFYI_write(struct file *file, const char __user *buffer, | |||
| 459 | cifsFYI = 0; | 528 | cifsFYI = 0; |
| 460 | else if (c == '1' || c == 'y' || c == 'Y') | 529 | else if (c == '1' || c == 'y' || c == 'Y') |
| 461 | cifsFYI = 1; | 530 | cifsFYI = 1; |
| 531 | else if((c > '1') && (c <= '9')) | ||
| 532 | cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */ | ||
| 462 | 533 | ||
| 463 | return count; | 534 | return count; |
| 464 | } | 535 | } |
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index bf24d2828f68..4304d9dcfb6c 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h | |||
| @@ -26,6 +26,9 @@ | |||
| 26 | void cifs_dump_mem(char *label, void *data, int length); | 26 | void cifs_dump_mem(char *label, void *data, int length); |
| 27 | extern int traceSMB; /* flag which enables the function below */ | 27 | extern int traceSMB; /* flag which enables the function below */ |
| 28 | void dump_smb(struct smb_hdr *, int); | 28 | void dump_smb(struct smb_hdr *, int); |
| 29 | #define CIFS_INFO 0x01 | ||
| 30 | #define CIFS_RC 0x02 | ||
| 31 | #define CIFS_TIMER 0x04 | ||
| 29 | 32 | ||
| 30 | /* | 33 | /* |
| 31 | * debug ON | 34 | * debug ON |
| @@ -36,7 +39,7 @@ void dump_smb(struct smb_hdr *, int); | |||
| 36 | 39 | ||
| 37 | /* information message: e.g., configuration, major event */ | 40 | /* information message: e.g., configuration, major event */ |
| 38 | extern int cifsFYI; | 41 | extern int cifsFYI; |
| 39 | #define cifsfyi(format,arg...) if (cifsFYI) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) | 42 | #define cifsfyi(format,arg...) if (cifsFYI & CIFS_INFO) printk(KERN_DEBUG " " __FILE__ ": " format "\n" "" , ## arg) |
| 40 | 43 | ||
| 41 | #define cFYI(button,prspec) if (button) cifsfyi prspec | 44 | #define cFYI(button,prspec) if (button) cifsfyi prspec |
| 42 | 45 | ||
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index ec00d61d5308..f799f6f0e729 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
| @@ -24,6 +24,9 @@ | |||
| 24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ | 24 | #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ |
| 25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ | 25 | #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ |
| 26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ | 26 | #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ |
| 27 | #define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ | ||
| 28 | #define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */ | ||
| 29 | #define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */ | ||
| 27 | 30 | ||
| 28 | struct cifs_sb_info { | 31 | struct cifs_sb_info { |
| 29 | struct cifsTconInfo *tcon; /* primary mount */ | 32 | struct cifsTconInfo *tcon; /* primary mount */ |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1ebf7dafc1d7..877095a1192a 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -59,6 +59,8 @@ unsigned int ntlmv2_support = 0; | |||
| 59 | unsigned int sign_CIFS_PDUs = 1; | 59 | unsigned int sign_CIFS_PDUs = 1; |
| 60 | extern struct task_struct * oplockThread; /* remove sparse warning */ | 60 | extern struct task_struct * oplockThread; /* remove sparse warning */ |
| 61 | struct task_struct * oplockThread = NULL; | 61 | struct task_struct * oplockThread = NULL; |
| 62 | extern struct task_struct * dnotifyThread; /* remove sparse warning */ | ||
| 63 | struct task_struct * dnotifyThread = NULL; | ||
| 62 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; | 64 | unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; |
| 63 | module_param(CIFSMaxBufSize, int, 0); | 65 | module_param(CIFSMaxBufSize, int, 0); |
| 64 | MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); | 66 | MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); |
| @@ -73,6 +75,7 @@ module_param(cifs_max_pending, int, 0); | |||
| 73 | MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); | 75 | MODULE_PARM_DESC(cifs_max_pending,"Simultaneous requests to server. Default: 50 Range: 2 to 256"); |
| 74 | 76 | ||
| 75 | static DECLARE_COMPLETION(cifs_oplock_exited); | 77 | static DECLARE_COMPLETION(cifs_oplock_exited); |
| 78 | static DECLARE_COMPLETION(cifs_dnotify_exited); | ||
| 76 | 79 | ||
| 77 | extern mempool_t *cifs_sm_req_poolp; | 80 | extern mempool_t *cifs_sm_req_poolp; |
| 78 | extern mempool_t *cifs_req_poolp; | 81 | extern mempool_t *cifs_req_poolp; |
| @@ -202,6 +205,10 @@ cifs_statfs(struct super_block *sb, struct kstatfs *buf) | |||
| 202 | #endif /* CIFS_EXPERIMENTAL */ | 205 | #endif /* CIFS_EXPERIMENTAL */ |
| 203 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); | 206 | rc = CIFSSMBQFSInfo(xid, pTcon, buf); |
| 204 | 207 | ||
| 208 | /* Old Windows servers do not support level 103, retry with level | ||
| 209 | one if old server failed the previous call */ | ||
| 210 | if(rc) | ||
| 211 | rc = SMBOldQFSInfo(xid, pTcon, buf); | ||
| 205 | /* | 212 | /* |
| 206 | int f_type; | 213 | int f_type; |
| 207 | __fsid_t f_fsid; | 214 | __fsid_t f_fsid; |
| @@ -253,7 +260,7 @@ cifs_alloc_inode(struct super_block *sb) | |||
| 253 | cifs_inode->clientCanCacheAll = FALSE; | 260 | cifs_inode->clientCanCacheAll = FALSE; |
| 254 | cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; | 261 | cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE; |
| 255 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ | 262 | cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */ |
| 256 | 263 | cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME; | |
| 257 | INIT_LIST_HEAD(&cifs_inode->openFileList); | 264 | INIT_LIST_HEAD(&cifs_inode->openFileList); |
| 258 | return &cifs_inode->vfs_inode; | 265 | return &cifs_inode->vfs_inode; |
| 259 | } | 266 | } |
| @@ -398,6 +405,34 @@ static struct quotactl_ops cifs_quotactl_ops = { | |||
| 398 | }; | 405 | }; |
| 399 | #endif | 406 | #endif |
| 400 | 407 | ||
| 408 | static void cifs_umount_begin(struct super_block * sblock) | ||
| 409 | { | ||
| 410 | struct cifs_sb_info *cifs_sb; | ||
| 411 | struct cifsTconInfo * tcon; | ||
| 412 | |||
| 413 | cifs_sb = CIFS_SB(sblock); | ||
| 414 | if(cifs_sb == NULL) | ||
| 415 | return; | ||
| 416 | |||
| 417 | tcon = cifs_sb->tcon; | ||
| 418 | if(tcon == NULL) | ||
| 419 | return; | ||
| 420 | down(&tcon->tconSem); | ||
| 421 | if (atomic_read(&tcon->useCount) == 1) | ||
| 422 | tcon->tidStatus = CifsExiting; | ||
| 423 | up(&tcon->tconSem); | ||
| 424 | |||
| 425 | if(tcon->ses && tcon->ses->server) | ||
| 426 | { | ||
| 427 | cERROR(1,("wake up tasks now - umount begin not complete")); | ||
| 428 | wake_up_all(&tcon->ses->server->request_q); | ||
| 429 | } | ||
| 430 | /* BB FIXME - finish add checks for tidStatus BB */ | ||
| 431 | |||
| 432 | return; | ||
| 433 | } | ||
| 434 | |||
| 435 | |||
| 401 | static int cifs_remount(struct super_block *sb, int *flags, char *data) | 436 | static int cifs_remount(struct super_block *sb, int *flags, char *data) |
| 402 | { | 437 | { |
| 403 | *flags |= MS_NODIRATIME; | 438 | *flags |= MS_NODIRATIME; |
| @@ -415,7 +450,7 @@ struct super_operations cifs_super_ops = { | |||
| 415 | unless later we add lazy close of inodes or unless the kernel forgets to call | 450 | unless later we add lazy close of inodes or unless the kernel forgets to call |
| 416 | us with the same number of releases (closes) as opens */ | 451 | us with the same number of releases (closes) as opens */ |
| 417 | .show_options = cifs_show_options, | 452 | .show_options = cifs_show_options, |
| 418 | /* .umount_begin = cifs_umount_begin, *//* consider adding in the future */ | 453 | /* .umount_begin = cifs_umount_begin, */ /* BB finish in the future */ |
| 419 | .remount_fs = cifs_remount, | 454 | .remount_fs = cifs_remount, |
| 420 | }; | 455 | }; |
| 421 | 456 | ||
| @@ -783,9 +818,7 @@ static int cifs_oplock_thread(void * dummyarg) | |||
| 783 | do { | 818 | do { |
| 784 | if (try_to_freeze()) | 819 | if (try_to_freeze()) |
| 785 | continue; | 820 | continue; |
| 786 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 787 | 821 | ||
| 788 | schedule_timeout(1*HZ); | ||
| 789 | spin_lock(&GlobalMid_Lock); | 822 | spin_lock(&GlobalMid_Lock); |
| 790 | if(list_empty(&GlobalOplock_Q)) { | 823 | if(list_empty(&GlobalOplock_Q)) { |
| 791 | spin_unlock(&GlobalMid_Lock); | 824 | spin_unlock(&GlobalMid_Lock); |
| @@ -834,10 +867,27 @@ static int cifs_oplock_thread(void * dummyarg) | |||
| 834 | } | 867 | } |
| 835 | } else | 868 | } else |
| 836 | spin_unlock(&GlobalMid_Lock); | 869 | spin_unlock(&GlobalMid_Lock); |
| 870 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 871 | schedule_timeout(1); /* yield in case q were corrupt */ | ||
| 837 | } | 872 | } |
| 838 | } while(!signal_pending(current)); | 873 | } while(!signal_pending(current)); |
| 839 | complete_and_exit (&cifs_oplock_exited, 0); | ||
| 840 | oplockThread = NULL; | 874 | oplockThread = NULL; |
| 875 | complete_and_exit (&cifs_oplock_exited, 0); | ||
| 876 | } | ||
| 877 | |||
| 878 | static int cifs_dnotify_thread(void * dummyarg) | ||
| 879 | { | ||
| 880 | daemonize("cifsdnotifyd"); | ||
| 881 | allow_signal(SIGTERM); | ||
| 882 | |||
| 883 | dnotifyThread = current; | ||
| 884 | do { | ||
| 885 | if(try_to_freeze()) | ||
| 886 | continue; | ||
| 887 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 888 | schedule_timeout(39*HZ); | ||
| 889 | } while(!signal_pending(current)); | ||
| 890 | complete_and_exit (&cifs_dnotify_exited, 0); | ||
| 841 | } | 891 | } |
| 842 | 892 | ||
| 843 | static int __init | 893 | static int __init |
| @@ -851,6 +901,10 @@ init_cifs(void) | |||
| 851 | INIT_LIST_HEAD(&GlobalSMBSessionList); | 901 | INIT_LIST_HEAD(&GlobalSMBSessionList); |
| 852 | INIT_LIST_HEAD(&GlobalTreeConnectionList); | 902 | INIT_LIST_HEAD(&GlobalTreeConnectionList); |
| 853 | INIT_LIST_HEAD(&GlobalOplock_Q); | 903 | INIT_LIST_HEAD(&GlobalOplock_Q); |
| 904 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
| 905 | INIT_LIST_HEAD(&GlobalDnotifyReqList); | ||
| 906 | INIT_LIST_HEAD(&GlobalDnotifyRsp_Q); | ||
| 907 | #endif | ||
| 854 | /* | 908 | /* |
| 855 | * Initialize Global counters | 909 | * Initialize Global counters |
| 856 | */ | 910 | */ |
| @@ -886,10 +940,16 @@ init_cifs(void) | |||
| 886 | if (!rc) { | 940 | if (!rc) { |
| 887 | rc = (int)kernel_thread(cifs_oplock_thread, NULL, | 941 | rc = (int)kernel_thread(cifs_oplock_thread, NULL, |
| 888 | CLONE_FS | CLONE_FILES | CLONE_VM); | 942 | CLONE_FS | CLONE_FILES | CLONE_VM); |
| 889 | if(rc > 0) | 943 | if(rc > 0) { |
| 890 | return 0; | 944 | rc = (int)kernel_thread(cifs_dnotify_thread, NULL, |
| 891 | else | 945 | CLONE_FS | CLONE_FILES | CLONE_VM); |
| 946 | if(rc > 0) | ||
| 947 | return 0; | ||
| 948 | else | ||
| 949 | cERROR(1,("error %d create dnotify thread", rc)); | ||
| 950 | } else { | ||
| 892 | cERROR(1,("error %d create oplock thread",rc)); | 951 | cERROR(1,("error %d create oplock thread",rc)); |
| 952 | } | ||
| 893 | } | 953 | } |
| 894 | cifs_destroy_request_bufs(); | 954 | cifs_destroy_request_bufs(); |
| 895 | } | 955 | } |
| @@ -918,6 +978,10 @@ exit_cifs(void) | |||
| 918 | send_sig(SIGTERM, oplockThread, 1); | 978 | send_sig(SIGTERM, oplockThread, 1); |
| 919 | wait_for_completion(&cifs_oplock_exited); | 979 | wait_for_completion(&cifs_oplock_exited); |
| 920 | } | 980 | } |
| 981 | if(dnotifyThread) { | ||
| 982 | send_sig(SIGTERM, dnotifyThread, 1); | ||
| 983 | wait_for_completion(&cifs_dnotify_exited); | ||
| 984 | } | ||
| 921 | } | 985 | } |
| 922 | 986 | ||
| 923 | MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); | 987 | MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 1fd21f66f243..1223fa81dbd2 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
| @@ -81,6 +81,7 @@ extern int cifs_dir_notify(struct file *, unsigned long arg); | |||
| 81 | 81 | ||
| 82 | /* Functions related to dir entries */ | 82 | /* Functions related to dir entries */ |
| 83 | extern struct dentry_operations cifs_dentry_ops; | 83 | extern struct dentry_operations cifs_dentry_ops; |
| 84 | extern struct dentry_operations cifs_ci_dentry_ops; | ||
| 84 | 85 | ||
| 85 | /* Functions related to symlinks */ | 86 | /* Functions related to symlinks */ |
| 86 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); | 87 | extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd); |
| @@ -96,5 +97,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); | |||
| 96 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 97 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
| 97 | extern int cifs_ioctl (struct inode * inode, struct file * filep, | 98 | extern int cifs_ioctl (struct inode * inode, struct file * filep, |
| 98 | unsigned int command, unsigned long arg); | 99 | unsigned int command, unsigned long arg); |
| 99 | #define CIFS_VERSION "1.35" | 100 | #define CIFS_VERSION "1.39" |
| 100 | #endif /* _CIFSFS_H */ | 101 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 81babab265e1..1ba08f8c5bc4 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -110,8 +110,9 @@ enum protocolEnum { | |||
| 110 | */ | 110 | */ |
| 111 | 111 | ||
| 112 | struct TCP_Server_Info { | 112 | struct TCP_Server_Info { |
| 113 | char server_Name[SERVER_NAME_LEN_WITH_NULL]; /* 15 chars + X'20'in 16th */ | 113 | /* 15 character server name + 0x20 16th byte indicating type = srv */ |
| 114 | char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; /* Unicode version of server_Name */ | 114 | char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; |
| 115 | char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; | ||
| 115 | struct socket *ssocket; | 116 | struct socket *ssocket; |
| 116 | union { | 117 | union { |
| 117 | struct sockaddr_in sockAddr; | 118 | struct sockaddr_in sockAddr; |
| @@ -122,13 +123,17 @@ struct TCP_Server_Info { | |||
| 122 | struct list_head pending_mid_q; | 123 | struct list_head pending_mid_q; |
| 123 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ | 124 | void *Server_NlsInfo; /* BB - placeholder for future NLS info */ |
| 124 | unsigned short server_codepage; /* codepage for the server */ | 125 | unsigned short server_codepage; /* codepage for the server */ |
| 125 | unsigned long ip_address; /* IP addr for the server if known */ | 126 | unsigned long ip_address; /* IP addr for the server if known */ |
| 126 | enum protocolEnum protocolType; | 127 | enum protocolEnum protocolType; |
| 127 | char versionMajor; | 128 | char versionMajor; |
| 128 | char versionMinor; | 129 | char versionMinor; |
| 129 | unsigned svlocal:1; /* local server or remote */ | 130 | unsigned svlocal:1; /* local server or remote */ |
| 130 | atomic_t socketUseCount; /* number of open cifs sessions on socket */ | 131 | atomic_t socketUseCount; /* number of open cifs sessions on socket */ |
| 131 | atomic_t inFlight; /* number of requests on the wire to server */ | 132 | atomic_t inFlight; /* number of requests on the wire to server */ |
| 133 | #ifdef CONFIG_CIFS_STATS2 | ||
| 134 | atomic_t inSend; /* requests trying to send */ | ||
| 135 | atomic_t num_waiters; /* blocked waiting to get in sendrecv */ | ||
| 136 | #endif | ||
| 132 | enum statusEnum tcpStatus; /* what we think the status is */ | 137 | enum statusEnum tcpStatus; /* what we think the status is */ |
| 133 | struct semaphore tcpSem; | 138 | struct semaphore tcpSem; |
| 134 | struct task_struct *tsk; | 139 | struct task_struct *tsk; |
| @@ -147,8 +152,10 @@ struct TCP_Server_Info { | |||
| 147 | /* (returned on Negotiate */ | 152 | /* (returned on Negotiate */ |
| 148 | int capabilities; /* allow selective disabling of caps by smb sess */ | 153 | int capabilities; /* allow selective disabling of caps by smb sess */ |
| 149 | __u16 timeZone; | 154 | __u16 timeZone; |
| 155 | __u16 CurrentMid; /* multiplex id - rotating counter */ | ||
| 150 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; | 156 | char cryptKey[CIFS_CRYPTO_KEY_SIZE]; |
| 151 | char workstation_RFC1001_name[16]; /* 16th byte is always zero */ | 157 | /* 16th byte of RFC1001 workstation name is always null */ |
| 158 | char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; | ||
| 152 | __u32 sequence_number; /* needed for CIFS PDU signature */ | 159 | __u32 sequence_number; /* needed for CIFS PDU signature */ |
| 153 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; | 160 | char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; |
| 154 | }; | 161 | }; |
| @@ -214,19 +221,41 @@ struct cifsTconInfo { | |||
| 214 | atomic_t num_reads; | 221 | atomic_t num_reads; |
| 215 | atomic_t num_oplock_brks; | 222 | atomic_t num_oplock_brks; |
| 216 | atomic_t num_opens; | 223 | atomic_t num_opens; |
| 224 | atomic_t num_closes; | ||
| 217 | atomic_t num_deletes; | 225 | atomic_t num_deletes; |
| 218 | atomic_t num_mkdirs; | 226 | atomic_t num_mkdirs; |
| 219 | atomic_t num_rmdirs; | 227 | atomic_t num_rmdirs; |
| 220 | atomic_t num_renames; | 228 | atomic_t num_renames; |
| 221 | atomic_t num_t2renames; | 229 | atomic_t num_t2renames; |
| 230 | atomic_t num_ffirst; | ||
| 231 | atomic_t num_fnext; | ||
| 232 | atomic_t num_fclose; | ||
| 233 | atomic_t num_hardlinks; | ||
| 234 | atomic_t num_symlinks; | ||
| 235 | atomic_t num_locks; | ||
| 236 | #ifdef CONFIG_CIFS_STATS2 | ||
| 237 | unsigned long long time_writes; | ||
| 238 | unsigned long long time_reads; | ||
| 239 | unsigned long long time_opens; | ||
| 240 | unsigned long long time_deletes; | ||
| 241 | unsigned long long time_closes; | ||
| 242 | unsigned long long time_mkdirs; | ||
| 243 | unsigned long long time_rmdirs; | ||
| 244 | unsigned long long time_renames; | ||
| 245 | unsigned long long time_t2renames; | ||
| 246 | unsigned long long time_ffirst; | ||
| 247 | unsigned long long time_fnext; | ||
| 248 | unsigned long long time_fclose; | ||
| 249 | #endif /* CONFIG_CIFS_STATS2 */ | ||
| 222 | __u64 bytes_read; | 250 | __u64 bytes_read; |
| 223 | __u64 bytes_written; | 251 | __u64 bytes_written; |
| 224 | spinlock_t stat_lock; | 252 | spinlock_t stat_lock; |
| 225 | #endif | 253 | #endif /* CONFIG_CIFS_STATS */ |
| 226 | FILE_SYSTEM_DEVICE_INFO fsDevInfo; | 254 | FILE_SYSTEM_DEVICE_INFO fsDevInfo; |
| 227 | FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ | 255 | FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ |
| 228 | FILE_SYSTEM_UNIX_INFO fsUnixInfo; | 256 | FILE_SYSTEM_UNIX_INFO fsUnixInfo; |
| 229 | unsigned retry:1; | 257 | unsigned retry:1; |
| 258 | unsigned nocase:1; | ||
| 230 | /* BB add field for back pointer to sb struct? */ | 259 | /* BB add field for back pointer to sb struct? */ |
| 231 | }; | 260 | }; |
| 232 | 261 | ||
| @@ -270,6 +299,7 @@ struct cifsFileInfo { | |||
| 270 | struct inode * pInode; /* needed for oplock break */ | 299 | struct inode * pInode; /* needed for oplock break */ |
| 271 | unsigned closePend:1; /* file is marked to close */ | 300 | unsigned closePend:1; /* file is marked to close */ |
| 272 | unsigned invalidHandle:1; /* file closed via session abend */ | 301 | unsigned invalidHandle:1; /* file closed via session abend */ |
| 302 | atomic_t wrtPending; /* handle in use - defer close */ | ||
| 273 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ | 303 | struct semaphore fh_sem; /* prevents reopen race after dead ses*/ |
| 274 | char * search_resume_name; /* BB removeme BB */ | 304 | char * search_resume_name; /* BB removeme BB */ |
| 275 | unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ | 305 | unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ |
| @@ -306,6 +336,41 @@ CIFS_SB(struct super_block *sb) | |||
| 306 | return sb->s_fs_info; | 336 | return sb->s_fs_info; |
| 307 | } | 337 | } |
| 308 | 338 | ||
| 339 | static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb) | ||
| 340 | { | ||
| 341 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) | ||
| 342 | return '/'; | ||
| 343 | else | ||
| 344 | return '\\'; | ||
| 345 | } | ||
| 346 | |||
| 347 | #ifdef CONFIG_CIFS_STATS | ||
| 348 | #define cifs_stats_inc atomic_inc | ||
| 349 | |||
| 350 | static inline void cifs_stats_bytes_written(struct cifsTconInfo *tcon, | ||
| 351 | unsigned int bytes) | ||
| 352 | { | ||
| 353 | if (bytes) { | ||
| 354 | spin_lock(&tcon->stat_lock); | ||
| 355 | tcon->bytes_written += bytes; | ||
| 356 | spin_unlock(&tcon->stat_lock); | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 360 | static inline void cifs_stats_bytes_read(struct cifsTconInfo *tcon, | ||
| 361 | unsigned int bytes) | ||
| 362 | { | ||
| 363 | spin_lock(&tcon->stat_lock); | ||
| 364 | tcon->bytes_read += bytes; | ||
| 365 | spin_unlock(&tcon->stat_lock); | ||
| 366 | } | ||
| 367 | #else | ||
| 368 | |||
| 369 | #define cifs_stats_inc(field) do {} while(0) | ||
| 370 | #define cifs_stats_bytes_written(tcon, bytes) do {} while(0) | ||
| 371 | #define cifs_stats_bytes_read(tcon, bytes) do {} while(0) | ||
| 372 | |||
| 373 | #endif | ||
| 309 | 374 | ||
| 310 | /* one of these for every pending CIFS request to the server */ | 375 | /* one of these for every pending CIFS request to the server */ |
| 311 | struct mid_q_entry { | 376 | struct mid_q_entry { |
| @@ -313,7 +378,11 @@ struct mid_q_entry { | |||
| 313 | __u16 mid; /* multiplex id */ | 378 | __u16 mid; /* multiplex id */ |
| 314 | __u16 pid; /* process id */ | 379 | __u16 pid; /* process id */ |
| 315 | __u32 sequence_number; /* for CIFS signing */ | 380 | __u32 sequence_number; /* for CIFS signing */ |
| 316 | struct timeval when_sent; /* time when smb sent */ | 381 | unsigned long when_alloc; /* when mid was created */ |
| 382 | #ifdef CONFIG_CIFS_STATS2 | ||
| 383 | unsigned long when_sent; /* time when smb send finished */ | ||
| 384 | unsigned long when_received; /* when demux complete (taken off wire) */ | ||
| 385 | #endif | ||
| 317 | struct cifsSesInfo *ses; /* smb was sent to this server */ | 386 | struct cifsSesInfo *ses; /* smb was sent to this server */ |
| 318 | struct task_struct *tsk; /* task waiting for response */ | 387 | struct task_struct *tsk; /* task waiting for response */ |
| 319 | struct smb_hdr *resp_buf; /* response buffer */ | 388 | struct smb_hdr *resp_buf; /* response buffer */ |
| @@ -331,6 +400,20 @@ struct oplock_q_entry { | |||
| 331 | __u16 netfid; | 400 | __u16 netfid; |
| 332 | }; | 401 | }; |
| 333 | 402 | ||
| 403 | /* for pending dnotify requests */ | ||
| 404 | struct dir_notify_req { | ||
| 405 | struct list_head lhead; | ||
| 406 | __le16 Pid; | ||
| 407 | __le16 PidHigh; | ||
| 408 | __u16 Mid; | ||
| 409 | __u16 Tid; | ||
| 410 | __u16 Uid; | ||
| 411 | __u16 netfid; | ||
| 412 | __u32 filter; /* CompletionFilter (for multishot) */ | ||
| 413 | int multishot; | ||
| 414 | struct file * pfile; | ||
| 415 | }; | ||
| 416 | |||
| 334 | #define MID_FREE 0 | 417 | #define MID_FREE 0 |
| 335 | #define MID_REQUEST_ALLOCATED 1 | 418 | #define MID_REQUEST_ALLOCATED 1 |
| 336 | #define MID_REQUEST_SUBMITTED 2 | 419 | #define MID_REQUEST_SUBMITTED 2 |
| @@ -399,6 +482,9 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ | |||
| 399 | 482 | ||
| 400 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; | 483 | GLOBAL_EXTERN struct list_head GlobalOplock_Q; |
| 401 | 484 | ||
| 485 | GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ | ||
| 486 | GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */ | ||
| 487 | |||
| 402 | /* | 488 | /* |
| 403 | * Global transaction id (XID) information | 489 | * Global transaction id (XID) information |
| 404 | */ | 490 | */ |
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index aede6a813167..48a05b9df7eb 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h | |||
| @@ -36,9 +36,11 @@ | |||
| 36 | #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ | 36 | #define SMB_COM_CLOSE 0x04 /* triv req/rsp, timestamp ignored */ |
| 37 | #define SMB_COM_DELETE 0x06 /* trivial response */ | 37 | #define SMB_COM_DELETE 0x06 /* trivial response */ |
| 38 | #define SMB_COM_RENAME 0x07 /* trivial response */ | 38 | #define SMB_COM_RENAME 0x07 /* trivial response */ |
| 39 | #define SMB_COM_QUERY_INFORMATION 0x08 /* aka getattr */ | ||
| 39 | #define SMB_COM_SETATTR 0x09 /* trivial response */ | 40 | #define SMB_COM_SETATTR 0x09 /* trivial response */ |
| 40 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ | 41 | #define SMB_COM_LOCKING_ANDX 0x24 /* trivial response */ |
| 41 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ | 42 | #define SMB_COM_COPY 0x29 /* trivial rsp, fail filename ignrd*/ |
| 43 | #define SMB_COM_OPEN_ANDX 0x2D /* Legacy open for old servers */ | ||
| 42 | #define SMB_COM_READ_ANDX 0x2E | 44 | #define SMB_COM_READ_ANDX 0x2E |
| 43 | #define SMB_COM_WRITE_ANDX 0x2F | 45 | #define SMB_COM_WRITE_ANDX 0x2F |
| 44 | #define SMB_COM_TRANSACTION2 0x32 | 46 | #define SMB_COM_TRANSACTION2 0x32 |
| @@ -52,6 +54,7 @@ | |||
| 52 | #define SMB_COM_NT_TRANSACT 0xA0 | 54 | #define SMB_COM_NT_TRANSACT 0xA0 |
| 53 | #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 | 55 | #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 |
| 54 | #define SMB_COM_NT_CREATE_ANDX 0xA2 | 56 | #define SMB_COM_NT_CREATE_ANDX 0xA2 |
| 57 | #define SMB_COM_NT_CANCEL 0xA4 /* no response */ | ||
| 55 | #define SMB_COM_NT_RENAME 0xA5 /* trivial response */ | 58 | #define SMB_COM_NT_RENAME 0xA5 /* trivial response */ |
| 56 | 59 | ||
| 57 | /* Transact2 subcommand codes */ | 60 | /* Transact2 subcommand codes */ |
| @@ -59,6 +62,7 @@ | |||
| 59 | #define TRANS2_FIND_FIRST 0x01 | 62 | #define TRANS2_FIND_FIRST 0x01 |
| 60 | #define TRANS2_FIND_NEXT 0x02 | 63 | #define TRANS2_FIND_NEXT 0x02 |
| 61 | #define TRANS2_QUERY_FS_INFORMATION 0x03 | 64 | #define TRANS2_QUERY_FS_INFORMATION 0x03 |
| 65 | #define TRANS2_SET_FS_INFORMATION 0x04 | ||
| 62 | #define TRANS2_QUERY_PATH_INFORMATION 0x05 | 66 | #define TRANS2_QUERY_PATH_INFORMATION 0x05 |
| 63 | #define TRANS2_SET_PATH_INFORMATION 0x06 | 67 | #define TRANS2_SET_PATH_INFORMATION 0x06 |
| 64 | #define TRANS2_QUERY_FILE_INFORMATION 0x07 | 68 | #define TRANS2_QUERY_FILE_INFORMATION 0x07 |
| @@ -76,7 +80,7 @@ | |||
| 76 | #define NT_TRANSACT_GET_USER_QUOTA 0x07 | 80 | #define NT_TRANSACT_GET_USER_QUOTA 0x07 |
| 77 | #define NT_TRANSACT_SET_USER_QUOTA 0x08 | 81 | #define NT_TRANSACT_SET_USER_QUOTA 0x08 |
| 78 | 82 | ||
| 79 | #define MAX_CIFS_HDR_SIZE 256 /* chained NTCreateXReadX will probably be biggest */ | 83 | #define MAX_CIFS_HDR_SIZE 256 /* is future chained NTCreateXReadX bigger? */ |
| 80 | 84 | ||
| 81 | /* internal cifs vfs structures */ | 85 | /* internal cifs vfs structures */ |
| 82 | /***************************************************************** | 86 | /***************************************************************** |
| @@ -129,10 +133,11 @@ | |||
| 129 | /* | 133 | /* |
| 130 | * SMB flag definitions | 134 | * SMB flag definitions |
| 131 | */ | 135 | */ |
| 132 | #define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock primitives */ | 136 | #define SMBFLG_EXTD_LOCK 0x01 /* server supports lock-read write-unlock smb */ |
| 133 | #define SMBFLG_RCV_POSTED 0x02 /* obsolete */ | 137 | #define SMBFLG_RCV_POSTED 0x02 /* obsolete */ |
| 134 | #define SMBFLG_RSVD 0x04 | 138 | #define SMBFLG_RSVD 0x04 |
| 135 | #define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off implies case sensitive file handling requested) */ | 139 | #define SMBFLG_CASELESS 0x08 /* all pathnames treated as caseless (off |
| 140 | implies case sensitive file handling request) */ | ||
| 136 | #define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */ | 141 | #define SMBFLG_CANONICAL_PATH_FORMAT 0x10 /* obsolete */ |
| 137 | #define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */ | 142 | #define SMBFLG_OLD_OPLOCK 0x20 /* obsolete */ |
| 138 | #define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */ | 143 | #define SMBFLG_OLD_OPLOCK_NOTIFY 0x40 /* obsolete */ |
| @@ -141,7 +146,8 @@ | |||
| 141 | /* | 146 | /* |
| 142 | * SMB flag2 definitions | 147 | * SMB flag2 definitions |
| 143 | */ | 148 | */ |
| 144 | #define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3) path names in response */ | 149 | #define SMBFLG2_KNOWS_LONG_NAMES cpu_to_le16(1) /* can send long (non-8.3) |
| 150 | path names in response */ | ||
| 145 | #define SMBFLG2_KNOWS_EAS cpu_to_le16(2) | 151 | #define SMBFLG2_KNOWS_EAS cpu_to_le16(2) |
| 146 | #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4) | 152 | #define SMBFLG2_SECURITY_SIGNATURE cpu_to_le16(4) |
| 147 | #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) | 153 | #define SMBFLG2_IS_LONG_NAME cpu_to_le16(0x40) |
| @@ -160,32 +166,32 @@ | |||
| 160 | * file and can have any suitable combination of the following values: | 166 | * file and can have any suitable combination of the following values: |
| 161 | */ | 167 | */ |
| 162 | 168 | ||
| 163 | #define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ | 169 | #define FILE_READ_DATA 0x00000001 /* Data can be read from the file */ |
| 164 | #define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ | 170 | #define FILE_WRITE_DATA 0x00000002 /* Data can be written to the file */ |
| 165 | #define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ | 171 | #define FILE_APPEND_DATA 0x00000004 /* Data can be appended to the file */ |
| 166 | #define FILE_READ_EA 0x00000008 /* Extended attributes associated */ | 172 | #define FILE_READ_EA 0x00000008 /* Extended attributes associated */ |
| 167 | /* with the file can be read */ | 173 | /* with the file can be read */ |
| 168 | #define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ | 174 | #define FILE_WRITE_EA 0x00000010 /* Extended attributes associated */ |
| 169 | /* with the file can be written */ | 175 | /* with the file can be written */ |
| 170 | #define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ | 176 | #define FILE_EXECUTE 0x00000020 /*Data can be read into memory from */ |
| 171 | /* the file using system paging I/O */ | 177 | /* the file using system paging I/O */ |
| 172 | #define FILE_DELETE_CHILD 0x00000040 | 178 | #define FILE_DELETE_CHILD 0x00000040 |
| 173 | #define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ | 179 | #define FILE_READ_ATTRIBUTES 0x00000080 /* Attributes associated with the */ |
| 174 | /* file can be read */ | 180 | /* file can be read */ |
| 175 | #define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ | 181 | #define FILE_WRITE_ATTRIBUTES 0x00000100 /* Attributes associated with the */ |
| 176 | /* file can be written */ | 182 | /* file can be written */ |
| 177 | #define DELETE 0x00010000 /* The file can be deleted */ | 183 | #define DELETE 0x00010000 /* The file can be deleted */ |
| 178 | #define READ_CONTROL 0x00020000 /* The access control list and */ | 184 | #define READ_CONTROL 0x00020000 /* The access control list and */ |
| 179 | /* ownership associated with the */ | 185 | /* ownership associated with the */ |
| 180 | /* file can be read */ | 186 | /* file can be read */ |
| 181 | #define WRITE_DAC 0x00040000 /* The access control list and */ | 187 | #define WRITE_DAC 0x00040000 /* The access control list and */ |
| 182 | /* ownership associated with the */ | 188 | /* ownership associated with the */ |
| 183 | /* file can be written. */ | 189 | /* file can be written. */ |
| 184 | #define WRITE_OWNER 0x00080000 /* Ownership information associated */ | 190 | #define WRITE_OWNER 0x00080000 /* Ownership information associated */ |
| 185 | /* with the file can be written */ | 191 | /* with the file can be written */ |
| 186 | #define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ | 192 | #define SYNCHRONIZE 0x00100000 /* The file handle can waited on to */ |
| 187 | /* synchronize with the completion */ | 193 | /* synchronize with the completion */ |
| 188 | /* of an input/output request */ | 194 | /* of an input/output request */ |
| 189 | #define GENERIC_ALL 0x10000000 | 195 | #define GENERIC_ALL 0x10000000 |
| 190 | #define GENERIC_EXECUTE 0x20000000 | 196 | #define GENERIC_EXECUTE 0x20000000 |
| 191 | #define GENERIC_WRITE 0x40000000 | 197 | #define GENERIC_WRITE 0x40000000 |
| @@ -193,7 +199,7 @@ | |||
| 193 | /* In summary - Relevant file */ | 199 | /* In summary - Relevant file */ |
| 194 | /* access flags from CIFS are */ | 200 | /* access flags from CIFS are */ |
| 195 | /* file_read_data, file_write_data */ | 201 | /* file_read_data, file_write_data */ |
| 196 | /* file_execute, file_read_attributes */ | 202 | /* file_execute, file_read_attributes*/ |
| 197 | /* write_dac, and delete. */ | 203 | /* write_dac, and delete. */ |
| 198 | 204 | ||
| 199 | /* | 205 | /* |
| @@ -238,7 +244,8 @@ | |||
| 238 | #define ATTR_SPARSE 0x0200 | 244 | #define ATTR_SPARSE 0x0200 |
| 239 | #define ATTR_REPARSE 0x0400 | 245 | #define ATTR_REPARSE 0x0400 |
| 240 | #define ATTR_COMPRESSED 0x0800 | 246 | #define ATTR_COMPRESSED 0x0800 |
| 241 | #define ATTR_OFFLINE 0x1000 /* ie file not immediately available - offline storage */ | 247 | #define ATTR_OFFLINE 0x1000 /* ie file not immediately available - |
| 248 | on offline storage */ | ||
| 242 | #define ATTR_NOT_CONTENT_INDEXED 0x2000 | 249 | #define ATTR_NOT_CONTENT_INDEXED 0x2000 |
| 243 | #define ATTR_ENCRYPTED 0x4000 | 250 | #define ATTR_ENCRYPTED 0x4000 |
| 244 | #define ATTR_POSIX_SEMANTICS 0x01000000 | 251 | #define ATTR_POSIX_SEMANTICS 0x01000000 |
| @@ -267,10 +274,18 @@ | |||
| 267 | /* CreateOptions */ | 274 | /* CreateOptions */ |
| 268 | #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ | 275 | #define CREATE_NOT_FILE 0x00000001 /* if set must not be file */ |
| 269 | #define CREATE_WRITE_THROUGH 0x00000002 | 276 | #define CREATE_WRITE_THROUGH 0x00000002 |
| 270 | #define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ | 277 | #define CREATE_SEQUENTIAL 0x00000004 |
| 278 | #define CREATE_SYNC_ALERT 0x00000010 | ||
| 279 | #define CREATE_ASYNC_ALERT 0x00000020 | ||
| 280 | #define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */ | ||
| 281 | #define CREATE_NO_EA_KNOWLEDGE 0x00000200 | ||
| 282 | #define CREATE_EIGHT_DOT_THREE 0x00000400 | ||
| 271 | #define CREATE_RANDOM_ACCESS 0x00000800 | 283 | #define CREATE_RANDOM_ACCESS 0x00000800 |
| 272 | #define CREATE_DELETE_ON_CLOSE 0x00001000 | 284 | #define CREATE_DELETE_ON_CLOSE 0x00001000 |
| 285 | #define CREATE_OPEN_BY_ID 0x00002000 | ||
| 273 | #define OPEN_REPARSE_POINT 0x00200000 | 286 | #define OPEN_REPARSE_POINT 0x00200000 |
| 287 | #define CREATE_OPTIONS_MASK 0x007FFFFF | ||
| 288 | #define CREATE_OPTION_SPECIAL 0x20000000 /* system. NB not sent over wire */ | ||
| 274 | 289 | ||
| 275 | /* ImpersonationLevel flags */ | 290 | /* ImpersonationLevel flags */ |
| 276 | #define SECURITY_ANONYMOUS 0 | 291 | #define SECURITY_ANONYMOUS 0 |
| @@ -297,10 +312,10 @@ | |||
| 297 | #define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ | 312 | #define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ |
| 298 | #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ | 313 | #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ |
| 299 | 314 | ||
| 300 | #pragma pack(1) | ||
| 301 | |||
| 302 | struct smb_hdr { | 315 | struct smb_hdr { |
| 303 | __u32 smb_buf_length; /* big endian on wire *//* BB length is only two or three bytes - with one or two byte type preceding it but that is always zero - we could mask the type byte off just in case BB */ | 316 | __u32 smb_buf_length; /* big endian on wire *//* BB length is only two |
| 317 | or three bytes - with one or two byte type preceding it that are | ||
| 318 | zero - we could mask the type byte off just in case BB */ | ||
| 304 | __u8 Protocol[4]; | 319 | __u8 Protocol[4]; |
| 305 | __u8 Command; | 320 | __u8 Command; |
| 306 | union { | 321 | union { |
| @@ -308,9 +323,9 @@ struct smb_hdr { | |||
| 308 | __u8 ErrorClass; | 323 | __u8 ErrorClass; |
| 309 | __u8 Reserved; | 324 | __u8 Reserved; |
| 310 | __le16 Error; | 325 | __le16 Error; |
| 311 | } DosError; | 326 | } __attribute__((packed)) DosError; |
| 312 | __le32 CifsError; | 327 | __le32 CifsError; |
| 313 | } Status; | 328 | } __attribute__((packed)) Status; |
| 314 | __u8 Flags; | 329 | __u8 Flags; |
| 315 | __le16 Flags2; /* note: le */ | 330 | __le16 Flags2; /* note: le */ |
| 316 | __le16 PidHigh; | 331 | __le16 PidHigh; |
| @@ -318,16 +333,16 @@ struct smb_hdr { | |||
| 318 | struct { | 333 | struct { |
| 319 | __le32 SequenceNumber; /* le */ | 334 | __le32 SequenceNumber; /* le */ |
| 320 | __u32 Reserved; /* zero */ | 335 | __u32 Reserved; /* zero */ |
| 321 | } Sequence; | 336 | } __attribute__((packed)) Sequence; |
| 322 | __u8 SecuritySignature[8]; /* le */ | 337 | __u8 SecuritySignature[8]; /* le */ |
| 323 | } Signature; | 338 | } __attribute__((packed)) Signature; |
| 324 | __u8 pad[2]; | 339 | __u8 pad[2]; |
| 325 | __u16 Tid; | 340 | __u16 Tid; |
| 326 | __le16 Pid; | 341 | __le16 Pid; |
| 327 | __u16 Uid; | 342 | __u16 Uid; |
| 328 | __u16 Mid; | 343 | __u16 Mid; |
| 329 | __u8 WordCount; | 344 | __u8 WordCount; |
| 330 | }; | 345 | } __attribute__((packed)); |
| 331 | /* given a pointer to an smb_hdr retrieve the value of byte count */ | 346 | /* given a pointer to an smb_hdr retrieve the value of byte count */ |
| 332 | #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) | 347 | #define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) |
| 333 | #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) | 348 | #define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) |
| @@ -379,7 +394,7 @@ typedef struct negotiate_req { | |||
| 379 | struct smb_hdr hdr; /* wct = 0 */ | 394 | struct smb_hdr hdr; /* wct = 0 */ |
| 380 | __le16 ByteCount; | 395 | __le16 ByteCount; |
| 381 | unsigned char DialectsArray[1]; | 396 | unsigned char DialectsArray[1]; |
| 382 | } NEGOTIATE_REQ; | 397 | } __attribute__((packed)) NEGOTIATE_REQ; |
| 383 | 398 | ||
| 384 | typedef struct negotiate_rsp { | 399 | typedef struct negotiate_rsp { |
| 385 | struct smb_hdr hdr; /* wct = 17 */ | 400 | struct smb_hdr hdr; /* wct = 17 */ |
| @@ -397,16 +412,16 @@ typedef struct negotiate_rsp { | |||
| 397 | __u8 EncryptionKeyLength; | 412 | __u8 EncryptionKeyLength; |
| 398 | __u16 ByteCount; | 413 | __u16 ByteCount; |
| 399 | union { | 414 | union { |
| 400 | unsigned char EncryptionKey[1]; /* if cap extended security is off */ | 415 | unsigned char EncryptionKey[1]; /* cap extended security off */ |
| 401 | /* followed by Domain name - if extended security is off */ | 416 | /* followed by Domain name - if extended security is off */ |
| 402 | /* followed by 16 bytes of server GUID */ | 417 | /* followed by 16 bytes of server GUID */ |
| 403 | /* followed by security blob if cap_extended_security negotiated */ | 418 | /* then security blob if cap_extended_security negotiated */ |
| 404 | struct { | 419 | struct { |
| 405 | unsigned char GUID[16]; | 420 | unsigned char GUID[16]; |
| 406 | unsigned char SecurityBlob[1]; | 421 | unsigned char SecurityBlob[1]; |
| 407 | } extended_response; | 422 | } __attribute__((packed)) extended_response; |
| 408 | } u; | 423 | } __attribute__((packed)) u; |
| 409 | } NEGOTIATE_RSP; | 424 | } __attribute__((packed)) NEGOTIATE_RSP; |
| 410 | 425 | ||
| 411 | /* SecurityMode bits */ | 426 | /* SecurityMode bits */ |
| 412 | #define SECMODE_USER 0x01 /* off indicates share level security */ | 427 | #define SECMODE_USER 0x01 /* off indicates share level security */ |
| @@ -452,7 +467,8 @@ typedef union smb_com_session_setup_andx { | |||
| 452 | unsigned char SecurityBlob[1]; /* followed by */ | 467 | unsigned char SecurityBlob[1]; /* followed by */ |
| 453 | /* STRING NativeOS */ | 468 | /* STRING NativeOS */ |
| 454 | /* STRING NativeLanMan */ | 469 | /* STRING NativeLanMan */ |
| 455 | } req; /* NTLM request format (with extended security */ | 470 | } __attribute__((packed)) req; /* NTLM request format (with |
| 471 | extended security */ | ||
| 456 | 472 | ||
| 457 | struct { /* request format */ | 473 | struct { /* request format */ |
| 458 | struct smb_hdr hdr; /* wct = 13 */ | 474 | struct smb_hdr hdr; /* wct = 13 */ |
| @@ -463,18 +479,19 @@ typedef union smb_com_session_setup_andx { | |||
| 463 | __le16 MaxMpxCount; | 479 | __le16 MaxMpxCount; |
| 464 | __le16 VcNumber; | 480 | __le16 VcNumber; |
| 465 | __u32 SessionKey; | 481 | __u32 SessionKey; |
| 466 | __le16 CaseInsensitivePasswordLength; /* ASCII password length */ | 482 | __le16 CaseInsensitivePasswordLength; /* ASCII password len */ |
| 467 | __le16 CaseSensitivePasswordLength; /* Unicode password length */ | 483 | __le16 CaseSensitivePasswordLength; /* Unicode password length*/ |
| 468 | __u32 Reserved; /* see below */ | 484 | __u32 Reserved; /* see below */ |
| 469 | __le32 Capabilities; | 485 | __le32 Capabilities; |
| 470 | __le16 ByteCount; | 486 | __le16 ByteCount; |
| 471 | unsigned char CaseInsensitivePassword[1]; /* followed by: */ | 487 | unsigned char CaseInsensitivePassword[1]; /* followed by: */ |
| 472 | /* unsigned char * CaseSensitivePassword; */ | 488 | /* unsigned char * CaseSensitivePassword; */ |
| 473 | /* STRING AccountName */ | 489 | /* STRING AccountName */ |
| 474 | /* STRING PrimaryDomain */ | 490 | /* STRING PrimaryDomain */ |
| 475 | /* STRING NativeOS */ | 491 | /* STRING NativeOS */ |
| 476 | /* STRING NativeLanMan */ | 492 | /* STRING NativeLanMan */ |
| 477 | } req_no_secext; /* NTLM request format (without extended security */ | 493 | } __attribute__((packed)) req_no_secext; /* NTLM request format (without |
| 494 | extended security */ | ||
| 478 | 495 | ||
| 479 | struct { /* default (NTLM) response format */ | 496 | struct { /* default (NTLM) response format */ |
| 480 | struct smb_hdr hdr; /* wct = 4 */ | 497 | struct smb_hdr hdr; /* wct = 4 */ |
| @@ -488,7 +505,7 @@ typedef union smb_com_session_setup_andx { | |||
| 488 | /* unsigned char * NativeOS; */ | 505 | /* unsigned char * NativeOS; */ |
| 489 | /* unsigned char * NativeLanMan; */ | 506 | /* unsigned char * NativeLanMan; */ |
| 490 | /* unsigned char * PrimaryDomain; */ | 507 | /* unsigned char * PrimaryDomain; */ |
| 491 | } resp; /* NTLM response format (with or without extended security */ | 508 | } __attribute__((packed)) resp; /* NTLM response format (with or without extended security */ |
| 492 | 509 | ||
| 493 | struct { /* request format */ | 510 | struct { /* request format */ |
| 494 | struct smb_hdr hdr; /* wct = 10 */ | 511 | struct smb_hdr hdr; /* wct = 10 */ |
| @@ -507,7 +524,7 @@ typedef union smb_com_session_setup_andx { | |||
| 507 | /* STRING PrimaryDomain */ | 524 | /* STRING PrimaryDomain */ |
| 508 | /* STRING NativeOS */ | 525 | /* STRING NativeOS */ |
| 509 | /* STRING NativeLanMan */ | 526 | /* STRING NativeLanMan */ |
| 510 | } old_req; /* pre-NTLM (LANMAN2.1) request format */ | 527 | } __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) request format */ |
| 511 | 528 | ||
| 512 | struct { /* default (NTLM) response format */ | 529 | struct { /* default (NTLM) response format */ |
| 513 | struct smb_hdr hdr; /* wct = 3 */ | 530 | struct smb_hdr hdr; /* wct = 3 */ |
| @@ -519,8 +536,8 @@ typedef union smb_com_session_setup_andx { | |||
| 519 | unsigned char NativeOS[1]; /* followed by */ | 536 | unsigned char NativeOS[1]; /* followed by */ |
| 520 | /* unsigned char * NativeLanMan; */ | 537 | /* unsigned char * NativeLanMan; */ |
| 521 | /* unsigned char * PrimaryDomain; */ | 538 | /* unsigned char * PrimaryDomain; */ |
| 522 | } old_resp; /* pre-NTLM (LANMAN2.1) response format */ | 539 | } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response format */ |
| 523 | } SESSION_SETUP_ANDX; | 540 | } __attribute__((packed)) SESSION_SETUP_ANDX; |
| 524 | 541 | ||
| 525 | #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" | 542 | #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" |
| 526 | 543 | ||
| @@ -530,7 +547,8 @@ typedef union smb_com_session_setup_andx { | |||
| 530 | #define CAP_NT_SMBS 0x00000010 | 547 | #define CAP_NT_SMBS 0x00000010 |
| 531 | #define CAP_STATUS32 0x00000040 | 548 | #define CAP_STATUS32 0x00000040 |
| 532 | #define CAP_LEVEL_II_OPLOCKS 0x00000080 | 549 | #define CAP_LEVEL_II_OPLOCKS 0x00000080 |
| 533 | #define CAP_NT_FIND 0x00000200 /* reserved should be zero (presumably because NT_SMBs implies the same thing) */ | 550 | #define CAP_NT_FIND 0x00000200 /* reserved should be zero |
| 551 | (because NT_SMBs implies the same thing?) */ | ||
| 534 | #define CAP_BULK_TRANSFER 0x20000000 | 552 | #define CAP_BULK_TRANSFER 0x20000000 |
| 535 | #define CAP_EXTENDED_SECURITY 0x80000000 | 553 | #define CAP_EXTENDED_SECURITY 0x80000000 |
| 536 | 554 | ||
| @@ -548,7 +566,7 @@ typedef struct smb_com_tconx_req { | |||
| 548 | unsigned char Password[1]; /* followed by */ | 566 | unsigned char Password[1]; /* followed by */ |
| 549 | /* STRING Path *//* \\server\share name */ | 567 | /* STRING Path *//* \\server\share name */ |
| 550 | /* STRING Service */ | 568 | /* STRING Service */ |
| 551 | } TCONX_REQ; | 569 | } __attribute__((packed)) TCONX_REQ; |
| 552 | 570 | ||
| 553 | typedef struct smb_com_tconx_rsp { | 571 | typedef struct smb_com_tconx_rsp { |
| 554 | struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ | 572 | struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ |
| @@ -559,13 +577,14 @@ typedef struct smb_com_tconx_rsp { | |||
| 559 | __u16 ByteCount; | 577 | __u16 ByteCount; |
| 560 | unsigned char Service[1]; /* always ASCII, not Unicode */ | 578 | unsigned char Service[1]; /* always ASCII, not Unicode */ |
| 561 | /* STRING NativeFileSystem */ | 579 | /* STRING NativeFileSystem */ |
| 562 | } TCONX_RSP; | 580 | } __attribute__((packed)) TCONX_RSP; |
| 563 | 581 | ||
| 564 | /* tree connect Flags */ | 582 | /* tree connect Flags */ |
| 565 | #define DISCONNECT_TID 0x0001 | 583 | #define DISCONNECT_TID 0x0001 |
| 566 | #define TCON_EXTENDED_SECINFO 0x0008 | 584 | #define TCON_EXTENDED_SECINFO 0x0008 |
| 567 | /* OptionalSupport bits */ | 585 | /* OptionalSupport bits */ |
| 568 | #define SMB_SUPPORT_SEARCH_BITS 0x0001 /* must have bits (exclusive searches suppt. */ | 586 | #define SMB_SUPPORT_SEARCH_BITS 0x0001 /* "must have" directory search bits |
| 587 | (exclusive searches supported) */ | ||
| 569 | #define SMB_SHARE_IS_IN_DFS 0x0002 | 588 | #define SMB_SHARE_IS_IN_DFS 0x0002 |
| 570 | 589 | ||
| 571 | typedef struct smb_com_logoff_andx_req { | 590 | typedef struct smb_com_logoff_andx_req { |
| @@ -574,7 +593,7 @@ typedef struct smb_com_logoff_andx_req { | |||
| 574 | __u8 AndXReserved; | 593 | __u8 AndXReserved; |
| 575 | __u16 AndXOffset; | 594 | __u16 AndXOffset; |
| 576 | __u16 ByteCount; | 595 | __u16 ByteCount; |
| 577 | } LOGOFF_ANDX_REQ; | 596 | } __attribute__((packed)) LOGOFF_ANDX_REQ; |
| 578 | 597 | ||
| 579 | typedef struct smb_com_logoff_andx_rsp { | 598 | typedef struct smb_com_logoff_andx_rsp { |
| 580 | struct smb_hdr hdr; /* wct = 2 */ | 599 | struct smb_hdr hdr; /* wct = 2 */ |
| @@ -582,38 +601,39 @@ typedef struct smb_com_logoff_andx_rsp { | |||
| 582 | __u8 AndXReserved; | 601 | __u8 AndXReserved; |
| 583 | __u16 AndXOffset; | 602 | __u16 AndXOffset; |
| 584 | __u16 ByteCount; | 603 | __u16 ByteCount; |
| 585 | } LOGOFF_ANDX_RSP; | 604 | } __attribute__((packed)) LOGOFF_ANDX_RSP; |
| 586 | 605 | ||
| 587 | typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ | 606 | typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ |
| 588 | struct { | 607 | struct { |
| 589 | struct smb_hdr hdr; /* wct = 0 */ | 608 | struct smb_hdr hdr; /* wct = 0 */ |
| 590 | __u16 ByteCount; /* bcc = 0 */ | 609 | __u16 ByteCount; /* bcc = 0 */ |
| 591 | } req; | 610 | } __attribute__((packed)) req; |
| 592 | struct { | 611 | struct { |
| 593 | struct smb_hdr hdr; /* wct = 0 */ | 612 | struct smb_hdr hdr; /* wct = 0 */ |
| 594 | __u16 ByteCount; /* bcc = 0 */ | 613 | __u16 ByteCount; /* bcc = 0 */ |
| 595 | } resp; | 614 | } __attribute__((packed)) resp; |
| 596 | } TREE_DISCONNECT; | 615 | } __attribute__((packed)) TREE_DISCONNECT; |
| 597 | 616 | ||
| 598 | typedef struct smb_com_close_req { | 617 | typedef struct smb_com_close_req { |
| 599 | struct smb_hdr hdr; /* wct = 3 */ | 618 | struct smb_hdr hdr; /* wct = 3 */ |
| 600 | __u16 FileID; | 619 | __u16 FileID; |
| 601 | __u32 LastWriteTime; /* should be zero */ | 620 | __u32 LastWriteTime; /* should be zero */ |
| 602 | __u16 ByteCount; /* 0 */ | 621 | __u16 ByteCount; /* 0 */ |
| 603 | } CLOSE_REQ; | 622 | } __attribute__((packed)) CLOSE_REQ; |
| 604 | 623 | ||
| 605 | typedef struct smb_com_close_rsp { | 624 | typedef struct smb_com_close_rsp { |
| 606 | struct smb_hdr hdr; /* wct = 0 */ | 625 | struct smb_hdr hdr; /* wct = 0 */ |
| 607 | __u16 ByteCount; /* bct = 0 */ | 626 | __u16 ByteCount; /* bct = 0 */ |
| 608 | } CLOSE_RSP; | 627 | } __attribute__((packed)) CLOSE_RSP; |
| 609 | 628 | ||
| 610 | typedef struct smb_com_findclose_req { | 629 | typedef struct smb_com_findclose_req { |
| 611 | struct smb_hdr hdr; /* wct = 1 */ | 630 | struct smb_hdr hdr; /* wct = 1 */ |
| 612 | __u16 FileID; | 631 | __u16 FileID; |
| 613 | __u16 ByteCount; /* 0 */ | 632 | __u16 ByteCount; /* 0 */ |
| 614 | } FINDCLOSE_REQ; | 633 | } __attribute__((packed)) FINDCLOSE_REQ; |
| 615 | 634 | ||
| 616 | /* OpenFlags */ | 635 | /* OpenFlags */ |
| 636 | #define REQ_MORE_INFO 0x00000001 /* legacy (OPEN_AND_X) only */ | ||
| 617 | #define REQ_OPLOCK 0x00000002 | 637 | #define REQ_OPLOCK 0x00000002 |
| 618 | #define REQ_BATCHOPLOCK 0x00000004 | 638 | #define REQ_BATCHOPLOCK 0x00000004 |
| 619 | #define REQ_OPENDIRONLY 0x00000008 | 639 | #define REQ_OPENDIRONLY 0x00000008 |
| @@ -637,7 +657,7 @@ typedef struct smb_com_open_req { /* also handles create */ | |||
| 637 | __u8 SecurityFlags; | 657 | __u8 SecurityFlags; |
| 638 | __le16 ByteCount; | 658 | __le16 ByteCount; |
| 639 | char fileName[1]; | 659 | char fileName[1]; |
| 640 | } OPEN_REQ; | 660 | } __attribute__((packed)) OPEN_REQ; |
| 641 | 661 | ||
| 642 | /* open response: oplock levels */ | 662 | /* open response: oplock levels */ |
| 643 | #define OPLOCK_NONE 0 | 663 | #define OPLOCK_NONE 0 |
| @@ -667,7 +687,63 @@ typedef struct smb_com_open_rsp { | |||
| 667 | __le16 DeviceState; | 687 | __le16 DeviceState; |
| 668 | __u8 DirectoryFlag; | 688 | __u8 DirectoryFlag; |
| 669 | __u16 ByteCount; /* bct = 0 */ | 689 | __u16 ByteCount; /* bct = 0 */ |
| 670 | } OPEN_RSP; | 690 | } __attribute__((packed)) OPEN_RSP; |
| 691 | |||
| 692 | /* format of legacy open request */ | ||
| 693 | typedef struct smb_com_openx_req { | ||
| 694 | struct smb_hdr hdr; /* wct = 15 */ | ||
| 695 | __u8 AndXCommand; | ||
| 696 | __u8 AndXReserved; | ||
| 697 | __le16 AndXOffset; | ||
| 698 | __le16 OpenFlags; | ||
| 699 | __le16 Mode; | ||
| 700 | __le16 Sattr; /* search attributes */ | ||
| 701 | __le16 FileAttributes; /* dos attrs */ | ||
| 702 | __le32 CreateTime; /* os2 format */ | ||
| 703 | __le16 OpenFunction; | ||
| 704 | __le32 EndOfFile; | ||
| 705 | __le32 Timeout; | ||
| 706 | __le32 Reserved; | ||
| 707 | __le16 ByteCount; /* file name follows */ | ||
| 708 | char fileName[1]; | ||
| 709 | } __attribute__((packed)) OPENX_REQ; | ||
| 710 | |||
| 711 | typedef struct smb_com_openx_rsp { | ||
| 712 | struct smb_hdr hdr; /* wct = 15 */ | ||
| 713 | __u8 AndXCommand; | ||
| 714 | __u8 AndXReserved; | ||
| 715 | __le16 AndXOffset; | ||
| 716 | __u16 Fid; | ||
| 717 | __le16 FileAttributes; | ||
| 718 | __le32 LastWriteTime; /* os2 format */ | ||
| 719 | __le32 EndOfFile; | ||
| 720 | __le16 Access; | ||
| 721 | __le16 FileType; | ||
| 722 | __le16 IPCState; | ||
| 723 | __le16 Action; | ||
| 724 | __u32 FileId; | ||
| 725 | __u16 Reserved; | ||
| 726 | __u16 ByteCount; | ||
| 727 | } __attribute__((packed)) OPENX_RSP; | ||
| 728 | |||
| 729 | /* Legacy write request for older servers */ | ||
| 730 | typedef struct smb_com_writex_req { | ||
| 731 | struct smb_hdr hdr; /* wct = 12 */ | ||
| 732 | __u8 AndXCommand; | ||
| 733 | __u8 AndXReserved; | ||
| 734 | __le16 AndXOffset; | ||
| 735 | __u16 Fid; | ||
| 736 | __le32 OffsetLow; | ||
| 737 | __u32 Reserved; /* Timeout */ | ||
| 738 | __le16 WriteMode; /* 1 = write through */ | ||
| 739 | __le16 Remaining; | ||
| 740 | __le16 Reserved2; | ||
| 741 | __le16 DataLengthLow; | ||
| 742 | __le16 DataOffset; | ||
| 743 | __le16 ByteCount; | ||
| 744 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ | ||
| 745 | char Data[0]; | ||
| 746 | } __attribute__((packed)) WRITEX_REQ; | ||
| 671 | 747 | ||
| 672 | typedef struct smb_com_write_req { | 748 | typedef struct smb_com_write_req { |
| 673 | struct smb_hdr hdr; /* wct = 14 */ | 749 | struct smb_hdr hdr; /* wct = 14 */ |
| @@ -686,7 +762,7 @@ typedef struct smb_com_write_req { | |||
| 686 | __le16 ByteCount; | 762 | __le16 ByteCount; |
| 687 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ | 763 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ |
| 688 | char Data[0]; | 764 | char Data[0]; |
| 689 | } WRITE_REQ; | 765 | } __attribute__((packed)) WRITE_REQ; |
| 690 | 766 | ||
| 691 | typedef struct smb_com_write_rsp { | 767 | typedef struct smb_com_write_rsp { |
| 692 | struct smb_hdr hdr; /* wct = 6 */ | 768 | struct smb_hdr hdr; /* wct = 6 */ |
| @@ -698,7 +774,22 @@ typedef struct smb_com_write_rsp { | |||
| 698 | __le16 CountHigh; | 774 | __le16 CountHigh; |
| 699 | __u16 Reserved; | 775 | __u16 Reserved; |
| 700 | __u16 ByteCount; | 776 | __u16 ByteCount; |
| 701 | } WRITE_RSP; | 777 | } __attribute__((packed)) WRITE_RSP; |
| 778 | |||
| 779 | /* legacy read request for older servers */ | ||
| 780 | typedef struct smb_com_readx_req { | ||
| 781 | struct smb_hdr hdr; /* wct = 10 */ | ||
| 782 | __u8 AndXCommand; | ||
| 783 | __u8 AndXReserved; | ||
| 784 | __le16 AndXOffset; | ||
| 785 | __u16 Fid; | ||
| 786 | __le32 OffsetLow; | ||
| 787 | __le16 MaxCount; | ||
| 788 | __le16 MinCount; /* obsolete */ | ||
| 789 | __le32 Reserved; | ||
| 790 | __le16 Remaining; | ||
| 791 | __le16 ByteCount; | ||
| 792 | } __attribute__((packed)) READX_REQ; | ||
| 702 | 793 | ||
| 703 | typedef struct smb_com_read_req { | 794 | typedef struct smb_com_read_req { |
| 704 | struct smb_hdr hdr; /* wct = 12 */ | 795 | struct smb_hdr hdr; /* wct = 12 */ |
| @@ -713,7 +804,7 @@ typedef struct smb_com_read_req { | |||
| 713 | __le16 Remaining; | 804 | __le16 Remaining; |
| 714 | __le32 OffsetHigh; | 805 | __le32 OffsetHigh; |
| 715 | __le16 ByteCount; | 806 | __le16 ByteCount; |
| 716 | } READ_REQ; | 807 | } __attribute__((packed)) READ_REQ; |
| 717 | 808 | ||
| 718 | typedef struct smb_com_read_rsp { | 809 | typedef struct smb_com_read_rsp { |
| 719 | struct smb_hdr hdr; /* wct = 12 */ | 810 | struct smb_hdr hdr; /* wct = 12 */ |
| @@ -730,7 +821,7 @@ typedef struct smb_com_read_rsp { | |||
| 730 | __u16 ByteCount; | 821 | __u16 ByteCount; |
| 731 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ | 822 | __u8 Pad; /* BB check for whether padded to DWORD boundary and optimum performance here */ |
| 732 | char Data[1]; | 823 | char Data[1]; |
| 733 | } READ_RSP; | 824 | } __attribute__((packed)) READ_RSP; |
| 734 | 825 | ||
| 735 | typedef struct locking_andx_range { | 826 | typedef struct locking_andx_range { |
| 736 | __le16 Pid; | 827 | __le16 Pid; |
| @@ -739,7 +830,7 @@ typedef struct locking_andx_range { | |||
| 739 | __le32 OffsetLow; | 830 | __le32 OffsetLow; |
| 740 | __le32 LengthHigh; | 831 | __le32 LengthHigh; |
| 741 | __le32 LengthLow; | 832 | __le32 LengthLow; |
| 742 | } LOCKING_ANDX_RANGE; | 833 | } __attribute__((packed)) LOCKING_ANDX_RANGE; |
| 743 | 834 | ||
| 744 | #define LOCKING_ANDX_SHARED_LOCK 0x01 | 835 | #define LOCKING_ANDX_SHARED_LOCK 0x01 |
| 745 | #define LOCKING_ANDX_OPLOCK_RELEASE 0x02 | 836 | #define LOCKING_ANDX_OPLOCK_RELEASE 0x02 |
| @@ -760,7 +851,7 @@ typedef struct smb_com_lock_req { | |||
| 760 | __le16 NumberOfLocks; | 851 | __le16 NumberOfLocks; |
| 761 | __le16 ByteCount; | 852 | __le16 ByteCount; |
| 762 | LOCKING_ANDX_RANGE Locks[1]; | 853 | LOCKING_ANDX_RANGE Locks[1]; |
| 763 | } LOCK_REQ; | 854 | } __attribute__((packed)) LOCK_REQ; |
| 764 | 855 | ||
| 765 | 856 | ||
| 766 | typedef struct cifs_posix_lock { | 857 | typedef struct cifs_posix_lock { |
| @@ -770,7 +861,7 @@ typedef struct cifs_posix_lock { | |||
| 770 | __le64 start; | 861 | __le64 start; |
| 771 | __le64 length; | 862 | __le64 length; |
| 772 | /* BB what about additional owner info to identify network client */ | 863 | /* BB what about additional owner info to identify network client */ |
| 773 | } CIFS_POSIX_LOCK; | 864 | } __attribute__((packed)) CIFS_POSIX_LOCK; |
| 774 | 865 | ||
| 775 | typedef struct smb_com_lock_rsp { | 866 | typedef struct smb_com_lock_rsp { |
| 776 | struct smb_hdr hdr; /* wct = 2 */ | 867 | struct smb_hdr hdr; /* wct = 2 */ |
| @@ -778,7 +869,7 @@ typedef struct smb_com_lock_rsp { | |||
| 778 | __u8 AndXReserved; | 869 | __u8 AndXReserved; |
| 779 | __le16 AndXOffset; | 870 | __le16 AndXOffset; |
| 780 | __u16 ByteCount; | 871 | __u16 ByteCount; |
| 781 | } LOCK_RSP; | 872 | } __attribute__((packed)) LOCK_RSP; |
| 782 | 873 | ||
| 783 | typedef struct smb_com_rename_req { | 874 | typedef struct smb_com_rename_req { |
| 784 | struct smb_hdr hdr; /* wct = 1 */ | 875 | struct smb_hdr hdr; /* wct = 1 */ |
| @@ -788,7 +879,7 @@ typedef struct smb_com_rename_req { | |||
| 788 | unsigned char OldFileName[1]; | 879 | unsigned char OldFileName[1]; |
| 789 | /* followed by __u8 BufferFormat2 */ | 880 | /* followed by __u8 BufferFormat2 */ |
| 790 | /* followed by NewFileName */ | 881 | /* followed by NewFileName */ |
| 791 | } RENAME_REQ; | 882 | } __attribute__((packed)) RENAME_REQ; |
| 792 | 883 | ||
| 793 | /* copy request flags */ | 884 | /* copy request flags */ |
| 794 | #define COPY_MUST_BE_FILE 0x0001 | 885 | #define COPY_MUST_BE_FILE 0x0001 |
| @@ -808,7 +899,7 @@ typedef struct smb_com_copy_req { | |||
| 808 | unsigned char OldFileName[1]; | 899 | unsigned char OldFileName[1]; |
| 809 | /* followed by __u8 BufferFormat2 */ | 900 | /* followed by __u8 BufferFormat2 */ |
| 810 | /* followed by NewFileName string */ | 901 | /* followed by NewFileName string */ |
| 811 | } COPY_REQ; | 902 | } __attribute__((packed)) COPY_REQ; |
| 812 | 903 | ||
| 813 | typedef struct smb_com_copy_rsp { | 904 | typedef struct smb_com_copy_rsp { |
| 814 | struct smb_hdr hdr; /* wct = 1 */ | 905 | struct smb_hdr hdr; /* wct = 1 */ |
| @@ -816,7 +907,7 @@ typedef struct smb_com_copy_rsp { | |||
| 816 | __u16 ByteCount; /* may be zero */ | 907 | __u16 ByteCount; /* may be zero */ |
| 817 | __u8 BufferFormat; /* 0x04 - only present if errored file follows */ | 908 | __u8 BufferFormat; /* 0x04 - only present if errored file follows */ |
| 818 | unsigned char ErrorFileName[1]; /* only present if error in copy */ | 909 | unsigned char ErrorFileName[1]; /* only present if error in copy */ |
| 819 | } COPY_RSP; | 910 | } __attribute__((packed)) COPY_RSP; |
| 820 | 911 | ||
| 821 | #define CREATE_HARD_LINK 0x103 | 912 | #define CREATE_HARD_LINK 0x103 |
| 822 | #define MOVEFILE_COPY_ALLOWED 0x0002 | 913 | #define MOVEFILE_COPY_ALLOWED 0x0002 |
| @@ -832,12 +923,12 @@ typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */ | |||
| 832 | unsigned char OldFileName[1]; | 923 | unsigned char OldFileName[1]; |
| 833 | /* followed by __u8 BufferFormat2 */ | 924 | /* followed by __u8 BufferFormat2 */ |
| 834 | /* followed by NewFileName */ | 925 | /* followed by NewFileName */ |
| 835 | } NT_RENAME_REQ; | 926 | } __attribute__((packed)) NT_RENAME_REQ; |
| 836 | 927 | ||
| 837 | typedef struct smb_com_rename_rsp { | 928 | typedef struct smb_com_rename_rsp { |
| 838 | struct smb_hdr hdr; /* wct = 0 */ | 929 | struct smb_hdr hdr; /* wct = 0 */ |
| 839 | __u16 ByteCount; /* bct = 0 */ | 930 | __u16 ByteCount; /* bct = 0 */ |
| 840 | } RENAME_RSP; | 931 | } __attribute__((packed)) RENAME_RSP; |
| 841 | 932 | ||
| 842 | typedef struct smb_com_delete_file_req { | 933 | typedef struct smb_com_delete_file_req { |
| 843 | struct smb_hdr hdr; /* wct = 1 */ | 934 | struct smb_hdr hdr; /* wct = 1 */ |
| @@ -845,36 +936,52 @@ typedef struct smb_com_delete_file_req { | |||
| 845 | __le16 ByteCount; | 936 | __le16 ByteCount; |
| 846 | __u8 BufferFormat; /* 4 = ASCII */ | 937 | __u8 BufferFormat; /* 4 = ASCII */ |
| 847 | unsigned char fileName[1]; | 938 | unsigned char fileName[1]; |
| 848 | } DELETE_FILE_REQ; | 939 | } __attribute__((packed)) DELETE_FILE_REQ; |
| 849 | 940 | ||
| 850 | typedef struct smb_com_delete_file_rsp { | 941 | typedef struct smb_com_delete_file_rsp { |
| 851 | struct smb_hdr hdr; /* wct = 0 */ | 942 | struct smb_hdr hdr; /* wct = 0 */ |
| 852 | __u16 ByteCount; /* bct = 0 */ | 943 | __u16 ByteCount; /* bct = 0 */ |
| 853 | } DELETE_FILE_RSP; | 944 | } __attribute__((packed)) DELETE_FILE_RSP; |
| 854 | 945 | ||
| 855 | typedef struct smb_com_delete_directory_req { | 946 | typedef struct smb_com_delete_directory_req { |
| 856 | struct smb_hdr hdr; /* wct = 0 */ | 947 | struct smb_hdr hdr; /* wct = 0 */ |
| 857 | __le16 ByteCount; | 948 | __le16 ByteCount; |
| 858 | __u8 BufferFormat; /* 4 = ASCII */ | 949 | __u8 BufferFormat; /* 4 = ASCII */ |
| 859 | unsigned char DirName[1]; | 950 | unsigned char DirName[1]; |
| 860 | } DELETE_DIRECTORY_REQ; | 951 | } __attribute__((packed)) DELETE_DIRECTORY_REQ; |
| 861 | 952 | ||
| 862 | typedef struct smb_com_delete_directory_rsp { | 953 | typedef struct smb_com_delete_directory_rsp { |
| 863 | struct smb_hdr hdr; /* wct = 0 */ | 954 | struct smb_hdr hdr; /* wct = 0 */ |
| 864 | __u16 ByteCount; /* bct = 0 */ | 955 | __u16 ByteCount; /* bct = 0 */ |
| 865 | } DELETE_DIRECTORY_RSP; | 956 | } __attribute__((packed)) DELETE_DIRECTORY_RSP; |
| 866 | 957 | ||
| 867 | typedef struct smb_com_create_directory_req { | 958 | typedef struct smb_com_create_directory_req { |
| 868 | struct smb_hdr hdr; /* wct = 0 */ | 959 | struct smb_hdr hdr; /* wct = 0 */ |
| 869 | __le16 ByteCount; | 960 | __le16 ByteCount; |
| 870 | __u8 BufferFormat; /* 4 = ASCII */ | 961 | __u8 BufferFormat; /* 4 = ASCII */ |
| 871 | unsigned char DirName[1]; | 962 | unsigned char DirName[1]; |
| 872 | } CREATE_DIRECTORY_REQ; | 963 | } __attribute__((packed)) CREATE_DIRECTORY_REQ; |
| 873 | 964 | ||
| 874 | typedef struct smb_com_create_directory_rsp { | 965 | typedef struct smb_com_create_directory_rsp { |
| 875 | struct smb_hdr hdr; /* wct = 0 */ | 966 | struct smb_hdr hdr; /* wct = 0 */ |
| 876 | __u16 ByteCount; /* bct = 0 */ | 967 | __u16 ByteCount; /* bct = 0 */ |
| 877 | } CREATE_DIRECTORY_RSP; | 968 | } __attribute__((packed)) CREATE_DIRECTORY_RSP; |
| 969 | |||
| 970 | typedef struct smb_com_query_information_req { | ||
| 971 | struct smb_hdr hdr; /* wct = 0 */ | ||
| 972 | __le16 ByteCount; /* 1 + namelen + 1 */ | ||
| 973 | __u8 BufferFormat; /* 4 = ASCII */ | ||
| 974 | unsigned char FileName[1]; | ||
| 975 | } __attribute__((packed)) QUERY_INFORMATION_REQ; | ||
| 976 | |||
| 977 | typedef struct smb_com_query_information_rsp { | ||
| 978 | struct smb_hdr hdr; /* wct = 10 */ | ||
| 979 | __le16 attr; | ||
| 980 | __le32 last_write_time; | ||
| 981 | __le32 size; | ||
| 982 | __u16 reserved[5]; | ||
| 983 | __le16 ByteCount; /* bcc = 0 */ | ||
| 984 | } __attribute__((packed)) QUERY_INFORMATION_RSP; | ||
| 878 | 985 | ||
| 879 | typedef struct smb_com_setattr_req { | 986 | typedef struct smb_com_setattr_req { |
| 880 | struct smb_hdr hdr; /* wct = 8 */ | 987 | struct smb_hdr hdr; /* wct = 8 */ |
| @@ -885,12 +992,12 @@ typedef struct smb_com_setattr_req { | |||
| 885 | __u16 ByteCount; | 992 | __u16 ByteCount; |
| 886 | __u8 BufferFormat; /* 4 = ASCII */ | 993 | __u8 BufferFormat; /* 4 = ASCII */ |
| 887 | unsigned char fileName[1]; | 994 | unsigned char fileName[1]; |
| 888 | } SETATTR_REQ; | 995 | } __attribute__((packed)) SETATTR_REQ; |
| 889 | 996 | ||
| 890 | typedef struct smb_com_setattr_rsp { | 997 | typedef struct smb_com_setattr_rsp { |
| 891 | struct smb_hdr hdr; /* wct = 0 */ | 998 | struct smb_hdr hdr; /* wct = 0 */ |
| 892 | __u16 ByteCount; /* bct = 0 */ | 999 | __u16 ByteCount; /* bct = 0 */ |
| 893 | } SETATTR_RSP; | 1000 | } __attribute__((packed)) SETATTR_RSP; |
| 894 | 1001 | ||
| 895 | /* empty wct response to setattr */ | 1002 | /* empty wct response to setattr */ |
| 896 | 1003 | ||
| @@ -920,7 +1027,7 @@ typedef struct smb_com_transaction_ioctl_req { | |||
| 920 | __le16 ByteCount; | 1027 | __le16 ByteCount; |
| 921 | __u8 Pad[3]; | 1028 | __u8 Pad[3]; |
| 922 | __u8 Data[1]; | 1029 | __u8 Data[1]; |
| 923 | } TRANSACT_IOCTL_REQ; | 1030 | } __attribute__((packed)) TRANSACT_IOCTL_REQ; |
| 924 | 1031 | ||
| 925 | typedef struct smb_com_transaction_ioctl_rsp { | 1032 | typedef struct smb_com_transaction_ioctl_rsp { |
| 926 | struct smb_hdr hdr; /* wct = 19 */ | 1033 | struct smb_hdr hdr; /* wct = 19 */ |
| @@ -937,7 +1044,7 @@ typedef struct smb_com_transaction_ioctl_rsp { | |||
| 937 | __le16 ReturnedDataLen; | 1044 | __le16 ReturnedDataLen; |
| 938 | __u16 ByteCount; | 1045 | __u16 ByteCount; |
| 939 | __u8 Pad[3]; | 1046 | __u8 Pad[3]; |
| 940 | } TRANSACT_IOCTL_RSP; | 1047 | } __attribute__((packed)) TRANSACT_IOCTL_RSP; |
| 941 | 1048 | ||
| 942 | typedef struct smb_com_transaction_change_notify_req { | 1049 | typedef struct smb_com_transaction_change_notify_req { |
| 943 | struct smb_hdr hdr; /* wct = 23 */ | 1050 | struct smb_hdr hdr; /* wct = 23 */ |
| @@ -961,7 +1068,7 @@ typedef struct smb_com_transaction_change_notify_req { | |||
| 961 | __le16 ByteCount; | 1068 | __le16 ByteCount; |
| 962 | /* __u8 Pad[3];*/ | 1069 | /* __u8 Pad[3];*/ |
| 963 | /* __u8 Data[1];*/ | 1070 | /* __u8 Data[1];*/ |
| 964 | } TRANSACT_CHANGE_NOTIFY_REQ; | 1071 | } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ; |
| 965 | 1072 | ||
| 966 | typedef struct smb_com_transaction_change_notify_rsp { | 1073 | typedef struct smb_com_transaction_change_notify_rsp { |
| 967 | struct smb_hdr hdr; /* wct = 18 */ | 1074 | struct smb_hdr hdr; /* wct = 18 */ |
| @@ -977,7 +1084,7 @@ typedef struct smb_com_transaction_change_notify_rsp { | |||
| 977 | __u8 SetupCount; /* 0 */ | 1084 | __u8 SetupCount; /* 0 */ |
| 978 | __u16 ByteCount; | 1085 | __u16 ByteCount; |
| 979 | /* __u8 Pad[3]; */ | 1086 | /* __u8 Pad[3]; */ |
| 980 | } TRANSACT_CHANGE_NOTIFY_RSP; | 1087 | } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_RSP; |
| 981 | /* Completion Filter flags for Notify */ | 1088 | /* Completion Filter flags for Notify */ |
| 982 | #define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 | 1089 | #define FILE_NOTIFY_CHANGE_FILE_NAME 0x00000001 |
| 983 | #define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 | 1090 | #define FILE_NOTIFY_CHANGE_DIR_NAME 0x00000002 |
| @@ -1008,7 +1115,7 @@ struct file_notify_information { | |||
| 1008 | __le32 Action; | 1115 | __le32 Action; |
| 1009 | __le32 FileNameLength; | 1116 | __le32 FileNameLength; |
| 1010 | __u8 FileName[0]; | 1117 | __u8 FileName[0]; |
| 1011 | }; | 1118 | } __attribute__((packed)); |
| 1012 | 1119 | ||
| 1013 | struct reparse_data { | 1120 | struct reparse_data { |
| 1014 | __u32 ReparseTag; | 1121 | __u32 ReparseTag; |
| @@ -1019,7 +1126,7 @@ struct reparse_data { | |||
| 1019 | __u16 TargetNameOffset; | 1126 | __u16 TargetNameOffset; |
| 1020 | __u16 TargetNameLen; | 1127 | __u16 TargetNameLen; |
| 1021 | char LinkNamesBuf[1]; | 1128 | char LinkNamesBuf[1]; |
| 1022 | }; | 1129 | } __attribute__((packed)); |
| 1023 | 1130 | ||
| 1024 | struct cifs_quota_data { | 1131 | struct cifs_quota_data { |
| 1025 | __u32 rsrvd1; /* 0 */ | 1132 | __u32 rsrvd1; /* 0 */ |
| @@ -1029,7 +1136,7 @@ struct cifs_quota_data { | |||
| 1029 | __u64 soft_limit; | 1136 | __u64 soft_limit; |
| 1030 | __u64 hard_limit; | 1137 | __u64 hard_limit; |
| 1031 | char sid[1]; /* variable size? */ | 1138 | char sid[1]; /* variable size? */ |
| 1032 | }; | 1139 | } __attribute__((packed)); |
| 1033 | 1140 | ||
| 1034 | /* quota sub commands */ | 1141 | /* quota sub commands */ |
| 1035 | #define QUOTA_LIST_CONTINUE 0 | 1142 | #define QUOTA_LIST_CONTINUE 0 |
| @@ -1055,12 +1162,12 @@ struct trans2_req { | |||
| 1055 | __u8 Reserved3; | 1162 | __u8 Reserved3; |
| 1056 | __le16 SubCommand; /* 1st setup word - SetupCount words follow */ | 1163 | __le16 SubCommand; /* 1st setup word - SetupCount words follow */ |
| 1057 | __le16 ByteCount; | 1164 | __le16 ByteCount; |
| 1058 | }; | 1165 | } __attribute__((packed)); |
| 1059 | 1166 | ||
| 1060 | struct smb_t2_req { | 1167 | struct smb_t2_req { |
| 1061 | struct smb_hdr hdr; | 1168 | struct smb_hdr hdr; |
| 1062 | struct trans2_req t2_req; | 1169 | struct trans2_req t2_req; |
| 1063 | }; | 1170 | } __attribute__((packed)); |
| 1064 | 1171 | ||
| 1065 | struct trans2_resp { | 1172 | struct trans2_resp { |
| 1066 | /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */ | 1173 | /* struct smb_hdr hdr precedes. Note wct = 10 + setup count */ |
| @@ -1079,12 +1186,12 @@ struct trans2_resp { | |||
| 1079 | __u16 ByteCount; | 1186 | __u16 ByteCount; |
| 1080 | __u16 Reserved2;*/ | 1187 | __u16 Reserved2;*/ |
| 1081 | /* data area follows */ | 1188 | /* data area follows */ |
| 1082 | }; | 1189 | } __attribute__((packed)); |
| 1083 | 1190 | ||
| 1084 | struct smb_t2_rsp { | 1191 | struct smb_t2_rsp { |
| 1085 | struct smb_hdr hdr; | 1192 | struct smb_hdr hdr; |
| 1086 | struct trans2_resp t2_rsp; | 1193 | struct trans2_resp t2_rsp; |
| 1087 | }; | 1194 | } __attribute__((packed)); |
| 1088 | 1195 | ||
| 1089 | /* PathInfo/FileInfo infolevels */ | 1196 | /* PathInfo/FileInfo infolevels */ |
| 1090 | #define SMB_INFO_STANDARD 1 | 1197 | #define SMB_INFO_STANDARD 1 |
| @@ -1171,14 +1278,14 @@ typedef struct smb_com_transaction2_qpi_req { | |||
| 1171 | __le16 InformationLevel; | 1278 | __le16 InformationLevel; |
| 1172 | __u32 Reserved4; | 1279 | __u32 Reserved4; |
| 1173 | char FileName[1]; | 1280 | char FileName[1]; |
| 1174 | } TRANSACTION2_QPI_REQ; | 1281 | } __attribute__((packed)) TRANSACTION2_QPI_REQ; |
| 1175 | 1282 | ||
| 1176 | typedef struct smb_com_transaction2_qpi_rsp { | 1283 | typedef struct smb_com_transaction2_qpi_rsp { |
| 1177 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1284 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
| 1178 | struct trans2_resp t2; | 1285 | struct trans2_resp t2; |
| 1179 | __u16 ByteCount; | 1286 | __u16 ByteCount; |
| 1180 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ | 1287 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ |
| 1181 | } TRANSACTION2_QPI_RSP; | 1288 | } __attribute__((packed)) TRANSACTION2_QPI_RSP; |
| 1182 | 1289 | ||
| 1183 | typedef struct smb_com_transaction2_spi_req { | 1290 | typedef struct smb_com_transaction2_spi_req { |
| 1184 | struct smb_hdr hdr; /* wct = 15 */ | 1291 | struct smb_hdr hdr; /* wct = 15 */ |
| @@ -1204,21 +1311,21 @@ typedef struct smb_com_transaction2_spi_req { | |||
| 1204 | __le16 InformationLevel; | 1311 | __le16 InformationLevel; |
| 1205 | __u32 Reserved4; | 1312 | __u32 Reserved4; |
| 1206 | char FileName[1]; | 1313 | char FileName[1]; |
| 1207 | } TRANSACTION2_SPI_REQ; | 1314 | } __attribute__((packed)) TRANSACTION2_SPI_REQ; |
| 1208 | 1315 | ||
| 1209 | typedef struct smb_com_transaction2_spi_rsp { | 1316 | typedef struct smb_com_transaction2_spi_rsp { |
| 1210 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1317 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
| 1211 | struct trans2_resp t2; | 1318 | struct trans2_resp t2; |
| 1212 | __u16 ByteCount; | 1319 | __u16 ByteCount; |
| 1213 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ | 1320 | __u16 Reserved2; /* parameter word reserved - present for infolevels > 100 */ |
| 1214 | } TRANSACTION2_SPI_RSP; | 1321 | } __attribute__((packed)) TRANSACTION2_SPI_RSP; |
| 1215 | 1322 | ||
| 1216 | struct set_file_rename { | 1323 | struct set_file_rename { |
| 1217 | __le32 overwrite; /* 1 = overwrite dest */ | 1324 | __le32 overwrite; /* 1 = overwrite dest */ |
| 1218 | __u32 root_fid; /* zero */ | 1325 | __u32 root_fid; /* zero */ |
| 1219 | __le32 target_name_len; | 1326 | __le32 target_name_len; |
| 1220 | char target_name[0]; /* Must be unicode */ | 1327 | char target_name[0]; /* Must be unicode */ |
| 1221 | }; | 1328 | } __attribute__((packed)); |
| 1222 | 1329 | ||
| 1223 | struct smb_com_transaction2_sfi_req { | 1330 | struct smb_com_transaction2_sfi_req { |
| 1224 | struct smb_hdr hdr; /* wct = 15 */ | 1331 | struct smb_hdr hdr; /* wct = 15 */ |
| @@ -1244,7 +1351,7 @@ struct smb_com_transaction2_sfi_req { | |||
| 1244 | __u16 Fid; | 1351 | __u16 Fid; |
| 1245 | __le16 InformationLevel; | 1352 | __le16 InformationLevel; |
| 1246 | __u16 Reserved4; | 1353 | __u16 Reserved4; |
| 1247 | }; | 1354 | } __attribute__((packed)); |
| 1248 | 1355 | ||
| 1249 | struct smb_com_transaction2_sfi_rsp { | 1356 | struct smb_com_transaction2_sfi_rsp { |
| 1250 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1357 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
| @@ -1252,7 +1359,7 @@ struct smb_com_transaction2_sfi_rsp { | |||
| 1252 | __u16 ByteCount; | 1359 | __u16 ByteCount; |
| 1253 | __u16 Reserved2; /* parameter word reserved - | 1360 | __u16 Reserved2; /* parameter word reserved - |
| 1254 | present for infolevels > 100 */ | 1361 | present for infolevels > 100 */ |
| 1255 | }; | 1362 | } __attribute__((packed)); |
| 1256 | 1363 | ||
| 1257 | struct smb_t2_qfi_req { | 1364 | struct smb_t2_qfi_req { |
| 1258 | struct smb_hdr hdr; | 1365 | struct smb_hdr hdr; |
| @@ -1260,7 +1367,7 @@ struct smb_t2_qfi_req { | |||
| 1260 | __u8 Pad; | 1367 | __u8 Pad; |
| 1261 | __u16 Fid; | 1368 | __u16 Fid; |
| 1262 | __le16 InformationLevel; | 1369 | __le16 InformationLevel; |
| 1263 | }; | 1370 | } __attribute__((packed)); |
| 1264 | 1371 | ||
| 1265 | struct smb_t2_qfi_rsp { | 1372 | struct smb_t2_qfi_rsp { |
| 1266 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1373 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
| @@ -1268,7 +1375,7 @@ struct smb_t2_qfi_rsp { | |||
| 1268 | __u16 ByteCount; | 1375 | __u16 ByteCount; |
| 1269 | __u16 Reserved2; /* parameter word reserved - | 1376 | __u16 Reserved2; /* parameter word reserved - |
| 1270 | present for infolevels > 100 */ | 1377 | present for infolevels > 100 */ |
| 1271 | }; | 1378 | } __attribute__((packed)); |
| 1272 | 1379 | ||
| 1273 | /* | 1380 | /* |
| 1274 | * Flags on T2 FINDFIRST and FINDNEXT | 1381 | * Flags on T2 FINDFIRST and FINDNEXT |
| @@ -1310,13 +1417,13 @@ typedef struct smb_com_transaction2_ffirst_req { | |||
| 1310 | __le16 InformationLevel; | 1417 | __le16 InformationLevel; |
| 1311 | __le32 SearchStorageType; | 1418 | __le32 SearchStorageType; |
| 1312 | char FileName[1]; | 1419 | char FileName[1]; |
| 1313 | } TRANSACTION2_FFIRST_REQ; | 1420 | } __attribute__((packed)) TRANSACTION2_FFIRST_REQ; |
| 1314 | 1421 | ||
| 1315 | typedef struct smb_com_transaction2_ffirst_rsp { | 1422 | typedef struct smb_com_transaction2_ffirst_rsp { |
| 1316 | struct smb_hdr hdr; /* wct = 10 */ | 1423 | struct smb_hdr hdr; /* wct = 10 */ |
| 1317 | struct trans2_resp t2; | 1424 | struct trans2_resp t2; |
| 1318 | __u16 ByteCount; | 1425 | __u16 ByteCount; |
| 1319 | } TRANSACTION2_FFIRST_RSP; | 1426 | } __attribute__((packed)) TRANSACTION2_FFIRST_RSP; |
| 1320 | 1427 | ||
| 1321 | typedef struct smb_com_transaction2_ffirst_rsp_parms { | 1428 | typedef struct smb_com_transaction2_ffirst_rsp_parms { |
| 1322 | __u16 SearchHandle; | 1429 | __u16 SearchHandle; |
| @@ -1324,7 +1431,7 @@ typedef struct smb_com_transaction2_ffirst_rsp_parms { | |||
| 1324 | __le16 EndofSearch; | 1431 | __le16 EndofSearch; |
| 1325 | __le16 EAErrorOffset; | 1432 | __le16 EAErrorOffset; |
| 1326 | __le16 LastNameOffset; | 1433 | __le16 LastNameOffset; |
| 1327 | } T2_FFIRST_RSP_PARMS; | 1434 | } __attribute__((packed)) T2_FFIRST_RSP_PARMS; |
| 1328 | 1435 | ||
| 1329 | typedef struct smb_com_transaction2_fnext_req { | 1436 | typedef struct smb_com_transaction2_fnext_req { |
| 1330 | struct smb_hdr hdr; /* wct = 15 */ | 1437 | struct smb_hdr hdr; /* wct = 15 */ |
| @@ -1352,20 +1459,20 @@ typedef struct smb_com_transaction2_fnext_req { | |||
| 1352 | __u32 ResumeKey; | 1459 | __u32 ResumeKey; |
| 1353 | __le16 SearchFlags; | 1460 | __le16 SearchFlags; |
| 1354 | char ResumeFileName[1]; | 1461 | char ResumeFileName[1]; |
| 1355 | } TRANSACTION2_FNEXT_REQ; | 1462 | } __attribute__((packed)) TRANSACTION2_FNEXT_REQ; |
| 1356 | 1463 | ||
| 1357 | typedef struct smb_com_transaction2_fnext_rsp { | 1464 | typedef struct smb_com_transaction2_fnext_rsp { |
| 1358 | struct smb_hdr hdr; /* wct = 10 */ | 1465 | struct smb_hdr hdr; /* wct = 10 */ |
| 1359 | struct trans2_resp t2; | 1466 | struct trans2_resp t2; |
| 1360 | __u16 ByteCount; | 1467 | __u16 ByteCount; |
| 1361 | } TRANSACTION2_FNEXT_RSP; | 1468 | } __attribute__((packed)) TRANSACTION2_FNEXT_RSP; |
| 1362 | 1469 | ||
| 1363 | typedef struct smb_com_transaction2_fnext_rsp_parms { | 1470 | typedef struct smb_com_transaction2_fnext_rsp_parms { |
| 1364 | __le16 SearchCount; | 1471 | __le16 SearchCount; |
| 1365 | __le16 EndofSearch; | 1472 | __le16 EndofSearch; |
| 1366 | __le16 EAErrorOffset; | 1473 | __le16 EAErrorOffset; |
| 1367 | __le16 LastNameOffset; | 1474 | __le16 LastNameOffset; |
| 1368 | } T2_FNEXT_RSP_PARMS; | 1475 | } __attribute__((packed)) T2_FNEXT_RSP_PARMS; |
| 1369 | 1476 | ||
| 1370 | /* QFSInfo Levels */ | 1477 | /* QFSInfo Levels */ |
| 1371 | #define SMB_INFO_ALLOCATION 1 | 1478 | #define SMB_INFO_ALLOCATION 1 |
| @@ -1402,14 +1509,51 @@ typedef struct smb_com_transaction2_qfsi_req { | |||
| 1402 | __le16 ByteCount; | 1509 | __le16 ByteCount; |
| 1403 | __u8 Pad; | 1510 | __u8 Pad; |
| 1404 | __le16 InformationLevel; | 1511 | __le16 InformationLevel; |
| 1405 | } TRANSACTION2_QFSI_REQ; | 1512 | } __attribute__((packed)) TRANSACTION2_QFSI_REQ; |
| 1406 | 1513 | ||
| 1407 | typedef struct smb_com_transaction_qfsi_rsp { | 1514 | typedef struct smb_com_transaction_qfsi_rsp { |
| 1408 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ | 1515 | struct smb_hdr hdr; /* wct = 10 + SetupCount */ |
| 1409 | struct trans2_resp t2; | 1516 | struct trans2_resp t2; |
| 1410 | __u16 ByteCount; | 1517 | __u16 ByteCount; |
| 1411 | __u8 Pad; /* may be three bytes *//* followed by data area */ | 1518 | __u8 Pad; /* may be three bytes *//* followed by data area */ |
| 1412 | } TRANSACTION2_QFSI_RSP; | 1519 | } __attribute__((packed)) TRANSACTION2_QFSI_RSP; |
| 1520 | |||
| 1521 | |||
| 1522 | /* SETFSInfo Levels */ | ||
| 1523 | #define SMB_SET_CIFS_UNIX_INFO 0x200 | ||
| 1524 | typedef struct smb_com_transaction2_setfsi_req { | ||
| 1525 | struct smb_hdr hdr; /* wct = 15 */ | ||
| 1526 | __le16 TotalParameterCount; | ||
| 1527 | __le16 TotalDataCount; | ||
| 1528 | __le16 MaxParameterCount; | ||
| 1529 | __le16 MaxDataCount; | ||
| 1530 | __u8 MaxSetupCount; | ||
| 1531 | __u8 Reserved; | ||
| 1532 | __le16 Flags; | ||
| 1533 | __le32 Timeout; | ||
| 1534 | __u16 Reserved2; | ||
| 1535 | __le16 ParameterCount; /* 4 */ | ||
| 1536 | __le16 ParameterOffset; | ||
| 1537 | __le16 DataCount; /* 12 */ | ||
| 1538 | __le16 DataOffset; | ||
| 1539 | __u8 SetupCount; /* one */ | ||
| 1540 | __u8 Reserved3; | ||
| 1541 | __le16 SubCommand; /* TRANS2_SET_FS_INFORMATION */ | ||
| 1542 | __le16 ByteCount; | ||
| 1543 | __u8 Pad; | ||
| 1544 | __u16 FileNum; /* Parameters start. */ | ||
| 1545 | __le16 InformationLevel;/* Parameters end. */ | ||
| 1546 | __le16 ClientUnixMajor; /* Data start. */ | ||
| 1547 | __le16 ClientUnixMinor; | ||
| 1548 | __le64 ClientUnixCap; /* Data end */ | ||
| 1549 | } __attribute__((packed)) TRANSACTION2_SETFSI_REQ; | ||
| 1550 | |||
| 1551 | typedef struct smb_com_transaction2_setfsi_rsp { | ||
| 1552 | struct smb_hdr hdr; /* wct = 10 */ | ||
| 1553 | struct trans2_resp t2; | ||
| 1554 | __u16 ByteCount; | ||
| 1555 | } __attribute__((packed)) TRANSACTION2_SETFSI_RSP; | ||
| 1556 | |||
| 1413 | 1557 | ||
| 1414 | typedef struct smb_com_transaction2_get_dfs_refer_req { | 1558 | typedef struct smb_com_transaction2_get_dfs_refer_req { |
| 1415 | struct smb_hdr hdr; /* wct = 15 */ | 1559 | struct smb_hdr hdr; /* wct = 15 */ |
| @@ -1433,7 +1577,7 @@ typedef struct smb_com_transaction2_get_dfs_refer_req { | |||
| 1433 | __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ | 1577 | __u8 Pad[3]; /* Win2K has sent 0x0F01 (max resp length perhaps?) followed by one byte pad - doesn't seem to matter though */ |
| 1434 | __le16 MaxReferralLevel; | 1578 | __le16 MaxReferralLevel; |
| 1435 | char RequestFileName[1]; | 1579 | char RequestFileName[1]; |
| 1436 | } TRANSACTION2_GET_DFS_REFER_REQ; | 1580 | } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_REQ; |
| 1437 | 1581 | ||
| 1438 | typedef struct dfs_referral_level_3 { | 1582 | typedef struct dfs_referral_level_3 { |
| 1439 | __le16 VersionNumber; | 1583 | __le16 VersionNumber; |
| @@ -1445,7 +1589,7 @@ typedef struct dfs_referral_level_3 { | |||
| 1445 | __le16 DfsPathOffset; | 1589 | __le16 DfsPathOffset; |
| 1446 | __le16 DfsAlternatePathOffset; | 1590 | __le16 DfsAlternatePathOffset; |
| 1447 | __le16 NetworkAddressOffset; | 1591 | __le16 NetworkAddressOffset; |
| 1448 | } REFERRAL3; | 1592 | } __attribute__((packed)) REFERRAL3; |
| 1449 | 1593 | ||
| 1450 | typedef struct smb_com_transaction_get_dfs_refer_rsp { | 1594 | typedef struct smb_com_transaction_get_dfs_refer_rsp { |
| 1451 | struct smb_hdr hdr; /* wct = 10 */ | 1595 | struct smb_hdr hdr; /* wct = 10 */ |
| @@ -1458,7 +1602,7 @@ typedef struct smb_com_transaction_get_dfs_refer_rsp { | |||
| 1458 | __u16 Pad2; | 1602 | __u16 Pad2; |
| 1459 | REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ | 1603 | REFERRAL3 referrals[1]; /* array of level 3 dfs_referral structures */ |
| 1460 | /* followed by the strings pointed to by the referral structures */ | 1604 | /* followed by the strings pointed to by the referral structures */ |
| 1461 | } TRANSACTION2_GET_DFS_REFER_RSP; | 1605 | } __attribute__((packed)) TRANSACTION2_GET_DFS_REFER_RSP; |
| 1462 | 1606 | ||
| 1463 | /* DFS Flags */ | 1607 | /* DFS Flags */ |
| 1464 | #define DFSREF_REFERRAL_SERVER 0x0001 | 1608 | #define DFSREF_REFERRAL_SERVER 0x0001 |
| @@ -1512,7 +1656,7 @@ struct serverInfo { | |||
| 1512 | unsigned char versionMinor; | 1656 | unsigned char versionMinor; |
| 1513 | unsigned long type; | 1657 | unsigned long type; |
| 1514 | unsigned int commentOffset; | 1658 | unsigned int commentOffset; |
| 1515 | }; | 1659 | } __attribute__((packed)); |
| 1516 | 1660 | ||
| 1517 | /* | 1661 | /* |
| 1518 | * The following structure is the format of the data returned on a NetShareEnum | 1662 | * The following structure is the format of the data returned on a NetShareEnum |
| @@ -1524,39 +1668,55 @@ struct shareInfo { | |||
| 1524 | char pad; | 1668 | char pad; |
| 1525 | unsigned short type; | 1669 | unsigned short type; |
| 1526 | unsigned int commentOffset; | 1670 | unsigned int commentOffset; |
| 1527 | }; | 1671 | } __attribute__((packed)); |
| 1528 | 1672 | ||
| 1529 | struct aliasInfo { | 1673 | struct aliasInfo { |
| 1530 | char aliasName[9]; | 1674 | char aliasName[9]; |
| 1531 | char pad; | 1675 | char pad; |
| 1532 | unsigned int commentOffset; | 1676 | unsigned int commentOffset; |
| 1533 | unsigned char type[2]; | 1677 | unsigned char type[2]; |
| 1534 | }; | 1678 | } __attribute__((packed)); |
| 1535 | 1679 | ||
| 1536 | struct aliasInfo92 { | 1680 | struct aliasInfo92 { |
| 1537 | int aliasNameOffset; | 1681 | int aliasNameOffset; |
| 1538 | int serverNameOffset; | 1682 | int serverNameOffset; |
| 1539 | int shareNameOffset; | 1683 | int shareNameOffset; |
| 1540 | }; | 1684 | } __attribute__((packed)); |
| 1541 | 1685 | ||
| 1542 | typedef struct { | 1686 | typedef struct { |
| 1543 | __le64 TotalAllocationUnits; | 1687 | __le64 TotalAllocationUnits; |
| 1544 | __le64 FreeAllocationUnits; | 1688 | __le64 FreeAllocationUnits; |
| 1545 | __le32 SectorsPerAllocationUnit; | 1689 | __le32 SectorsPerAllocationUnit; |
| 1546 | __le32 BytesPerSector; | 1690 | __le32 BytesPerSector; |
| 1547 | } FILE_SYSTEM_INFO; /* size info, level 0x103 */ | 1691 | } __attribute__((packed)) FILE_SYSTEM_INFO; /* size info, level 0x103 */ |
| 1692 | |||
| 1693 | typedef struct { | ||
| 1694 | __le32 fsid; | ||
| 1695 | __le32 SectorsPerAllocationUnit; | ||
| 1696 | __le32 TotalAllocationUnits; | ||
| 1697 | __le32 FreeAllocationUnits; | ||
| 1698 | __le16 BytesPerSector; | ||
| 1699 | } __attribute__((packed)) FILE_SYSTEM_ALLOC_INFO; | ||
| 1548 | 1700 | ||
| 1549 | typedef struct { | 1701 | typedef struct { |
| 1550 | __le16 MajorVersionNumber; | 1702 | __le16 MajorVersionNumber; |
| 1551 | __le16 MinorVersionNumber; | 1703 | __le16 MinorVersionNumber; |
| 1552 | __le64 Capability; | 1704 | __le64 Capability; |
| 1553 | } FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ | 1705 | } __attribute__((packed)) FILE_SYSTEM_UNIX_INFO; /* Unix extensions info, level 0x200 */ |
| 1706 | |||
| 1707 | /* Version numbers for CIFS UNIX major and minor. */ | ||
| 1708 | #define CIFS_UNIX_MAJOR_VERSION 1 | ||
| 1709 | #define CIFS_UNIX_MINOR_VERSION 0 | ||
| 1710 | |||
| 1554 | /* Linux/Unix extensions capability flags */ | 1711 | /* Linux/Unix extensions capability flags */ |
| 1555 | #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ | 1712 | #define CIFS_UNIX_FCNTL_CAP 0x00000001 /* support for fcntl locks */ |
| 1556 | #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ | 1713 | #define CIFS_UNIX_POSIX_ACL_CAP 0x00000002 /* support getfacl/setfacl */ |
| 1557 | #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ | 1714 | #define CIFS_UNIX_XATTR_CAP 0x00000004 /* support new namespace */ |
| 1558 | #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ | 1715 | #define CIFS_UNIX_EXTATTR_CAP 0x00000008 /* support chattr/chflag */ |
| 1716 | #define CIFS_UNIX_POSIX_PATHNAMES_CAP 0x00000010 /* Use POSIX pathnames on the wire. */ | ||
| 1717 | |||
| 1559 | #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ | 1718 | #define CIFS_POSIX_EXTENSIONS 0x00000010 /* support for new QFSInfo */ |
| 1719 | |||
| 1560 | typedef struct { | 1720 | typedef struct { |
| 1561 | /* For undefined recommended transfer size return -1 in that field */ | 1721 | /* For undefined recommended transfer size return -1 in that field */ |
| 1562 | __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ | 1722 | __le32 OptimalTransferSize; /* bsize on some os, iosize on other os */ |
| @@ -1577,7 +1737,7 @@ typedef struct { | |||
| 1577 | __le64 FileSysIdentifier; /* fsid */ | 1737 | __le64 FileSysIdentifier; /* fsid */ |
| 1578 | /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ | 1738 | /* NB Namelen comes from FILE_SYSTEM_ATTRIBUTE_INFO call */ |
| 1579 | /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ | 1739 | /* NB flags can come from FILE_SYSTEM_DEVICE_INFO call */ |
| 1580 | } FILE_SYSTEM_POSIX_INFO; | 1740 | } __attribute__((packed)) FILE_SYSTEM_POSIX_INFO; |
| 1581 | 1741 | ||
| 1582 | /* DeviceType Flags */ | 1742 | /* DeviceType Flags */ |
| 1583 | #define FILE_DEVICE_CD_ROM 0x00000002 | 1743 | #define FILE_DEVICE_CD_ROM 0x00000002 |
| @@ -1602,14 +1762,14 @@ typedef struct { | |||
| 1602 | typedef struct { | 1762 | typedef struct { |
| 1603 | __le32 DeviceType; | 1763 | __le32 DeviceType; |
| 1604 | __le32 DeviceCharacteristics; | 1764 | __le32 DeviceCharacteristics; |
| 1605 | } FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ | 1765 | } __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ |
| 1606 | 1766 | ||
| 1607 | typedef struct { | 1767 | typedef struct { |
| 1608 | __le32 Attributes; | 1768 | __le32 Attributes; |
| 1609 | __le32 MaxPathNameComponentLength; | 1769 | __le32 MaxPathNameComponentLength; |
| 1610 | __le32 FileSystemNameLen; | 1770 | __le32 FileSystemNameLen; |
| 1611 | char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ | 1771 | char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ |
| 1612 | } FILE_SYSTEM_ATTRIBUTE_INFO; | 1772 | } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; |
| 1613 | 1773 | ||
| 1614 | /******************************************************************************/ | 1774 | /******************************************************************************/ |
| 1615 | /* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */ | 1775 | /* QueryFileInfo/QueryPathinfo (also for SetPath/SetFile) data buffer formats */ |
| @@ -1636,7 +1796,7 @@ typedef struct { /* data block encoding of response to level 263 QPathInfo */ | |||
| 1636 | __le32 AlignmentRequirement; | 1796 | __le32 AlignmentRequirement; |
| 1637 | __le32 FileNameLength; | 1797 | __le32 FileNameLength; |
| 1638 | char FileName[1]; | 1798 | char FileName[1]; |
| 1639 | } FILE_ALL_INFO; /* level 0x107 QPathInfo */ | 1799 | } __attribute__((packed)) FILE_ALL_INFO; /* level 0x107 QPathInfo */ |
| 1640 | 1800 | ||
| 1641 | /* defines for enumerating possible values of the Unix type field below */ | 1801 | /* defines for enumerating possible values of the Unix type field below */ |
| 1642 | #define UNIX_FILE 0 | 1802 | #define UNIX_FILE 0 |
| @@ -1660,11 +1820,11 @@ typedef struct { | |||
| 1660 | __u64 UniqueId; | 1820 | __u64 UniqueId; |
| 1661 | __le64 Permissions; | 1821 | __le64 Permissions; |
| 1662 | __le64 Nlinks; | 1822 | __le64 Nlinks; |
| 1663 | } FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ | 1823 | } __attribute__((packed)) FILE_UNIX_BASIC_INFO; /* level 0x200 QPathInfo */ |
| 1664 | 1824 | ||
| 1665 | typedef struct { | 1825 | typedef struct { |
| 1666 | char LinkDest[1]; | 1826 | char LinkDest[1]; |
| 1667 | } FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ | 1827 | } __attribute__((packed)) FILE_UNIX_LINK_INFO; /* level 0x201 QPathInfo */ |
| 1668 | 1828 | ||
| 1669 | /* The following three structures are needed only for | 1829 | /* The following three structures are needed only for |
| 1670 | setting time to NT4 and some older servers via | 1830 | setting time to NT4 and some older servers via |
| @@ -1673,13 +1833,13 @@ typedef struct { | |||
| 1673 | __u16 Day:5; | 1833 | __u16 Day:5; |
| 1674 | __u16 Month:4; | 1834 | __u16 Month:4; |
| 1675 | __u16 Year:7; | 1835 | __u16 Year:7; |
| 1676 | } SMB_DATE; | 1836 | } __attribute__((packed)) SMB_DATE; |
| 1677 | 1837 | ||
| 1678 | typedef struct { | 1838 | typedef struct { |
| 1679 | __u16 TwoSeconds:5; | 1839 | __u16 TwoSeconds:5; |
| 1680 | __u16 Minutes:6; | 1840 | __u16 Minutes:6; |
| 1681 | __u16 Hours:5; | 1841 | __u16 Hours:5; |
| 1682 | } SMB_TIME; | 1842 | } __attribute__((packed)) SMB_TIME; |
| 1683 | 1843 | ||
| 1684 | typedef struct { | 1844 | typedef struct { |
| 1685 | __le16 CreationDate; /* SMB Date see above */ | 1845 | __le16 CreationDate; /* SMB Date see above */ |
| @@ -1692,7 +1852,7 @@ typedef struct { | |||
| 1692 | __le32 AllocationSize; | 1852 | __le32 AllocationSize; |
| 1693 | __le16 Attributes; /* verify not u32 */ | 1853 | __le16 Attributes; /* verify not u32 */ |
| 1694 | __le32 EASize; | 1854 | __le32 EASize; |
| 1695 | } FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ | 1855 | } __attribute__((packed)) FILE_INFO_STANDARD; /* level 1 SetPath/FileInfo */ |
| 1696 | 1856 | ||
| 1697 | typedef struct { | 1857 | typedef struct { |
| 1698 | __le64 CreationTime; | 1858 | __le64 CreationTime; |
| @@ -1701,19 +1861,19 @@ typedef struct { | |||
| 1701 | __le64 ChangeTime; | 1861 | __le64 ChangeTime; |
| 1702 | __le32 Attributes; | 1862 | __le32 Attributes; |
| 1703 | __u32 Pad; | 1863 | __u32 Pad; |
| 1704 | } FILE_BASIC_INFO; /* size info, level 0x101 */ | 1864 | } __attribute__((packed)) FILE_BASIC_INFO; /* size info, level 0x101 */ |
| 1705 | 1865 | ||
| 1706 | struct file_allocation_info { | 1866 | struct file_allocation_info { |
| 1707 | __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ | 1867 | __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ |
| 1708 | }; /* size used on disk, level 0x103 for set, 0x105 for query */ | 1868 | } __attribute__((packed)); /* size used on disk, level 0x103 for set, 0x105 for query */ |
| 1709 | 1869 | ||
| 1710 | struct file_end_of_file_info { | 1870 | struct file_end_of_file_info { |
| 1711 | __le64 FileSize; /* offset to end of file */ | 1871 | __le64 FileSize; /* offset to end of file */ |
| 1712 | }; /* size info, level 0x104 for set, 0x106 for query */ | 1872 | } __attribute__((packed)); /* size info, level 0x104 for set, 0x106 for query */ |
| 1713 | 1873 | ||
| 1714 | struct file_alt_name_info { | 1874 | struct file_alt_name_info { |
| 1715 | __u8 alt_name[1]; | 1875 | __u8 alt_name[1]; |
| 1716 | }; /* level 0x0108 */ | 1876 | } __attribute__((packed)); /* level 0x0108 */ |
| 1717 | 1877 | ||
| 1718 | struct file_stream_info { | 1878 | struct file_stream_info { |
| 1719 | __le32 number_of_streams; /* BB check sizes and verify location */ | 1879 | __le32 number_of_streams; /* BB check sizes and verify location */ |
| @@ -1730,7 +1890,7 @@ struct file_compression_info { | |||
| 1730 | __u8 ch_shift; | 1890 | __u8 ch_shift; |
| 1731 | __u8 cl_shift; | 1891 | __u8 cl_shift; |
| 1732 | __u8 pad[3]; | 1892 | __u8 pad[3]; |
| 1733 | }; /* level 0x10b */ | 1893 | } __attribute__((packed)); /* level 0x10b */ |
| 1734 | 1894 | ||
| 1735 | /* POSIX ACL set/query path info structures */ | 1895 | /* POSIX ACL set/query path info structures */ |
| 1736 | #define CIFS_ACL_VERSION 1 | 1896 | #define CIFS_ACL_VERSION 1 |
| @@ -1738,7 +1898,7 @@ struct cifs_posix_ace { /* access control entry (ACE) */ | |||
| 1738 | __u8 cifs_e_tag; | 1898 | __u8 cifs_e_tag; |
| 1739 | __u8 cifs_e_perm; | 1899 | __u8 cifs_e_perm; |
| 1740 | __le64 cifs_uid; /* or gid */ | 1900 | __le64 cifs_uid; /* or gid */ |
| 1741 | }; | 1901 | } __attribute__((packed)); |
| 1742 | 1902 | ||
| 1743 | struct cifs_posix_acl { /* access conrol list (ACL) */ | 1903 | struct cifs_posix_acl { /* access conrol list (ACL) */ |
| 1744 | __le16 version; | 1904 | __le16 version; |
| @@ -1747,7 +1907,7 @@ struct cifs_posix_acl { /* access conrol list (ACL) */ | |||
| 1747 | struct cifs_posix_ace ace_array[0]; | 1907 | struct cifs_posix_ace ace_array[0]; |
| 1748 | /* followed by | 1908 | /* followed by |
| 1749 | struct cifs_posix_ace default_ace_arraay[] */ | 1909 | struct cifs_posix_ace default_ace_arraay[] */ |
| 1750 | }; /* level 0x204 */ | 1910 | } __attribute__((packed)); /* level 0x204 */ |
| 1751 | 1911 | ||
| 1752 | /* types of access control entries already defined in posix_acl.h */ | 1912 | /* types of access control entries already defined in posix_acl.h */ |
| 1753 | /* #define CIFS_POSIX_ACL_USER_OBJ 0x01 | 1913 | /* #define CIFS_POSIX_ACL_USER_OBJ 0x01 |
| @@ -1766,15 +1926,15 @@ struct cifs_posix_acl { /* access conrol list (ACL) */ | |||
| 1766 | 1926 | ||
| 1767 | struct file_internal_info { | 1927 | struct file_internal_info { |
| 1768 | __u64 UniqueId; /* inode number */ | 1928 | __u64 UniqueId; /* inode number */ |
| 1769 | }; /* level 0x3ee */ | 1929 | } __attribute__((packed)); /* level 0x3ee */ |
| 1770 | struct file_mode_info { | 1930 | struct file_mode_info { |
| 1771 | __le32 Mode; | 1931 | __le32 Mode; |
| 1772 | }; /* level 0x3f8 */ | 1932 | } __attribute__((packed)); /* level 0x3f8 */ |
| 1773 | 1933 | ||
| 1774 | struct file_attrib_tag { | 1934 | struct file_attrib_tag { |
| 1775 | __le32 Attribute; | 1935 | __le32 Attribute; |
| 1776 | __le32 ReparseTag; | 1936 | __le32 ReparseTag; |
| 1777 | }; /* level 0x40b */ | 1937 | } __attribute__((packed)); /* level 0x40b */ |
| 1778 | 1938 | ||
| 1779 | 1939 | ||
| 1780 | /********************************************************/ | 1940 | /********************************************************/ |
| @@ -1798,7 +1958,7 @@ typedef struct { | |||
| 1798 | __le64 Permissions; | 1958 | __le64 Permissions; |
| 1799 | __le64 Nlinks; | 1959 | __le64 Nlinks; |
| 1800 | char FileName[1]; | 1960 | char FileName[1]; |
| 1801 | } FILE_UNIX_INFO; /* level 0x202 */ | 1961 | } __attribute__((packed)) FILE_UNIX_INFO; /* level 0x202 */ |
| 1802 | 1962 | ||
| 1803 | typedef struct { | 1963 | typedef struct { |
| 1804 | __le32 NextEntryOffset; | 1964 | __le32 NextEntryOffset; |
| @@ -1812,7 +1972,7 @@ typedef struct { | |||
| 1812 | __le32 ExtFileAttributes; | 1972 | __le32 ExtFileAttributes; |
| 1813 | __le32 FileNameLength; | 1973 | __le32 FileNameLength; |
| 1814 | char FileName[1]; | 1974 | char FileName[1]; |
| 1815 | } FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ | 1975 | } __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ |
| 1816 | 1976 | ||
| 1817 | typedef struct { | 1977 | typedef struct { |
| 1818 | __le32 NextEntryOffset; | 1978 | __le32 NextEntryOffset; |
| @@ -1827,7 +1987,7 @@ typedef struct { | |||
| 1827 | __le32 FileNameLength; | 1987 | __le32 FileNameLength; |
| 1828 | __le32 EaSize; /* length of the xattrs */ | 1988 | __le32 EaSize; /* length of the xattrs */ |
| 1829 | char FileName[1]; | 1989 | char FileName[1]; |
| 1830 | } FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ | 1990 | } __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ |
| 1831 | 1991 | ||
| 1832 | typedef struct { | 1992 | typedef struct { |
| 1833 | __le32 NextEntryOffset; | 1993 | __le32 NextEntryOffset; |
| @@ -1844,7 +2004,7 @@ typedef struct { | |||
| 1844 | __le32 Reserved; | 2004 | __le32 Reserved; |
| 1845 | __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ | 2005 | __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ |
| 1846 | char FileName[1]; | 2006 | char FileName[1]; |
| 1847 | } SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ | 2007 | } __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ |
| 1848 | 2008 | ||
| 1849 | typedef struct { | 2009 | typedef struct { |
| 1850 | __le32 NextEntryOffset; | 2010 | __le32 NextEntryOffset; |
| @@ -1862,18 +2022,18 @@ typedef struct { | |||
| 1862 | __u8 Reserved; | 2022 | __u8 Reserved; |
| 1863 | __u8 ShortName[12]; | 2023 | __u8 ShortName[12]; |
| 1864 | char FileName[1]; | 2024 | char FileName[1]; |
| 1865 | } FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ | 2025 | } __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ |
| 1866 | 2026 | ||
| 1867 | 2027 | ||
| 1868 | struct gea { | 2028 | struct gea { |
| 1869 | unsigned char name_len; | 2029 | unsigned char name_len; |
| 1870 | char name[1]; | 2030 | char name[1]; |
| 1871 | }; | 2031 | } __attribute__((packed)); |
| 1872 | 2032 | ||
| 1873 | struct gealist { | 2033 | struct gealist { |
| 1874 | unsigned long list_len; | 2034 | unsigned long list_len; |
| 1875 | struct gea list[1]; | 2035 | struct gea list[1]; |
| 1876 | }; | 2036 | } __attribute__((packed)); |
| 1877 | 2037 | ||
| 1878 | struct fea { | 2038 | struct fea { |
| 1879 | unsigned char EA_flags; | 2039 | unsigned char EA_flags; |
| @@ -1881,21 +2041,21 @@ struct fea { | |||
| 1881 | __le16 value_len; | 2041 | __le16 value_len; |
| 1882 | char name[1]; | 2042 | char name[1]; |
| 1883 | /* optionally followed by value */ | 2043 | /* optionally followed by value */ |
| 1884 | }; | 2044 | } __attribute__((packed)); |
| 1885 | /* flags for _FEA.fEA */ | 2045 | /* flags for _FEA.fEA */ |
| 1886 | #define FEA_NEEDEA 0x80 /* need EA bit */ | 2046 | #define FEA_NEEDEA 0x80 /* need EA bit */ |
| 1887 | 2047 | ||
| 1888 | struct fealist { | 2048 | struct fealist { |
| 1889 | __le32 list_len; | 2049 | __le32 list_len; |
| 1890 | struct fea list[1]; | 2050 | struct fea list[1]; |
| 1891 | }; | 2051 | } __attribute__((packed)); |
| 1892 | 2052 | ||
| 1893 | /* used to hold an arbitrary blob of data */ | 2053 | /* used to hold an arbitrary blob of data */ |
| 1894 | struct data_blob { | 2054 | struct data_blob { |
| 1895 | __u8 *data; | 2055 | __u8 *data; |
| 1896 | size_t length; | 2056 | size_t length; |
| 1897 | void (*free) (struct data_blob * data_blob); | 2057 | void (*free) (struct data_blob * data_blob); |
| 1898 | }; | 2058 | } __attribute__((packed)); |
| 1899 | 2059 | ||
| 1900 | 2060 | ||
| 1901 | #ifdef CONFIG_CIFS_POSIX | 2061 | #ifdef CONFIG_CIFS_POSIX |
| @@ -1907,18 +2067,17 @@ struct data_blob { | |||
| 1907 | perhaps add a CreateDevice - to create Pipes and other special .inodes | 2067 | perhaps add a CreateDevice - to create Pipes and other special .inodes |
| 1908 | Also note POSIX open flags | 2068 | Also note POSIX open flags |
| 1909 | 2) Close - to return the last write time to do cache across close more safely | 2069 | 2) Close - to return the last write time to do cache across close more safely |
| 1910 | 3) PosixQFSInfo - to return statfs info | 2070 | 3) FindFirst return unique inode number - what about resume key, two |
| 1911 | 4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes) | 2071 | forms short (matches readdir) and full (enough info to cache inodes) |
| 1912 | 5) Mkdir - set mode | 2072 | 4) Mkdir - set mode |
| 1913 | 2073 | ||
| 1914 | And under consideration: | 2074 | And under consideration: |
| 1915 | 6) FindClose2 (return nanosecond timestamp ??) | 2075 | 5) FindClose2 (return nanosecond timestamp ??) |
| 1916 | 7) Use nanosecond timestamps throughout all time fields if | 2076 | 6) Use nanosecond timestamps throughout all time fields if |
| 1917 | corresponding attribute flag is set | 2077 | corresponding attribute flag is set |
| 1918 | 8) sendfile - handle based copy | 2078 | 7) sendfile - handle based copy |
| 1919 | 9) Direct i/o | 2079 | 8) Direct i/o |
| 1920 | 10) "POSIX ACL" support | 2080 | 9) Misc fcntls? |
| 1921 | 11) Misc fcntls? | ||
| 1922 | 2081 | ||
| 1923 | what about fixing 64 bit alignment | 2082 | what about fixing 64 bit alignment |
| 1924 | 2083 | ||
| @@ -1974,7 +2133,7 @@ struct data_blob { | |||
| 1974 | 2133 | ||
| 1975 | */ | 2134 | */ |
| 1976 | 2135 | ||
| 1977 | /* xsymlink is a symlink format that can be used | 2136 | /* xsymlink is a symlink format (used by MacOS) that can be used |
| 1978 | to save symlink info in a regular file when | 2137 | to save symlink info in a regular file when |
| 1979 | mounted to operating systems that do not | 2138 | mounted to operating systems that do not |
| 1980 | support the cifs Unix extensions or EAs (for xattr | 2139 | support the cifs Unix extensions or EAs (for xattr |
| @@ -1999,7 +2158,7 @@ struct xsymlink { | |||
| 1999 | char cr2; /* \n */ | 2158 | char cr2; /* \n */ |
| 2000 | /* if room left, then end with \n then 0x20s by convention but not required */ | 2159 | /* if room left, then end with \n then 0x20s by convention but not required */ |
| 2001 | char path[1024]; | 2160 | char path[1024]; |
| 2002 | }; | 2161 | } __attribute__((packed)); |
| 2003 | 2162 | ||
| 2004 | typedef struct file_xattr_info { | 2163 | typedef struct file_xattr_info { |
| 2005 | /* BB do we need another field for flags? BB */ | 2164 | /* BB do we need another field for flags? BB */ |
| @@ -2007,7 +2166,7 @@ typedef struct file_xattr_info { | |||
| 2007 | __u32 xattr_value_len; | 2166 | __u32 xattr_value_len; |
| 2008 | char xattr_name[0]; | 2167 | char xattr_name[0]; |
| 2009 | /* followed by xattr_value[xattr_value_len], no pad */ | 2168 | /* followed by xattr_value[xattr_value_len], no pad */ |
| 2010 | } FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ | 2169 | } __attribute__((packed)) FILE_XATTR_INFO; /* extended attribute, info level 0x205 */ |
| 2011 | 2170 | ||
| 2012 | 2171 | ||
| 2013 | /* flags for chattr command */ | 2172 | /* flags for chattr command */ |
| @@ -2033,10 +2192,8 @@ typedef struct file_xattr_info { | |||
| 2033 | typedef struct file_chattr_info { | 2192 | typedef struct file_chattr_info { |
| 2034 | __le64 mask; /* list of all possible attribute bits */ | 2193 | __le64 mask; /* list of all possible attribute bits */ |
| 2035 | __le64 mode; /* list of actual attribute bits on this inode */ | 2194 | __le64 mode; /* list of actual attribute bits on this inode */ |
| 2036 | } FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */ | 2195 | } __attribute__((packed)) FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x206 */ |
| 2037 | 2196 | ||
| 2038 | #endif | 2197 | #endif |
| 2039 | 2198 | ||
| 2040 | #pragma pack() /* resume default structure packing */ | ||
| 2041 | |||
| 2042 | #endif /* _CIFSPDU_H */ | 2199 | #endif /* _CIFSPDU_H */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ea239dea571e..d301149b1bb0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
| @@ -47,19 +47,24 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, | |||
| 47 | struct smb_hdr * /* input */ , | 47 | struct smb_hdr * /* input */ , |
| 48 | struct smb_hdr * /* out */ , | 48 | struct smb_hdr * /* out */ , |
| 49 | int * /* bytes returned */ , const int long_op); | 49 | int * /* bytes returned */ , const int long_op); |
| 50 | extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, | ||
| 51 | struct kvec *, int /* nvec */, | ||
| 52 | int * /* bytes returned */ , const int long_op); | ||
| 50 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); | 53 | extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); |
| 51 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); | 54 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); |
| 52 | extern int is_valid_oplock_break(struct smb_hdr *smb); | 55 | extern int is_valid_oplock_break(struct smb_hdr *smb); |
| 53 | extern int is_size_safe_to_change(struct cifsInodeInfo *); | 56 | extern int is_size_safe_to_change(struct cifsInodeInfo *); |
| 57 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); | ||
| 54 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); | 58 | extern unsigned int smbCalcSize(struct smb_hdr *ptr); |
| 59 | extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); | ||
| 55 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 60 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
| 56 | enum securityEnum *secType); | 61 | enum securityEnum *secType); |
| 57 | extern int cifs_inet_pton(int, char * source, void *dst); | 62 | extern int cifs_inet_pton(int, char * source, void *dst); |
| 58 | extern int map_smb_to_linux_error(struct smb_hdr *smb); | 63 | extern int map_smb_to_linux_error(struct smb_hdr *smb); |
| 59 | extern void header_assemble(struct smb_hdr *, char /* command */ , | 64 | extern void header_assemble(struct smb_hdr *, char /* command */ , |
| 60 | const struct cifsTconInfo *, int /* specifies length | 65 | const struct cifsTconInfo *, int /* length of |
| 61 | of fixed section (word count) in two byte units */ | 66 | fixed section (word count) in two byte units */); |
| 62 | ); | 67 | extern __u16 GetNextMid(struct TCP_Server_Info *server); |
| 63 | extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, | 68 | extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, |
| 64 | struct cifsTconInfo *); | 69 | struct cifsTconInfo *); |
| 65 | extern void DeleteOplockQEntry(struct oplock_q_entry *); | 70 | extern void DeleteOplockQEntry(struct oplock_q_entry *); |
| @@ -89,7 +94,7 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 89 | 94 | ||
| 90 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | 95 | extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, |
| 91 | const char *searchName, const struct nls_table *nls_codepage, | 96 | const char *searchName, const struct nls_table *nls_codepage, |
| 92 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map); | 97 | __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep); |
| 93 | 98 | ||
| 94 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | 99 | extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, |
| 95 | __u16 searchHandle, struct cifs_search_info * psrch_inf); | 100 | __u16 searchHandle, struct cifs_search_info * psrch_inf); |
| @@ -101,6 +106,10 @@ extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | |||
| 101 | const unsigned char *searchName, | 106 | const unsigned char *searchName, |
| 102 | FILE_ALL_INFO * findData, | 107 | FILE_ALL_INFO * findData, |
| 103 | const struct nls_table *nls_codepage, int remap); | 108 | const struct nls_table *nls_codepage, int remap); |
| 109 | extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | ||
| 110 | const unsigned char *searchName, | ||
| 111 | FILE_ALL_INFO * findData, | ||
| 112 | const struct nls_table *nls_codepage, int remap); | ||
| 104 | 113 | ||
| 105 | extern int CIFSSMBUnixQPathInfo(const int xid, | 114 | extern int CIFSSMBUnixQPathInfo(const int xid, |
| 106 | struct cifsTconInfo *tcon, | 115 | struct cifsTconInfo *tcon, |
| @@ -125,6 +134,11 @@ extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, | |||
| 125 | int remap); | 134 | int remap); |
| 126 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, | 135 | extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, |
| 127 | struct kstatfs *FSData); | 136 | struct kstatfs *FSData); |
| 137 | extern int SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, | ||
| 138 | struct kstatfs *FSData); | ||
| 139 | extern int CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, | ||
| 140 | __u64 cap); | ||
| 141 | |||
| 128 | extern int CIFSSMBQFSAttributeInfo(const int xid, | 142 | extern int CIFSSMBQFSAttributeInfo(const int xid, |
| 129 | struct cifsTconInfo *tcon); | 143 | struct cifsTconInfo *tcon); |
| 130 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); | 144 | extern int CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon); |
| @@ -207,6 +221,11 @@ extern int CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | |||
| 207 | const int access_flags, const int omode, | 221 | const int access_flags, const int omode, |
| 208 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, | 222 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, |
| 209 | const struct nls_table *nls_codepage, int remap); | 223 | const struct nls_table *nls_codepage, int remap); |
| 224 | extern int SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | ||
| 225 | const char *fileName, const int disposition, | ||
| 226 | const int access_flags, const int omode, | ||
| 227 | __u16 * netfid, int *pOplock, FILE_ALL_INFO *, | ||
| 228 | const struct nls_table *nls_codepage, int remap); | ||
| 210 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, | 229 | extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, |
| 211 | const int smb_file_id); | 230 | const int smb_file_id); |
| 212 | 231 | ||
| @@ -222,7 +241,7 @@ extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
| 222 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 241 | extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, |
| 223 | const int netfid, const unsigned int count, | 242 | const int netfid, const unsigned int count, |
| 224 | const __u64 offset, unsigned int *nbytes, | 243 | const __u64 offset, unsigned int *nbytes, |
| 225 | const char __user *buf,const int long_op); | 244 | struct kvec *iov, const int nvec, const int long_op); |
| 226 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, | 245 | extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, |
| 227 | const unsigned char *searchName, __u64 * inode_number, | 246 | const unsigned char *searchName, __u64 * inode_number, |
| 228 | const struct nls_table *nls_codepage, | 247 | const struct nls_table *nls_codepage, |
| @@ -264,7 +283,8 @@ extern int CIFSSMBCopy(int xid, | |||
| 264 | int remap_special_chars); | 283 | int remap_special_chars); |
| 265 | extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | 284 | extern int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, |
| 266 | const int notify_subdirs,const __u16 netfid, | 285 | const int notify_subdirs,const __u16 netfid, |
| 267 | __u32 filter, const struct nls_table *nls_codepage); | 286 | __u32 filter, struct file * file, int multishot, |
| 287 | const struct nls_table *nls_codepage); | ||
| 268 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, | 288 | extern ssize_t CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon, |
| 269 | const unsigned char *searchName, char * EAData, | 289 | const unsigned char *searchName, char * EAData, |
| 270 | size_t bufsize, const struct nls_table *nls_codepage, | 290 | size_t bufsize, const struct nls_table *nls_codepage, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 0db0b313d715..9312bfc56682 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -125,6 +125,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon | 125 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon |
| 126 | , nls_codepage); | 126 | , nls_codepage); |
| 127 | up(&tcon->ses->sesSem); | 127 | up(&tcon->ses->sesSem); |
| 128 | /* BB FIXME add code to check if wsize needs | ||
| 129 | update due to negotiated smb buffer size | ||
| 130 | shrinking */ | ||
| 128 | if(rc == 0) | 131 | if(rc == 0) |
| 129 | atomic_inc(&tconInfoReconnectCount); | 132 | atomic_inc(&tconInfoReconnectCount); |
| 130 | 133 | ||
| @@ -166,11 +169,9 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 166 | 169 | ||
| 167 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); | 170 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct); |
| 168 | 171 | ||
| 169 | #ifdef CONFIG_CIFS_STATS | 172 | if(tcon != NULL) |
| 170 | if(tcon != NULL) { | 173 | cifs_stats_inc(&tcon->num_smbs_sent); |
| 171 | atomic_inc(&tcon->num_smbs_sent); | 174 | |
| 172 | } | ||
| 173 | #endif /* CONFIG_CIFS_STATS */ | ||
| 174 | return rc; | 175 | return rc; |
| 175 | } | 176 | } |
| 176 | 177 | ||
| @@ -222,6 +223,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 222 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, | 223 | rc = CIFSTCon(0, tcon->ses, tcon->treeName, |
| 223 | tcon, nls_codepage); | 224 | tcon, nls_codepage); |
| 224 | up(&tcon->ses->sesSem); | 225 | up(&tcon->ses->sesSem); |
| 226 | /* BB FIXME add code to check if wsize needs | ||
| 227 | update due to negotiated smb buffer size | ||
| 228 | shrinking */ | ||
| 225 | if(rc == 0) | 229 | if(rc == 0) |
| 226 | atomic_inc(&tconInfoReconnectCount); | 230 | atomic_inc(&tconInfoReconnectCount); |
| 227 | 231 | ||
| @@ -269,11 +273,9 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, | |||
| 269 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, | 273 | header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, |
| 270 | wct /*wct */ ); | 274 | wct /*wct */ ); |
| 271 | 275 | ||
| 272 | #ifdef CONFIG_CIFS_STATS | 276 | if(tcon != NULL) |
| 273 | if(tcon != NULL) { | 277 | cifs_stats_inc(&tcon->num_smbs_sent); |
| 274 | atomic_inc(&tcon->num_smbs_sent); | 278 | |
| 275 | } | ||
| 276 | #endif /* CONFIG_CIFS_STATS */ | ||
| 277 | return rc; | 279 | return rc; |
| 278 | } | 280 | } |
| 279 | 281 | ||
| @@ -330,7 +332,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 330 | (void **) &pSMB, (void **) &pSMBr); | 332 | (void **) &pSMB, (void **) &pSMBr); |
| 331 | if (rc) | 333 | if (rc) |
| 332 | return rc; | 334 | return rc; |
| 333 | 335 | pSMB->hdr.Mid = GetNextMid(server); | |
| 334 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; | 336 | pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; |
| 335 | if (extended_security) | 337 | if (extended_security) |
| 336 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; | 338 | pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| @@ -422,8 +424,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) | |||
| 422 | } | 424 | } |
| 423 | 425 | ||
| 424 | } | 426 | } |
| 425 | if (pSMB) | 427 | |
| 426 | cifs_buf_release(pSMB); | 428 | cifs_buf_release(pSMB); |
| 427 | return rc; | 429 | return rc; |
| 428 | } | 430 | } |
| 429 | 431 | ||
| @@ -518,6 +520,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
| 518 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ | 520 | smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */ |
| 519 | 521 | ||
| 520 | if(ses->server) { | 522 | if(ses->server) { |
| 523 | pSMB->hdr.Mid = GetNextMid(ses->server); | ||
| 524 | |||
| 521 | if(ses->server->secMode & | 525 | if(ses->server->secMode & |
| 522 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 526 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
| 523 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | 527 | pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; |
| @@ -537,9 +541,8 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses) | |||
| 537 | rc = -ESHUTDOWN; | 541 | rc = -ESHUTDOWN; |
| 538 | } | 542 | } |
| 539 | } | 543 | } |
| 540 | if (pSMB) | ||
| 541 | cifs_small_buf_release(pSMB); | ||
| 542 | up(&ses->sesSem); | 544 | up(&ses->sesSem); |
| 545 | cifs_small_buf_release(pSMB); | ||
| 543 | 546 | ||
| 544 | /* if session dead then we do not need to do ulogoff, | 547 | /* if session dead then we do not need to do ulogoff, |
| 545 | since server closed smb session, no sense reporting | 548 | since server closed smb session, no sense reporting |
| @@ -583,14 +586,10 @@ DelFileRetry: | |||
| 583 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 586 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
| 584 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 587 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 585 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 588 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 589 | cifs_stats_inc(&tcon->num_deletes); | ||
| 586 | if (rc) { | 590 | if (rc) { |
| 587 | cFYI(1, ("Error in RMFile = %d", rc)); | 591 | cFYI(1, ("Error in RMFile = %d", rc)); |
| 588 | } | 592 | } |
| 589 | #ifdef CONFIG_CIFS_STATS | ||
| 590 | else { | ||
| 591 | atomic_inc(&tcon->num_deletes); | ||
| 592 | } | ||
| 593 | #endif | ||
| 594 | 593 | ||
| 595 | cifs_buf_release(pSMB); | 594 | cifs_buf_release(pSMB); |
| 596 | if (rc == -EAGAIN) | 595 | if (rc == -EAGAIN) |
| @@ -632,14 +631,10 @@ RmDirRetry: | |||
| 632 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 631 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
| 633 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 632 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 634 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 633 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 634 | cifs_stats_inc(&tcon->num_rmdirs); | ||
| 635 | if (rc) { | 635 | if (rc) { |
| 636 | cFYI(1, ("Error in RMDir = %d", rc)); | 636 | cFYI(1, ("Error in RMDir = %d", rc)); |
| 637 | } | 637 | } |
| 638 | #ifdef CONFIG_CIFS_STATS | ||
| 639 | else { | ||
| 640 | atomic_inc(&tcon->num_rmdirs); | ||
| 641 | } | ||
| 642 | #endif | ||
| 643 | 638 | ||
| 644 | cifs_buf_release(pSMB); | 639 | cifs_buf_release(pSMB); |
| 645 | if (rc == -EAGAIN) | 640 | if (rc == -EAGAIN) |
| @@ -680,20 +675,161 @@ MkDirRetry: | |||
| 680 | pSMB->ByteCount = cpu_to_le16(name_len + 1); | 675 | pSMB->ByteCount = cpu_to_le16(name_len + 1); |
| 681 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 676 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 682 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 677 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 678 | cifs_stats_inc(&tcon->num_mkdirs); | ||
| 683 | if (rc) { | 679 | if (rc) { |
| 684 | cFYI(1, ("Error in Mkdir = %d", rc)); | 680 | cFYI(1, ("Error in Mkdir = %d", rc)); |
| 685 | } | 681 | } |
| 686 | #ifdef CONFIG_CIFS_STATS | 682 | |
| 687 | else { | ||
| 688 | atomic_inc(&tcon->num_mkdirs); | ||
| 689 | } | ||
| 690 | #endif | ||
| 691 | cifs_buf_release(pSMB); | 683 | cifs_buf_release(pSMB); |
| 692 | if (rc == -EAGAIN) | 684 | if (rc == -EAGAIN) |
| 693 | goto MkDirRetry; | 685 | goto MkDirRetry; |
| 694 | return rc; | 686 | return rc; |
| 695 | } | 687 | } |
| 696 | 688 | ||
| 689 | static __u16 convert_disposition(int disposition) | ||
| 690 | { | ||
| 691 | __u16 ofun = 0; | ||
| 692 | |||
| 693 | switch (disposition) { | ||
| 694 | case FILE_SUPERSEDE: | ||
| 695 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | ||
| 696 | break; | ||
| 697 | case FILE_OPEN: | ||
| 698 | ofun = SMBOPEN_OAPPEND; | ||
| 699 | break; | ||
| 700 | case FILE_CREATE: | ||
| 701 | ofun = SMBOPEN_OCREATE; | ||
| 702 | break; | ||
| 703 | case FILE_OPEN_IF: | ||
| 704 | ofun = SMBOPEN_OCREATE | SMBOPEN_OAPPEND; | ||
| 705 | break; | ||
| 706 | case FILE_OVERWRITE: | ||
| 707 | ofun = SMBOPEN_OTRUNC; | ||
| 708 | break; | ||
| 709 | case FILE_OVERWRITE_IF: | ||
| 710 | ofun = SMBOPEN_OCREATE | SMBOPEN_OTRUNC; | ||
| 711 | break; | ||
| 712 | default: | ||
| 713 | cFYI(1,("unknown disposition %d",disposition)); | ||
| 714 | ofun = SMBOPEN_OAPPEND; /* regular open */ | ||
| 715 | } | ||
| 716 | return ofun; | ||
| 717 | } | ||
| 718 | |||
| 719 | int | ||
| 720 | SMBLegacyOpen(const int xid, struct cifsTconInfo *tcon, | ||
| 721 | const char *fileName, const int openDisposition, | ||
| 722 | const int access_flags, const int create_options, __u16 * netfid, | ||
| 723 | int *pOplock, FILE_ALL_INFO * pfile_info, | ||
| 724 | const struct nls_table *nls_codepage, int remap) | ||
| 725 | { | ||
| 726 | int rc = -EACCES; | ||
| 727 | OPENX_REQ *pSMB = NULL; | ||
| 728 | OPENX_RSP *pSMBr = NULL; | ||
| 729 | int bytes_returned; | ||
| 730 | int name_len; | ||
| 731 | __u16 count; | ||
| 732 | |||
| 733 | OldOpenRetry: | ||
| 734 | rc = smb_init(SMB_COM_OPEN_ANDX, 15, tcon, (void **) &pSMB, | ||
| 735 | (void **) &pSMBr); | ||
| 736 | if (rc) | ||
| 737 | return rc; | ||
| 738 | |||
| 739 | pSMB->AndXCommand = 0xFF; /* none */ | ||
| 740 | |||
| 741 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
| 742 | count = 1; /* account for one byte pad to word boundary */ | ||
| 743 | name_len = | ||
| 744 | cifsConvertToUCS((__le16 *) (pSMB->fileName + 1), | ||
| 745 | fileName, PATH_MAX, nls_codepage, remap); | ||
| 746 | name_len++; /* trailing null */ | ||
| 747 | name_len *= 2; | ||
| 748 | } else { /* BB improve check for buffer overruns BB */ | ||
| 749 | count = 0; /* no pad */ | ||
| 750 | name_len = strnlen(fileName, PATH_MAX); | ||
| 751 | name_len++; /* trailing null */ | ||
| 752 | strncpy(pSMB->fileName, fileName, name_len); | ||
| 753 | } | ||
| 754 | if (*pOplock & REQ_OPLOCK) | ||
| 755 | pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK); | ||
| 756 | else if (*pOplock & REQ_BATCHOPLOCK) { | ||
| 757 | pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); | ||
| 758 | } | ||
| 759 | pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); | ||
| 760 | /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ | ||
| 761 | /* 0 = read | ||
| 762 | 1 = write | ||
| 763 | 2 = rw | ||
| 764 | 3 = execute | ||
| 765 | */ | ||
| 766 | pSMB->Mode = cpu_to_le16(2); | ||
| 767 | pSMB->Mode |= cpu_to_le16(0x40); /* deny none */ | ||
| 768 | /* set file as system file if special file such | ||
| 769 | as fifo and server expecting SFU style and | ||
| 770 | no Unix extensions */ | ||
| 771 | |||
| 772 | if(create_options & CREATE_OPTION_SPECIAL) | ||
| 773 | pSMB->FileAttributes = cpu_to_le16(ATTR_SYSTEM); | ||
| 774 | else | ||
| 775 | pSMB->FileAttributes = cpu_to_le16(0/*ATTR_NORMAL*/); /* BB FIXME */ | ||
| 776 | |||
| 777 | /* if ((omode & S_IWUGO) == 0) | ||
| 778 | pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/ | ||
| 779 | /* Above line causes problems due to vfs splitting create into two | ||
| 780 | pieces - need to set mode after file created not while it is | ||
| 781 | being created */ | ||
| 782 | |||
| 783 | /* BB FIXME BB */ | ||
| 784 | /* pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); */ | ||
| 785 | /* BB FIXME END BB */ | ||
| 786 | |||
| 787 | pSMB->Sattr = cpu_to_le16(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_DIRECTORY); | ||
| 788 | pSMB->OpenFunction = cpu_to_le16(convert_disposition(openDisposition)); | ||
| 789 | count += name_len; | ||
| 790 | pSMB->hdr.smb_buf_length += count; | ||
| 791 | |||
| 792 | pSMB->ByteCount = cpu_to_le16(count); | ||
| 793 | /* long_op set to 1 to allow for oplock break timeouts */ | ||
| 794 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
| 795 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | ||
| 796 | cifs_stats_inc(&tcon->num_opens); | ||
| 797 | if (rc) { | ||
| 798 | cFYI(1, ("Error in Open = %d", rc)); | ||
| 799 | } else { | ||
| 800 | /* BB verify if wct == 15 */ | ||
| 801 | |||
| 802 | /* *pOplock = pSMBr->OplockLevel; */ /* BB take from action field BB */ | ||
| 803 | |||
| 804 | *netfid = pSMBr->Fid; /* cifs fid stays in le */ | ||
| 805 | /* Let caller know file was created so we can set the mode. */ | ||
| 806 | /* Do we care about the CreateAction in any other cases? */ | ||
| 807 | /* BB FIXME BB */ | ||
| 808 | /* if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction) | ||
| 809 | *pOplock |= CIFS_CREATE_ACTION; */ | ||
| 810 | /* BB FIXME END */ | ||
| 811 | |||
| 812 | if(pfile_info) { | ||
| 813 | pfile_info->CreationTime = 0; /* BB convert CreateTime*/ | ||
| 814 | pfile_info->LastAccessTime = 0; /* BB fixme */ | ||
| 815 | pfile_info->LastWriteTime = 0; /* BB fixme */ | ||
| 816 | pfile_info->ChangeTime = 0; /* BB fixme */ | ||
| 817 | pfile_info->Attributes = | ||
| 818 | cpu_to_le32(le16_to_cpu(pSMBr->FileAttributes)); | ||
| 819 | /* the file_info buf is endian converted by caller */ | ||
| 820 | pfile_info->AllocationSize = | ||
| 821 | cpu_to_le64(le32_to_cpu(pSMBr->EndOfFile)); | ||
| 822 | pfile_info->EndOfFile = pfile_info->AllocationSize; | ||
| 823 | pfile_info->NumberOfLinks = cpu_to_le32(1); | ||
| 824 | } | ||
| 825 | } | ||
| 826 | |||
| 827 | cifs_buf_release(pSMB); | ||
| 828 | if (rc == -EAGAIN) | ||
| 829 | goto OldOpenRetry; | ||
| 830 | return rc; | ||
| 831 | } | ||
| 832 | |||
| 697 | int | 833 | int |
| 698 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, | 834 | CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon, |
| 699 | const char *fileName, const int openDisposition, | 835 | const char *fileName, const int openDisposition, |
| @@ -738,7 +874,13 @@ openRetry: | |||
| 738 | } | 874 | } |
| 739 | pSMB->DesiredAccess = cpu_to_le32(access_flags); | 875 | pSMB->DesiredAccess = cpu_to_le32(access_flags); |
| 740 | pSMB->AllocationSize = 0; | 876 | pSMB->AllocationSize = 0; |
| 741 | pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); | 877 | /* set file as system file if special file such |
| 878 | as fifo and server expecting SFU style and | ||
| 879 | no Unix extensions */ | ||
| 880 | if(create_options & CREATE_OPTION_SPECIAL) | ||
| 881 | pSMB->FileAttributes = cpu_to_le32(ATTR_SYSTEM); | ||
| 882 | else | ||
| 883 | pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL); | ||
| 742 | /* XP does not handle ATTR_POSIX_SEMANTICS */ | 884 | /* XP does not handle ATTR_POSIX_SEMANTICS */ |
| 743 | /* but it helps speed up case sensitive checks for other | 885 | /* but it helps speed up case sensitive checks for other |
| 744 | servers such as Samba */ | 886 | servers such as Samba */ |
| @@ -752,7 +894,7 @@ openRetry: | |||
| 752 | being created */ | 894 | being created */ |
| 753 | pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); | 895 | pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL); |
| 754 | pSMB->CreateDisposition = cpu_to_le32(openDisposition); | 896 | pSMB->CreateDisposition = cpu_to_le32(openDisposition); |
| 755 | pSMB->CreateOptions = cpu_to_le32(create_options); | 897 | pSMB->CreateOptions = cpu_to_le32(create_options & CREATE_OPTIONS_MASK); |
| 756 | /* BB Expirement with various impersonation levels and verify */ | 898 | /* BB Expirement with various impersonation levels and verify */ |
| 757 | pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); | 899 | pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); |
| 758 | pSMB->SecurityFlags = | 900 | pSMB->SecurityFlags = |
| @@ -765,6 +907,7 @@ openRetry: | |||
| 765 | /* long_op set to 1 to allow for oplock break timeouts */ | 907 | /* long_op set to 1 to allow for oplock break timeouts */ |
| 766 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 908 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 767 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); | 909 | (struct smb_hdr *) pSMBr, &bytes_returned, 1); |
| 910 | cifs_stats_inc(&tcon->num_opens); | ||
| 768 | if (rc) { | 911 | if (rc) { |
| 769 | cFYI(1, ("Error in Open = %d", rc)); | 912 | cFYI(1, ("Error in Open = %d", rc)); |
| 770 | } else { | 913 | } else { |
| @@ -782,11 +925,8 @@ openRetry: | |||
| 782 | pfile_info->EndOfFile = pSMBr->EndOfFile; | 925 | pfile_info->EndOfFile = pSMBr->EndOfFile; |
| 783 | pfile_info->NumberOfLinks = cpu_to_le32(1); | 926 | pfile_info->NumberOfLinks = cpu_to_le32(1); |
| 784 | } | 927 | } |
| 785 | |||
| 786 | #ifdef CONFIG_CIFS_STATS | ||
| 787 | atomic_inc(&tcon->num_opens); | ||
| 788 | #endif | ||
| 789 | } | 928 | } |
| 929 | |||
| 790 | cifs_buf_release(pSMB); | 930 | cifs_buf_release(pSMB); |
| 791 | if (rc == -EAGAIN) | 931 | if (rc == -EAGAIN) |
| 792 | goto openRetry; | 932 | goto openRetry; |
| @@ -807,11 +947,16 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
| 807 | READ_RSP *pSMBr = NULL; | 947 | READ_RSP *pSMBr = NULL; |
| 808 | char *pReadData = NULL; | 948 | char *pReadData = NULL; |
| 809 | int bytes_returned; | 949 | int bytes_returned; |
| 950 | int wct; | ||
| 810 | 951 | ||
| 811 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); | 952 | cFYI(1,("Reading %d bytes on fid %d",count,netfid)); |
| 953 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | ||
| 954 | wct = 12; | ||
| 955 | else | ||
| 956 | wct = 10; /* old style read */ | ||
| 812 | 957 | ||
| 813 | *nbytes = 0; | 958 | *nbytes = 0; |
| 814 | rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB, | 959 | rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB, |
| 815 | (void **) &pSMBr); | 960 | (void **) &pSMBr); |
| 816 | if (rc) | 961 | if (rc) |
| 817 | return rc; | 962 | return rc; |
| @@ -823,14 +968,26 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, | |||
| 823 | pSMB->AndXCommand = 0xFF; /* none */ | 968 | pSMB->AndXCommand = 0xFF; /* none */ |
| 824 | pSMB->Fid = netfid; | 969 | pSMB->Fid = netfid; |
| 825 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); | 970 | pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); |
| 826 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | 971 | if(wct == 12) |
| 972 | pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); | ||
| 973 | else if((lseek >> 32) > 0) /* can not handle this big offset for old */ | ||
| 974 | return -EIO; | ||
| 975 | |||
| 827 | pSMB->Remaining = 0; | 976 | pSMB->Remaining = 0; |
| 828 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); | 977 | pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); |
| 829 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); | 978 | pSMB->MaxCountHigh = cpu_to_le32(count >> 16); |
| 830 | pSMB->ByteCount = 0; /* no need to do le conversion since it is 0 */ | 979 | if(wct == 12) |
| 831 | 980 | pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ | |
| 981 | else { | ||
| 982 | /* old style read */ | ||
| 983 | struct smb_com_readx_req * pSMBW = | ||
| 984 | (struct smb_com_readx_req *)pSMB; | ||
| 985 | pSMBW->ByteCount = 0; | ||
| 986 | } | ||
| 987 | |||
| 832 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 988 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 833 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 989 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 990 | cifs_stats_inc(&tcon->num_reads); | ||
| 834 | if (rc) { | 991 | if (rc) { |
| 835 | cERROR(1, ("Send error in read = %d", rc)); | 992 | cERROR(1, ("Send error in read = %d", rc)); |
| 836 | } else { | 993 | } else { |
| @@ -876,12 +1033,20 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
| 876 | int rc = -EACCES; | 1033 | int rc = -EACCES; |
| 877 | WRITE_REQ *pSMB = NULL; | 1034 | WRITE_REQ *pSMB = NULL; |
| 878 | WRITE_RSP *pSMBr = NULL; | 1035 | WRITE_RSP *pSMBr = NULL; |
| 879 | int bytes_returned; | 1036 | int bytes_returned, wct; |
| 880 | __u32 bytes_sent; | 1037 | __u32 bytes_sent; |
| 881 | __u16 byte_count; | 1038 | __u16 byte_count; |
| 882 | 1039 | ||
| 883 | /* cFYI(1,("write at %lld %d bytes",offset,count));*/ | 1040 | /* cFYI(1,("write at %lld %d bytes",offset,count));*/ |
| 884 | rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB, | 1041 | if(tcon->ses == NULL) |
| 1042 | return -ECONNABORTED; | ||
| 1043 | |||
| 1044 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | ||
| 1045 | wct = 14; | ||
| 1046 | else | ||
| 1047 | wct = 12; | ||
| 1048 | |||
| 1049 | rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB, | ||
| 885 | (void **) &pSMBr); | 1050 | (void **) &pSMBr); |
| 886 | if (rc) | 1051 | if (rc) |
| 887 | return rc; | 1052 | return rc; |
| @@ -892,7 +1057,11 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
| 892 | pSMB->AndXCommand = 0xFF; /* none */ | 1057 | pSMB->AndXCommand = 0xFF; /* none */ |
| 893 | pSMB->Fid = netfid; | 1058 | pSMB->Fid = netfid; |
| 894 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 1059 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); |
| 895 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 1060 | if(wct == 14) |
| 1061 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | ||
| 1062 | else if((offset >> 32) > 0) /* can not handle this big offset for old */ | ||
| 1063 | return -EIO; | ||
| 1064 | |||
| 896 | pSMB->Reserved = 0xFFFFFFFF; | 1065 | pSMB->Reserved = 0xFFFFFFFF; |
| 897 | pSMB->WriteMode = 0; | 1066 | pSMB->WriteMode = 0; |
| 898 | pSMB->Remaining = 0; | 1067 | pSMB->Remaining = 0; |
| @@ -911,7 +1080,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
| 911 | if (bytes_sent > count) | 1080 | if (bytes_sent > count) |
| 912 | bytes_sent = count; | 1081 | bytes_sent = count; |
| 913 | pSMB->DataOffset = | 1082 | pSMB->DataOffset = |
| 914 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1083 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
| 915 | if(buf) | 1084 | if(buf) |
| 916 | memcpy(pSMB->Data,buf,bytes_sent); | 1085 | memcpy(pSMB->Data,buf,bytes_sent); |
| 917 | else if(ubuf) { | 1086 | else if(ubuf) { |
| @@ -919,20 +1088,31 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
| 919 | cifs_buf_release(pSMB); | 1088 | cifs_buf_release(pSMB); |
| 920 | return -EFAULT; | 1089 | return -EFAULT; |
| 921 | } | 1090 | } |
| 922 | } else { | 1091 | } else if (count != 0) { |
| 923 | /* No buffer */ | 1092 | /* No buffer */ |
| 924 | cifs_buf_release(pSMB); | 1093 | cifs_buf_release(pSMB); |
| 925 | return -EINVAL; | 1094 | return -EINVAL; |
| 1095 | } /* else setting file size with write of zero bytes */ | ||
| 1096 | if(wct == 14) | ||
| 1097 | byte_count = bytes_sent + 1; /* pad */ | ||
| 1098 | else /* wct == 12 */ { | ||
| 1099 | byte_count = bytes_sent + 5; /* bigger pad, smaller smb hdr */ | ||
| 926 | } | 1100 | } |
| 927 | |||
| 928 | byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */ | ||
| 929 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); | 1101 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF); |
| 930 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); | 1102 | pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16); |
| 931 | pSMB->hdr.smb_buf_length += bytes_sent+1; | 1103 | pSMB->hdr.smb_buf_length += byte_count; |
| 932 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1104 | |
| 1105 | if(wct == 14) | ||
| 1106 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
| 1107 | else { /* old style write has byte count 4 bytes earlier so 4 bytes pad */ | ||
| 1108 | struct smb_com_writex_req * pSMBW = | ||
| 1109 | (struct smb_com_writex_req *)pSMB; | ||
| 1110 | pSMBW->ByteCount = cpu_to_le16(byte_count); | ||
| 1111 | } | ||
| 933 | 1112 | ||
| 934 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1113 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 935 | (struct smb_hdr *) pSMBr, &bytes_returned, long_op); | 1114 | (struct smb_hdr *) pSMBr, &bytes_returned, long_op); |
| 1115 | cifs_stats_inc(&tcon->num_writes); | ||
| 936 | if (rc) { | 1116 | if (rc) { |
| 937 | cFYI(1, ("Send error in write = %d", rc)); | 1117 | cFYI(1, ("Send error in write = %d", rc)); |
| 938 | *nbytes = 0; | 1118 | *nbytes = 0; |
| @@ -951,56 +1131,72 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, | |||
| 951 | } | 1131 | } |
| 952 | 1132 | ||
| 953 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1133 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| 954 | int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | 1134 | int |
| 1135 | CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | ||
| 955 | const int netfid, const unsigned int count, | 1136 | const int netfid, const unsigned int count, |
| 956 | const __u64 offset, unsigned int *nbytes, const char __user *buf, | 1137 | const __u64 offset, unsigned int *nbytes, struct kvec *iov, |
| 957 | const int long_op) | 1138 | int n_vec, const int long_op) |
| 958 | { | 1139 | { |
| 959 | int rc = -EACCES; | 1140 | int rc = -EACCES; |
| 960 | WRITE_REQ *pSMB = NULL; | 1141 | WRITE_REQ *pSMB = NULL; |
| 961 | WRITE_RSP *pSMBr = NULL; | 1142 | int bytes_returned, wct; |
| 962 | /*int bytes_returned;*/ | 1143 | int smb_hdr_len; |
| 963 | unsigned bytes_sent; | ||
| 964 | __u16 byte_count; | ||
| 965 | 1144 | ||
| 966 | rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB); | 1145 | cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ |
| 967 | 1146 | if(tcon->ses->capabilities & CAP_LARGE_FILES) | |
| 1147 | wct = 14; | ||
| 1148 | else | ||
| 1149 | wct = 12; | ||
| 1150 | rc = small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB); | ||
| 968 | if (rc) | 1151 | if (rc) |
| 969 | return rc; | 1152 | return rc; |
| 970 | |||
| 971 | pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */ | ||
| 972 | |||
| 973 | /* tcon and ses pointer are checked in smb_init */ | 1153 | /* tcon and ses pointer are checked in smb_init */ |
| 974 | if (tcon->ses->server == NULL) | 1154 | if (tcon->ses->server == NULL) |
| 975 | return -ECONNABORTED; | 1155 | return -ECONNABORTED; |
| 976 | 1156 | ||
| 977 | pSMB->AndXCommand = 0xFF; /* none */ | 1157 | pSMB->AndXCommand = 0xFF; /* none */ |
| 978 | pSMB->Fid = netfid; | 1158 | pSMB->Fid = netfid; |
| 979 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); | 1159 | pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF); |
| 980 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | 1160 | if(wct == 14) |
| 1161 | pSMB->OffsetHigh = cpu_to_le32(offset >> 32); | ||
| 1162 | else if((offset >> 32) > 0) /* can not handle this big offset for old */ | ||
| 1163 | return -EIO; | ||
| 981 | pSMB->Reserved = 0xFFFFFFFF; | 1164 | pSMB->Reserved = 0xFFFFFFFF; |
| 982 | pSMB->WriteMode = 0; | 1165 | pSMB->WriteMode = 0; |
| 983 | pSMB->Remaining = 0; | 1166 | pSMB->Remaining = 0; |
| 984 | bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF; | 1167 | |
| 985 | if (bytes_sent > count) | ||
| 986 | bytes_sent = count; | ||
| 987 | pSMB->DataLengthHigh = 0; | ||
| 988 | pSMB->DataOffset = | 1168 | pSMB->DataOffset = |
| 989 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); | 1169 | cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4); |
| 990 | 1170 | ||
| 991 | byte_count = bytes_sent + 1 /* pad */ ; | 1171 | pSMB->DataLengthLow = cpu_to_le16(count & 0xFFFF); |
| 992 | pSMB->DataLengthLow = cpu_to_le16(bytes_sent); | 1172 | pSMB->DataLengthHigh = cpu_to_le16(count >> 16); |
| 993 | pSMB->DataLengthHigh = 0; | 1173 | smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */ |
| 994 | pSMB->hdr.smb_buf_length += byte_count; | 1174 | if(wct == 14) |
| 995 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1175 | pSMB->hdr.smb_buf_length += count+1; |
| 1176 | else /* wct == 12 */ | ||
| 1177 | pSMB->hdr.smb_buf_length += count+5; /* smb data starts later */ | ||
| 1178 | if(wct == 14) | ||
| 1179 | pSMB->ByteCount = cpu_to_le16(count + 1); | ||
| 1180 | else /* wct == 12 */ /* bigger pad, smaller smb hdr, keep offset ok */ { | ||
| 1181 | struct smb_com_writex_req * pSMBW = | ||
| 1182 | (struct smb_com_writex_req *)pSMB; | ||
| 1183 | pSMBW->ByteCount = cpu_to_le16(count + 5); | ||
| 1184 | } | ||
| 1185 | iov[0].iov_base = pSMB; | ||
| 1186 | iov[0].iov_len = smb_hdr_len + 4; | ||
| 996 | 1187 | ||
| 997 | /* rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1188 | rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, |
| 998 | (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */ /* BB fixme BB */ | 1189 | long_op); |
| 1190 | cifs_stats_inc(&tcon->num_writes); | ||
| 999 | if (rc) { | 1191 | if (rc) { |
| 1000 | cFYI(1, ("Send error in write2 (large write) = %d", rc)); | 1192 | cFYI(1, ("Send error Write2 = %d", rc)); |
| 1001 | *nbytes = 0; | 1193 | *nbytes = 0; |
| 1002 | } else | 1194 | } else { |
| 1003 | *nbytes = le16_to_cpu(pSMBr->Count); | 1195 | WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; |
| 1196 | *nbytes = le16_to_cpu(pSMBr->CountHigh); | ||
| 1197 | *nbytes = (*nbytes) << 16; | ||
| 1198 | *nbytes += le16_to_cpu(pSMBr->Count); | ||
| 1199 | } | ||
| 1004 | 1200 | ||
| 1005 | cifs_small_buf_release(pSMB); | 1201 | cifs_small_buf_release(pSMB); |
| 1006 | 1202 | ||
| @@ -1009,6 +1205,8 @@ int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, | |||
| 1009 | 1205 | ||
| 1010 | return rc; | 1206 | return rc; |
| 1011 | } | 1207 | } |
| 1208 | |||
| 1209 | |||
| 1012 | #endif /* CIFS_EXPERIMENTAL */ | 1210 | #endif /* CIFS_EXPERIMENTAL */ |
| 1013 | 1211 | ||
| 1014 | int | 1212 | int |
| @@ -1065,7 +1263,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, | |||
| 1065 | 1263 | ||
| 1066 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1264 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1067 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); | 1265 | (struct smb_hdr *) pSMBr, &bytes_returned, timeout); |
| 1068 | 1266 | cifs_stats_inc(&tcon->num_locks); | |
| 1069 | if (rc) { | 1267 | if (rc) { |
| 1070 | cFYI(1, ("Send error in Lock = %d", rc)); | 1268 | cFYI(1, ("Send error in Lock = %d", rc)); |
| 1071 | } | 1269 | } |
| @@ -1099,6 +1297,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) | |||
| 1099 | pSMB->ByteCount = 0; | 1297 | pSMB->ByteCount = 0; |
| 1100 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1298 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1101 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1299 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 1300 | cifs_stats_inc(&tcon->num_closes); | ||
| 1102 | if (rc) { | 1301 | if (rc) { |
| 1103 | if(rc!=-EINTR) { | 1302 | if(rc!=-EINTR) { |
| 1104 | /* EINTR is expected when user ctl-c to kill app */ | 1303 | /* EINTR is expected when user ctl-c to kill app */ |
| @@ -1171,16 +1370,11 @@ renameRetry: | |||
| 1171 | 1370 | ||
| 1172 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1371 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1173 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1372 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 1373 | cifs_stats_inc(&tcon->num_renames); | ||
| 1174 | if (rc) { | 1374 | if (rc) { |
| 1175 | cFYI(1, ("Send error in rename = %d", rc)); | 1375 | cFYI(1, ("Send error in rename = %d", rc)); |
| 1176 | } | 1376 | } |
| 1177 | 1377 | ||
| 1178 | #ifdef CONFIG_CIFS_STATS | ||
| 1179 | else { | ||
| 1180 | atomic_inc(&tcon->num_renames); | ||
| 1181 | } | ||
| 1182 | #endif | ||
| 1183 | |||
| 1184 | cifs_buf_release(pSMB); | 1378 | cifs_buf_release(pSMB); |
| 1185 | 1379 | ||
| 1186 | if (rc == -EAGAIN) | 1380 | if (rc == -EAGAIN) |
| @@ -1255,14 +1449,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, | |||
| 1255 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1449 | pSMB->ByteCount = cpu_to_le16(byte_count); |
| 1256 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, | 1450 | rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB, |
| 1257 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1451 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 1452 | cifs_stats_inc(&pTcon->num_t2renames); | ||
| 1258 | if (rc) { | 1453 | if (rc) { |
| 1259 | cFYI(1,("Send error in Rename (by file handle) = %d", rc)); | 1454 | cFYI(1,("Send error in Rename (by file handle) = %d", rc)); |
| 1260 | } | 1455 | } |
| 1261 | #ifdef CONFIG_CIFS_STATS | 1456 | |
| 1262 | else { | ||
| 1263 | atomic_inc(&pTcon->num_t2renames); | ||
| 1264 | } | ||
| 1265 | #endif | ||
| 1266 | cifs_buf_release(pSMB); | 1457 | cifs_buf_release(pSMB); |
| 1267 | 1458 | ||
| 1268 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1459 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
| @@ -1416,6 +1607,7 @@ createSymLinkRetry: | |||
| 1416 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1607 | pSMB->ByteCount = cpu_to_le16(byte_count); |
| 1417 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1608 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1418 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1609 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 1610 | cifs_stats_inc(&tcon->num_symlinks); | ||
| 1419 | if (rc) { | 1611 | if (rc) { |
| 1420 | cFYI(1, | 1612 | cFYI(1, |
| 1421 | ("Send error in SetPathInfo (create symlink) = %d", | 1613 | ("Send error in SetPathInfo (create symlink) = %d", |
| @@ -1505,6 +1697,7 @@ createHardLinkRetry: | |||
| 1505 | pSMB->ByteCount = cpu_to_le16(byte_count); | 1697 | pSMB->ByteCount = cpu_to_le16(byte_count); |
| 1506 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1698 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1507 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1699 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 1700 | cifs_stats_inc(&tcon->num_hardlinks); | ||
| 1508 | if (rc) { | 1701 | if (rc) { |
| 1509 | cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); | 1702 | cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc)); |
| 1510 | } | 1703 | } |
| @@ -1575,6 +1768,7 @@ winCreateHardLinkRetry: | |||
| 1575 | 1768 | ||
| 1576 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 1769 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 1577 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 1770 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 1771 | cifs_stats_inc(&tcon->num_hardlinks); | ||
| 1578 | if (rc) { | 1772 | if (rc) { |
| 1579 | cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); | 1773 | cFYI(1, ("Send error in hard link (NT rename) = %d", rc)); |
| 1580 | } | 1774 | } |
| @@ -1775,8 +1969,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, | |||
| 1775 | } | 1969 | } |
| 1776 | } | 1970 | } |
| 1777 | qreparse_out: | 1971 | qreparse_out: |
| 1778 | if (pSMB) | 1972 | cifs_buf_release(pSMB); |
| 1779 | cifs_buf_release(pSMB); | ||
| 1780 | 1973 | ||
| 1781 | /* Note: On -EAGAIN error only caller can retry on handle based calls | 1974 | /* Note: On -EAGAIN error only caller can retry on handle based calls |
| 1782 | since file handle passed in no longer valid */ | 1975 | since file handle passed in no longer valid */ |
| @@ -2165,6 +2358,67 @@ GetExtAttrOut: | |||
| 2165 | 2358 | ||
| 2166 | #endif /* CONFIG_POSIX */ | 2359 | #endif /* CONFIG_POSIX */ |
| 2167 | 2360 | ||
| 2361 | /* Legacy Query Path Information call for lookup to old servers such | ||
| 2362 | as Win9x/WinME */ | ||
| 2363 | int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, | ||
| 2364 | const unsigned char *searchName, | ||
| 2365 | FILE_ALL_INFO * pFinfo, | ||
| 2366 | const struct nls_table *nls_codepage, int remap) | ||
| 2367 | { | ||
| 2368 | QUERY_INFORMATION_REQ * pSMB; | ||
| 2369 | QUERY_INFORMATION_RSP * pSMBr; | ||
| 2370 | int rc = 0; | ||
| 2371 | int bytes_returned; | ||
| 2372 | int name_len; | ||
| 2373 | |||
| 2374 | cFYI(1, ("In SMBQPath path %s", searchName)); | ||
| 2375 | QInfRetry: | ||
| 2376 | rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB, | ||
| 2377 | (void **) &pSMBr); | ||
| 2378 | if (rc) | ||
| 2379 | return rc; | ||
| 2380 | |||
| 2381 | if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { | ||
| 2382 | name_len = | ||
| 2383 | cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, | ||
| 2384 | PATH_MAX, nls_codepage, remap); | ||
| 2385 | name_len++; /* trailing null */ | ||
| 2386 | name_len *= 2; | ||
| 2387 | } else { | ||
| 2388 | name_len = strnlen(searchName, PATH_MAX); | ||
| 2389 | name_len++; /* trailing null */ | ||
| 2390 | strncpy(pSMB->FileName, searchName, name_len); | ||
| 2391 | } | ||
| 2392 | pSMB->BufferFormat = 0x04; | ||
| 2393 | name_len++; /* account for buffer type byte */ | ||
| 2394 | pSMB->hdr.smb_buf_length += (__u16) name_len; | ||
| 2395 | pSMB->ByteCount = cpu_to_le16(name_len); | ||
| 2396 | |||
| 2397 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
| 2398 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
| 2399 | if (rc) { | ||
| 2400 | cFYI(1, ("Send error in QueryInfo = %d", rc)); | ||
| 2401 | } else if (pFinfo) { /* decode response */ | ||
| 2402 | memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); | ||
| 2403 | pFinfo->AllocationSize = | ||
| 2404 | cpu_to_le64(le32_to_cpu(pSMBr->size)); | ||
| 2405 | pFinfo->EndOfFile = pFinfo->AllocationSize; | ||
| 2406 | pFinfo->Attributes = | ||
| 2407 | cpu_to_le32(le16_to_cpu(pSMBr->attr)); | ||
| 2408 | } else | ||
| 2409 | rc = -EIO; /* bad buffer passed in */ | ||
| 2410 | |||
| 2411 | cifs_buf_release(pSMB); | ||
| 2412 | |||
| 2413 | if (rc == -EAGAIN) | ||
| 2414 | goto QInfRetry; | ||
| 2415 | |||
| 2416 | return rc; | ||
| 2417 | } | ||
| 2418 | |||
| 2419 | |||
| 2420 | |||
| 2421 | |||
| 2168 | int | 2422 | int |
| 2169 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, | 2423 | CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, |
| 2170 | const unsigned char *searchName, | 2424 | const unsigned char *searchName, |
| @@ -2396,7 +2650,7 @@ findUniqueRetry: | |||
| 2396 | if (rc) { | 2650 | if (rc) { |
| 2397 | cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); | 2651 | cFYI(1, ("Send error in FindFileDirInfo = %d", rc)); |
| 2398 | } else { /* decode response */ | 2652 | } else { /* decode response */ |
| 2399 | 2653 | cifs_stats_inc(&tcon->num_ffirst); | |
| 2400 | /* BB fill in */ | 2654 | /* BB fill in */ |
| 2401 | } | 2655 | } |
| 2402 | 2656 | ||
| @@ -2414,7 +2668,7 @@ CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, | |||
| 2414 | const char *searchName, | 2668 | const char *searchName, |
| 2415 | const struct nls_table *nls_codepage, | 2669 | const struct nls_table *nls_codepage, |
| 2416 | __u16 * pnetfid, | 2670 | __u16 * pnetfid, |
| 2417 | struct cifs_search_info * psrch_inf, int remap) | 2671 | struct cifs_search_info * psrch_inf, int remap, const char dirsep) |
| 2418 | { | 2672 | { |
| 2419 | /* level 257 SMB_ */ | 2673 | /* level 257 SMB_ */ |
| 2420 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; | 2674 | TRANSACTION2_FFIRST_REQ *pSMB = NULL; |
| @@ -2441,7 +2695,7 @@ findFirstRetry: | |||
| 2441 | it got remapped to 0xF03A as if it were part of the | 2695 | it got remapped to 0xF03A as if it were part of the |
| 2442 | directory name instead of a wildcard */ | 2696 | directory name instead of a wildcard */ |
| 2443 | name_len *= 2; | 2697 | name_len *= 2; |
| 2444 | pSMB->FileName[name_len] = '\\'; | 2698 | pSMB->FileName[name_len] = dirsep; |
| 2445 | pSMB->FileName[name_len+1] = 0; | 2699 | pSMB->FileName[name_len+1] = 0; |
| 2446 | pSMB->FileName[name_len+2] = '*'; | 2700 | pSMB->FileName[name_len+2] = '*'; |
| 2447 | pSMB->FileName[name_len+3] = 0; | 2701 | pSMB->FileName[name_len+3] = 0; |
| @@ -2455,7 +2709,7 @@ findFirstRetry: | |||
| 2455 | if(name_len > buffersize-header) | 2709 | if(name_len > buffersize-header) |
| 2456 | free buffer exit; BB */ | 2710 | free buffer exit; BB */ |
| 2457 | strncpy(pSMB->FileName, searchName, name_len); | 2711 | strncpy(pSMB->FileName, searchName, name_len); |
| 2458 | pSMB->FileName[name_len] = '\\'; | 2712 | pSMB->FileName[name_len] = dirsep; |
| 2459 | pSMB->FileName[name_len+1] = '*'; | 2713 | pSMB->FileName[name_len+1] = '*'; |
| 2460 | pSMB->FileName[name_len+2] = 0; | 2714 | pSMB->FileName[name_len+2] = 0; |
| 2461 | name_len += 3; | 2715 | name_len += 3; |
| @@ -2496,6 +2750,7 @@ findFirstRetry: | |||
| 2496 | 2750 | ||
| 2497 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2751 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 2498 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2752 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 2753 | cifs_stats_inc(&tcon->num_ffirst); | ||
| 2499 | 2754 | ||
| 2500 | if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ | 2755 | if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */ |
| 2501 | /* BB Add code to handle unsupported level rc */ | 2756 | /* BB Add code to handle unsupported level rc */ |
| @@ -2617,7 +2872,7 @@ int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, | |||
| 2617 | 2872 | ||
| 2618 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 2873 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 2619 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 2874 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 2620 | 2875 | cifs_stats_inc(&tcon->num_fnext); | |
| 2621 | if (rc) { | 2876 | if (rc) { |
| 2622 | if (rc == -EBADF) { | 2877 | if (rc == -EBADF) { |
| 2623 | psrch_inf->endOfSearch = TRUE; | 2878 | psrch_inf->endOfSearch = TRUE; |
| @@ -2694,6 +2949,7 @@ CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle | |||
| 2694 | if (rc) { | 2949 | if (rc) { |
| 2695 | cERROR(1, ("Send error in FindClose = %d", rc)); | 2950 | cERROR(1, ("Send error in FindClose = %d", rc)); |
| 2696 | } | 2951 | } |
| 2952 | cifs_stats_inc(&tcon->num_fclose); | ||
| 2697 | cifs_small_buf_release(pSMB); | 2953 | cifs_small_buf_release(pSMB); |
| 2698 | 2954 | ||
| 2699 | /* Since session is dead, search handle closed on server already */ | 2955 | /* Since session is dead, search handle closed on server already */ |
| @@ -2827,7 +3083,10 @@ getDFSRetry: | |||
| 2827 | (void **) &pSMBr); | 3083 | (void **) &pSMBr); |
| 2828 | if (rc) | 3084 | if (rc) |
| 2829 | return rc; | 3085 | return rc; |
| 2830 | 3086 | ||
| 3087 | /* server pointer checked in called function, | ||
| 3088 | but should never be null here anyway */ | ||
| 3089 | pSMB->hdr.Mid = GetNextMid(ses->server); | ||
| 2831 | pSMB->hdr.Tid = ses->ipc_tid; | 3090 | pSMB->hdr.Tid = ses->ipc_tid; |
| 2832 | pSMB->hdr.Uid = ses->Suid; | 3091 | pSMB->hdr.Uid = ses->Suid; |
| 2833 | if (ses->capabilities & CAP_STATUS32) { | 3092 | if (ses->capabilities & CAP_STATUS32) { |
| @@ -2968,6 +3227,92 @@ GetDFSRefExit: | |||
| 2968 | return rc; | 3227 | return rc; |
| 2969 | } | 3228 | } |
| 2970 | 3229 | ||
| 3230 | /* Query File System Info such as free space to old servers such as Win 9x */ | ||
| 3231 | int | ||
| 3232 | SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) | ||
| 3233 | { | ||
| 3234 | /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */ | ||
| 3235 | TRANSACTION2_QFSI_REQ *pSMB = NULL; | ||
| 3236 | TRANSACTION2_QFSI_RSP *pSMBr = NULL; | ||
| 3237 | FILE_SYSTEM_ALLOC_INFO *response_data; | ||
| 3238 | int rc = 0; | ||
| 3239 | int bytes_returned = 0; | ||
| 3240 | __u16 params, byte_count; | ||
| 3241 | |||
| 3242 | cFYI(1, ("OldQFSInfo")); | ||
| 3243 | oldQFSInfoRetry: | ||
| 3244 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
| 3245 | (void **) &pSMBr); | ||
| 3246 | if (rc) | ||
| 3247 | return rc; | ||
| 3248 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
| 3249 | (void **) &pSMBr); | ||
| 3250 | if (rc) | ||
| 3251 | return rc; | ||
| 3252 | |||
| 3253 | params = 2; /* level */ | ||
| 3254 | pSMB->TotalDataCount = 0; | ||
| 3255 | pSMB->MaxParameterCount = cpu_to_le16(2); | ||
| 3256 | pSMB->MaxDataCount = cpu_to_le16(1000); | ||
| 3257 | pSMB->MaxSetupCount = 0; | ||
| 3258 | pSMB->Reserved = 0; | ||
| 3259 | pSMB->Flags = 0; | ||
| 3260 | pSMB->Timeout = 0; | ||
| 3261 | pSMB->Reserved2 = 0; | ||
| 3262 | byte_count = params + 1 /* pad */ ; | ||
| 3263 | pSMB->TotalParameterCount = cpu_to_le16(params); | ||
| 3264 | pSMB->ParameterCount = pSMB->TotalParameterCount; | ||
| 3265 | pSMB->ParameterOffset = cpu_to_le16(offsetof( | ||
| 3266 | struct smb_com_transaction2_qfsi_req, InformationLevel) - 4); | ||
| 3267 | pSMB->DataCount = 0; | ||
| 3268 | pSMB->DataOffset = 0; | ||
| 3269 | pSMB->SetupCount = 1; | ||
| 3270 | pSMB->Reserved3 = 0; | ||
| 3271 | pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION); | ||
| 3272 | pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION); | ||
| 3273 | pSMB->hdr.smb_buf_length += byte_count; | ||
| 3274 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
| 3275 | |||
| 3276 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
| 3277 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
| 3278 | if (rc) { | ||
| 3279 | cFYI(1, ("Send error in QFSInfo = %d", rc)); | ||
| 3280 | } else { /* decode response */ | ||
| 3281 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
| 3282 | |||
| 3283 | if (rc || (pSMBr->ByteCount < 18)) | ||
| 3284 | rc = -EIO; /* bad smb */ | ||
| 3285 | else { | ||
| 3286 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | ||
| 3287 | cFYI(1,("qfsinf resp BCC: %d Offset %d", | ||
| 3288 | pSMBr->ByteCount, data_offset)); | ||
| 3289 | |||
| 3290 | response_data = | ||
| 3291 | (FILE_SYSTEM_ALLOC_INFO *) | ||
| 3292 | (((char *) &pSMBr->hdr.Protocol) + data_offset); | ||
| 3293 | FSData->f_bsize = | ||
| 3294 | le16_to_cpu(response_data->BytesPerSector) * | ||
| 3295 | le32_to_cpu(response_data-> | ||
| 3296 | SectorsPerAllocationUnit); | ||
| 3297 | FSData->f_blocks = | ||
| 3298 | le32_to_cpu(response_data->TotalAllocationUnits); | ||
| 3299 | FSData->f_bfree = FSData->f_bavail = | ||
| 3300 | le32_to_cpu(response_data->FreeAllocationUnits); | ||
| 3301 | cFYI(1, | ||
| 3302 | ("Blocks: %lld Free: %lld Block size %ld", | ||
| 3303 | (unsigned long long)FSData->f_blocks, | ||
| 3304 | (unsigned long long)FSData->f_bfree, | ||
| 3305 | FSData->f_bsize)); | ||
| 3306 | } | ||
| 3307 | } | ||
| 3308 | cifs_buf_release(pSMB); | ||
| 3309 | |||
| 3310 | if (rc == -EAGAIN) | ||
| 3311 | goto oldQFSInfoRetry; | ||
| 3312 | |||
| 3313 | return rc; | ||
| 3314 | } | ||
| 3315 | |||
| 2971 | int | 3316 | int |
| 2972 | CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) | 3317 | CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData) |
| 2973 | { | 3318 | { |
| @@ -2989,7 +3334,7 @@ QFSInfoRetry: | |||
| 2989 | params = 2; /* level */ | 3334 | params = 2; /* level */ |
| 2990 | pSMB->TotalDataCount = 0; | 3335 | pSMB->TotalDataCount = 0; |
| 2991 | pSMB->MaxParameterCount = cpu_to_le16(2); | 3336 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 2992 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ | 3337 | pSMB->MaxDataCount = cpu_to_le16(1000); |
| 2993 | pSMB->MaxSetupCount = 0; | 3338 | pSMB->MaxSetupCount = 0; |
| 2994 | pSMB->Reserved = 0; | 3339 | pSMB->Reserved = 0; |
| 2995 | pSMB->Flags = 0; | 3340 | pSMB->Flags = 0; |
| @@ -3012,17 +3357,14 @@ QFSInfoRetry: | |||
| 3012 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | 3357 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, |
| 3013 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | 3358 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); |
| 3014 | if (rc) { | 3359 | if (rc) { |
| 3015 | cERROR(1, ("Send error in QFSInfo = %d", rc)); | 3360 | cFYI(1, ("Send error in QFSInfo = %d", rc)); |
| 3016 | } else { /* decode response */ | 3361 | } else { /* decode response */ |
| 3017 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | 3362 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); |
| 3018 | 3363 | ||
| 3019 | if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */ | 3364 | if (rc || (pSMBr->ByteCount < 24)) |
| 3020 | rc = -EIO; /* bad smb */ | 3365 | rc = -EIO; /* bad smb */ |
| 3021 | else { | 3366 | else { |
| 3022 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); | 3367 | __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); |
| 3023 | cFYI(1, | ||
| 3024 | ("Decoding qfsinfo response. BCC: %d Offset %d", | ||
| 3025 | pSMBr->ByteCount, data_offset)); | ||
| 3026 | 3368 | ||
| 3027 | response_data = | 3369 | response_data = |
| 3028 | (FILE_SYSTEM_INFO | 3370 | (FILE_SYSTEM_INFO |
| @@ -3257,6 +3599,77 @@ QFSUnixRetry: | |||
| 3257 | return rc; | 3599 | return rc; |
| 3258 | } | 3600 | } |
| 3259 | 3601 | ||
| 3602 | int | ||
| 3603 | CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap) | ||
| 3604 | { | ||
| 3605 | /* level 0x200 SMB_SET_CIFS_UNIX_INFO */ | ||
| 3606 | TRANSACTION2_SETFSI_REQ *pSMB = NULL; | ||
| 3607 | TRANSACTION2_SETFSI_RSP *pSMBr = NULL; | ||
| 3608 | int rc = 0; | ||
| 3609 | int bytes_returned = 0; | ||
| 3610 | __u16 params, param_offset, offset, byte_count; | ||
| 3611 | |||
| 3612 | cFYI(1, ("In SETFSUnixInfo")); | ||
| 3613 | SETFSUnixRetry: | ||
| 3614 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, | ||
| 3615 | (void **) &pSMBr); | ||
| 3616 | if (rc) | ||
| 3617 | return rc; | ||
| 3618 | |||
| 3619 | params = 4; /* 2 bytes zero followed by info level. */ | ||
| 3620 | pSMB->MaxSetupCount = 0; | ||
| 3621 | pSMB->Reserved = 0; | ||
| 3622 | pSMB->Flags = 0; | ||
| 3623 | pSMB->Timeout = 0; | ||
| 3624 | pSMB->Reserved2 = 0; | ||
| 3625 | param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4; | ||
| 3626 | offset = param_offset + params; | ||
| 3627 | |||
| 3628 | pSMB->MaxParameterCount = cpu_to_le16(4); | ||
| 3629 | pSMB->MaxDataCount = cpu_to_le16(100); /* BB find exact max SMB PDU from sess structure BB */ | ||
| 3630 | pSMB->SetupCount = 1; | ||
| 3631 | pSMB->Reserved3 = 0; | ||
| 3632 | pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION); | ||
| 3633 | byte_count = 1 /* pad */ + params + 12; | ||
| 3634 | |||
| 3635 | pSMB->DataCount = cpu_to_le16(12); | ||
| 3636 | pSMB->ParameterCount = cpu_to_le16(params); | ||
| 3637 | pSMB->TotalDataCount = pSMB->DataCount; | ||
| 3638 | pSMB->TotalParameterCount = pSMB->ParameterCount; | ||
| 3639 | pSMB->ParameterOffset = cpu_to_le16(param_offset); | ||
| 3640 | pSMB->DataOffset = cpu_to_le16(offset); | ||
| 3641 | |||
| 3642 | /* Params. */ | ||
| 3643 | pSMB->FileNum = 0; | ||
| 3644 | pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO); | ||
| 3645 | |||
| 3646 | /* Data. */ | ||
| 3647 | pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION); | ||
| 3648 | pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION); | ||
| 3649 | pSMB->ClientUnixCap = cpu_to_le64(cap); | ||
| 3650 | |||
| 3651 | pSMB->hdr.smb_buf_length += byte_count; | ||
| 3652 | pSMB->ByteCount = cpu_to_le16(byte_count); | ||
| 3653 | |||
| 3654 | rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, | ||
| 3655 | (struct smb_hdr *) pSMBr, &bytes_returned, 0); | ||
| 3656 | if (rc) { | ||
| 3657 | cERROR(1, ("Send error in SETFSUnixInfo = %d", rc)); | ||
| 3658 | } else { /* decode response */ | ||
| 3659 | rc = validate_t2((struct smb_t2_rsp *)pSMBr); | ||
| 3660 | if (rc) { | ||
| 3661 | rc = -EIO; /* bad smb */ | ||
| 3662 | } | ||
| 3663 | } | ||
| 3664 | cifs_buf_release(pSMB); | ||
| 3665 | |||
| 3666 | if (rc == -EAGAIN) | ||
| 3667 | goto SETFSUnixRetry; | ||
| 3668 | |||
| 3669 | return rc; | ||
| 3670 | } | ||
| 3671 | |||
| 3672 | |||
| 3260 | 3673 | ||
| 3261 | int | 3674 | int |
| 3262 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, | 3675 | CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon, |
| @@ -3321,16 +3734,16 @@ QFSPosixRetry: | |||
| 3321 | le64_to_cpu(response_data->TotalBlocks); | 3734 | le64_to_cpu(response_data->TotalBlocks); |
| 3322 | FSData->f_bfree = | 3735 | FSData->f_bfree = |
| 3323 | le64_to_cpu(response_data->BlocksAvail); | 3736 | le64_to_cpu(response_data->BlocksAvail); |
| 3324 | if(response_data->UserBlocksAvail == -1) { | 3737 | if(response_data->UserBlocksAvail == cpu_to_le64(-1)) { |
| 3325 | FSData->f_bavail = FSData->f_bfree; | 3738 | FSData->f_bavail = FSData->f_bfree; |
| 3326 | } else { | 3739 | } else { |
| 3327 | FSData->f_bavail = | 3740 | FSData->f_bavail = |
| 3328 | le64_to_cpu(response_data->UserBlocksAvail); | 3741 | le64_to_cpu(response_data->UserBlocksAvail); |
| 3329 | } | 3742 | } |
| 3330 | if(response_data->TotalFileNodes != -1) | 3743 | if(response_data->TotalFileNodes != cpu_to_le64(-1)) |
| 3331 | FSData->f_files = | 3744 | FSData->f_files = |
| 3332 | le64_to_cpu(response_data->TotalFileNodes); | 3745 | le64_to_cpu(response_data->TotalFileNodes); |
| 3333 | if(response_data->FreeFileNodes != -1) | 3746 | if(response_data->FreeFileNodes != cpu_to_le64(-1)) |
| 3334 | FSData->f_ffree = | 3747 | FSData->f_ffree = |
| 3335 | le64_to_cpu(response_data->FreeFileNodes); | 3748 | le64_to_cpu(response_data->FreeFileNodes); |
| 3336 | } | 3749 | } |
| @@ -3376,7 +3789,7 @@ SetEOFRetry: | |||
| 3376 | PATH_MAX, nls_codepage, remap); | 3789 | PATH_MAX, nls_codepage, remap); |
| 3377 | name_len++; /* trailing null */ | 3790 | name_len++; /* trailing null */ |
| 3378 | name_len *= 2; | 3791 | name_len *= 2; |
| 3379 | } else { /* BB improve the check for buffer overruns BB */ | 3792 | } else { /* BB improve the check for buffer overruns BB */ |
| 3380 | name_len = strnlen(fileName, PATH_MAX); | 3793 | name_len = strnlen(fileName, PATH_MAX); |
| 3381 | name_len++; /* trailing null */ | 3794 | name_len++; /* trailing null */ |
| 3382 | strncpy(pSMB->FileName, fileName, name_len); | 3795 | strncpy(pSMB->FileName, fileName, name_len); |
| @@ -3384,7 +3797,7 @@ SetEOFRetry: | |||
| 3384 | params = 6 + name_len; | 3797 | params = 6 + name_len; |
| 3385 | data_count = sizeof (struct file_end_of_file_info); | 3798 | data_count = sizeof (struct file_end_of_file_info); |
| 3386 | pSMB->MaxParameterCount = cpu_to_le16(2); | 3799 | pSMB->MaxParameterCount = cpu_to_le16(2); |
| 3387 | pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */ | 3800 | pSMB->MaxDataCount = cpu_to_le16(4100); |
| 3388 | pSMB->MaxSetupCount = 0; | 3801 | pSMB->MaxSetupCount = 0; |
| 3389 | pSMB->Reserved = 0; | 3802 | pSMB->Reserved = 0; |
| 3390 | pSMB->Flags = 0; | 3803 | pSMB->Flags = 0; |
| @@ -3766,7 +4179,7 @@ setPermsRetry: | |||
| 3766 | PATH_MAX, nls_codepage, remap); | 4179 | PATH_MAX, nls_codepage, remap); |
| 3767 | name_len++; /* trailing null */ | 4180 | name_len++; /* trailing null */ |
| 3768 | name_len *= 2; | 4181 | name_len *= 2; |
| 3769 | } else { /* BB improve the check for buffer overruns BB */ | 4182 | } else { /* BB improve the check for buffer overruns BB */ |
| 3770 | name_len = strnlen(fileName, PATH_MAX); | 4183 | name_len = strnlen(fileName, PATH_MAX); |
| 3771 | name_len++; /* trailing null */ | 4184 | name_len++; /* trailing null */ |
| 3772 | strncpy(pSMB->FileName, fileName, name_len); | 4185 | strncpy(pSMB->FileName, fileName, name_len); |
| @@ -3839,12 +4252,14 @@ setPermsRetry: | |||
| 3839 | } | 4252 | } |
| 3840 | 4253 | ||
| 3841 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | 4254 | int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, |
| 3842 | const int notify_subdirs, const __u16 netfid, | 4255 | const int notify_subdirs, const __u16 netfid, |
| 3843 | __u32 filter, const struct nls_table *nls_codepage) | 4256 | __u32 filter, struct file * pfile, int multishot, |
| 4257 | const struct nls_table *nls_codepage) | ||
| 3844 | { | 4258 | { |
| 3845 | int rc = 0; | 4259 | int rc = 0; |
| 3846 | struct smb_com_transaction_change_notify_req * pSMB = NULL; | 4260 | struct smb_com_transaction_change_notify_req * pSMB = NULL; |
| 3847 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; | 4261 | struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; |
| 4262 | struct dir_notify_req *dnotify_req; | ||
| 3848 | int bytes_returned; | 4263 | int bytes_returned; |
| 3849 | 4264 | ||
| 3850 | cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); | 4265 | cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid)); |
| @@ -3877,6 +4292,28 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, | |||
| 3877 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); | 4292 | (struct smb_hdr *) pSMBr, &bytes_returned, -1); |
| 3878 | if (rc) { | 4293 | if (rc) { |
| 3879 | cFYI(1, ("Error in Notify = %d", rc)); | 4294 | cFYI(1, ("Error in Notify = %d", rc)); |
| 4295 | } else { | ||
| 4296 | /* Add file to outstanding requests */ | ||
| 4297 | /* BB change to kmem cache alloc */ | ||
| 4298 | dnotify_req = (struct dir_notify_req *) kmalloc( | ||
| 4299 | sizeof(struct dir_notify_req), | ||
| 4300 | GFP_KERNEL); | ||
| 4301 | if(dnotify_req) { | ||
| 4302 | dnotify_req->Pid = pSMB->hdr.Pid; | ||
| 4303 | dnotify_req->PidHigh = pSMB->hdr.PidHigh; | ||
| 4304 | dnotify_req->Mid = pSMB->hdr.Mid; | ||
| 4305 | dnotify_req->Tid = pSMB->hdr.Tid; | ||
| 4306 | dnotify_req->Uid = pSMB->hdr.Uid; | ||
| 4307 | dnotify_req->netfid = netfid; | ||
| 4308 | dnotify_req->pfile = pfile; | ||
| 4309 | dnotify_req->filter = filter; | ||
| 4310 | dnotify_req->multishot = multishot; | ||
| 4311 | spin_lock(&GlobalMid_Lock); | ||
| 4312 | list_add_tail(&dnotify_req->lhead, | ||
| 4313 | &GlobalDnotifyReqList); | ||
| 4314 | spin_unlock(&GlobalMid_Lock); | ||
| 4315 | } else | ||
| 4316 | rc = -ENOMEM; | ||
| 3880 | } | 4317 | } |
| 3881 | cifs_buf_release(pSMB); | 4318 | cifs_buf_release(pSMB); |
| 3882 | return rc; | 4319 | return rc; |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 47360156cc54..d74367a08d51 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -29,6 +29,8 @@ | |||
| 29 | #include <linux/utsname.h> | 29 | #include <linux/utsname.h> |
| 30 | #include <linux/mempool.h> | 30 | #include <linux/mempool.h> |
| 31 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
| 32 | #include <linux/completion.h> | ||
| 33 | #include <linux/pagevec.h> | ||
| 32 | #include <asm/uaccess.h> | 34 | #include <asm/uaccess.h> |
| 33 | #include <asm/processor.h> | 35 | #include <asm/processor.h> |
| 34 | #include "cifspdu.h" | 36 | #include "cifspdu.h" |
| @@ -44,6 +46,8 @@ | |||
| 44 | #define CIFS_PORT 445 | 46 | #define CIFS_PORT 445 |
| 45 | #define RFC1001_PORT 139 | 47 | #define RFC1001_PORT 139 |
| 46 | 48 | ||
| 49 | static DECLARE_COMPLETION(cifsd_complete); | ||
| 50 | |||
| 47 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, | 51 | extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, |
| 48 | unsigned char *p24); | 52 | unsigned char *p24); |
| 49 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, | 53 | extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, |
| @@ -60,6 +64,7 @@ struct smb_vol { | |||
| 60 | char *in6_addr; /* ipv6 address as human readable form of in6_addr */ | 64 | char *in6_addr; /* ipv6 address as human readable form of in6_addr */ |
| 61 | char *iocharset; /* local code page for mapping to and from Unicode */ | 65 | char *iocharset; /* local code page for mapping to and from Unicode */ |
| 62 | char source_rfc1001_name[16]; /* netbios name of client */ | 66 | char source_rfc1001_name[16]; /* netbios name of client */ |
| 67 | char target_rfc1001_name[16]; /* netbios name of server for Win9x/ME */ | ||
| 63 | uid_t linux_uid; | 68 | uid_t linux_uid; |
| 64 | gid_t linux_gid; | 69 | gid_t linux_gid; |
| 65 | mode_t file_mode; | 70 | mode_t file_mode; |
| @@ -74,6 +79,10 @@ struct smb_vol { | |||
| 74 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ | 79 | unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ |
| 75 | unsigned direct_io:1; | 80 | unsigned direct_io:1; |
| 76 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ | 81 | unsigned remap:1; /* set to remap seven reserved chars in filenames */ |
| 82 | unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ | ||
| 83 | unsigned sfu_emul:1; | ||
| 84 | unsigned nocase; /* request case insensitive filenames */ | ||
| 85 | unsigned nobrl; /* disable sending byte range locks to srv */ | ||
| 77 | unsigned int rsize; | 86 | unsigned int rsize; |
| 78 | unsigned int wsize; | 87 | unsigned int wsize; |
| 79 | unsigned int sockopt; | 88 | unsigned int sockopt; |
| @@ -82,7 +91,8 @@ struct smb_vol { | |||
| 82 | 91 | ||
| 83 | static int ipv4_connect(struct sockaddr_in *psin_server, | 92 | static int ipv4_connect(struct sockaddr_in *psin_server, |
| 84 | struct socket **csocket, | 93 | struct socket **csocket, |
| 85 | char * netb_name); | 94 | char * netb_name, |
| 95 | char * server_netb_name); | ||
| 86 | static int ipv6_connect(struct sockaddr_in6 *psin_server, | 96 | static int ipv6_connect(struct sockaddr_in6 *psin_server, |
| 87 | struct socket **csocket); | 97 | struct socket **csocket); |
| 88 | 98 | ||
| @@ -175,9 +185,11 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 175 | } else { | 185 | } else { |
| 176 | rc = ipv4_connect(&server->addr.sockAddr, | 186 | rc = ipv4_connect(&server->addr.sockAddr, |
| 177 | &server->ssocket, | 187 | &server->ssocket, |
| 178 | server->workstation_RFC1001_name); | 188 | server->workstation_RFC1001_name, |
| 189 | server->server_RFC1001_name); | ||
| 179 | } | 190 | } |
| 180 | if(rc) { | 191 | if(rc) { |
| 192 | cFYI(1,("reconnect error %d",rc)); | ||
| 181 | msleep(3000); | 193 | msleep(3000); |
| 182 | } else { | 194 | } else { |
| 183 | atomic_inc(&tcpSesReconnectCount); | 195 | atomic_inc(&tcpSesReconnectCount); |
| @@ -293,12 +305,12 @@ static int coalesce_t2(struct smb_hdr * psecond, struct smb_hdr *pTargetSMB) | |||
| 293 | byte_count += total_in_buf2; | 305 | byte_count += total_in_buf2; |
| 294 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); | 306 | BCC_LE(pTargetSMB) = cpu_to_le16(byte_count); |
| 295 | 307 | ||
| 296 | byte_count = be32_to_cpu(pTargetSMB->smb_buf_length); | 308 | byte_count = pTargetSMB->smb_buf_length; |
| 297 | byte_count += total_in_buf2; | 309 | byte_count += total_in_buf2; |
| 298 | 310 | ||
| 299 | /* BB also add check that we are not beyond maximum buffer size */ | 311 | /* BB also add check that we are not beyond maximum buffer size */ |
| 300 | 312 | ||
| 301 | pTargetSMB->smb_buf_length = cpu_to_be32(byte_count); | 313 | pTargetSMB->smb_buf_length = byte_count; |
| 302 | 314 | ||
| 303 | if(remaining == total_in_buf2) { | 315 | if(remaining == total_in_buf2) { |
| 304 | cFYI(1,("found the last secondary response")); | 316 | cFYI(1,("found the last secondary response")); |
| @@ -323,7 +335,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 323 | struct cifsSesInfo *ses; | 335 | struct cifsSesInfo *ses; |
| 324 | struct task_struct *task_to_wake = NULL; | 336 | struct task_struct *task_to_wake = NULL; |
| 325 | struct mid_q_entry *mid_entry; | 337 | struct mid_q_entry *mid_entry; |
| 326 | char *temp; | 338 | char temp; |
| 327 | int isLargeBuf = FALSE; | 339 | int isLargeBuf = FALSE; |
| 328 | int isMultiRsp; | 340 | int isMultiRsp; |
| 329 | int reconnect; | 341 | int reconnect; |
| @@ -337,6 +349,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 337 | atomic_inc(&tcpSesAllocCount); | 349 | atomic_inc(&tcpSesAllocCount); |
| 338 | length = tcpSesAllocCount.counter; | 350 | length = tcpSesAllocCount.counter; |
| 339 | write_unlock(&GlobalSMBSeslock); | 351 | write_unlock(&GlobalSMBSeslock); |
| 352 | complete(&cifsd_complete); | ||
| 340 | if(length > 1) { | 353 | if(length > 1) { |
| 341 | mempool_resize(cifs_req_poolp, | 354 | mempool_resize(cifs_req_poolp, |
| 342 | length + cifs_min_rcv, | 355 | length + cifs_min_rcv, |
| @@ -424,22 +437,32 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 424 | continue; | 437 | continue; |
| 425 | } | 438 | } |
| 426 | 439 | ||
| 427 | /* the right amount was read from socket - 4 bytes */ | 440 | /* The right amount was read from socket - 4 bytes */ |
| 441 | /* so we can now interpret the length field */ | ||
| 442 | |||
| 443 | /* the first byte big endian of the length field, | ||
| 444 | is actually not part of the length but the type | ||
| 445 | with the most common, zero, as regular data */ | ||
| 446 | temp = *((char *) smb_buffer); | ||
| 428 | 447 | ||
| 448 | /* Note that FC 1001 length is big endian on the wire, | ||
| 449 | but we convert it here so it is always manipulated | ||
| 450 | as host byte order */ | ||
| 429 | pdu_length = ntohl(smb_buffer->smb_buf_length); | 451 | pdu_length = ntohl(smb_buffer->smb_buf_length); |
| 430 | cFYI(1,("rfc1002 length(big endian)0x%x)", pdu_length+4)); | 452 | smb_buffer->smb_buf_length = pdu_length; |
| 453 | |||
| 454 | cFYI(1,("rfc1002 length 0x%x)", pdu_length+4)); | ||
| 431 | 455 | ||
| 432 | temp = (char *) smb_buffer; | 456 | if (temp == (char) RFC1002_SESSION_KEEP_ALIVE) { |
| 433 | if (temp[0] == (char) RFC1002_SESSION_KEEP_ALIVE) { | ||
| 434 | continue; | 457 | continue; |
| 435 | } else if (temp[0] == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { | 458 | } else if (temp == (char)RFC1002_POSITIVE_SESSION_RESPONSE) { |
| 436 | cFYI(1,("Good RFC 1002 session rsp")); | 459 | cFYI(1,("Good RFC 1002 session rsp")); |
| 437 | continue; | 460 | continue; |
| 438 | } else if (temp[0] == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { | 461 | } else if (temp == (char)RFC1002_NEGATIVE_SESSION_RESPONSE) { |
| 439 | /* we get this from Windows 98 instead of | 462 | /* we get this from Windows 98 instead of |
| 440 | an error on SMB negprot response */ | 463 | an error on SMB negprot response */ |
| 441 | cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", | 464 | cFYI(1,("Negative RFC1002 Session Response Error 0x%x)", |
| 442 | temp[4])); | 465 | pdu_length)); |
| 443 | if(server->tcpStatus == CifsNew) { | 466 | if(server->tcpStatus == CifsNew) { |
| 444 | /* if nack on negprot (rather than | 467 | /* if nack on negprot (rather than |
| 445 | ret of smb negprot error) reconnecting | 468 | ret of smb negprot error) reconnecting |
| @@ -461,9 +484,10 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 461 | wake_up(&server->response_q); | 484 | wake_up(&server->response_q); |
| 462 | continue; | 485 | continue; |
| 463 | } | 486 | } |
| 464 | } else if (temp[0] != (char) 0) { | 487 | } else if (temp != (char) 0) { |
| 465 | cERROR(1,("Unknown RFC 1002 frame")); | 488 | cERROR(1,("Unknown RFC 1002 frame")); |
| 466 | cifs_dump_mem(" Received Data: ", temp, length); | 489 | cifs_dump_mem(" Received Data: ", (char *)smb_buffer, |
| 490 | length); | ||
| 467 | cifs_reconnect(server); | 491 | cifs_reconnect(server); |
| 468 | csocket = server->ssocket; | 492 | csocket = server->ssocket; |
| 469 | continue; | 493 | continue; |
| @@ -533,7 +557,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 533 | 557 | ||
| 534 | dump_smb(smb_buffer, length); | 558 | dump_smb(smb_buffer, length); |
| 535 | if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { | 559 | if (checkSMB (smb_buffer, smb_buffer->Mid, total_read+4)) { |
| 536 | cERROR(1, ("Bad SMB Received ")); | 560 | cifs_dump_mem("Bad SMB: ", smb_buffer, 48); |
| 537 | continue; | 561 | continue; |
| 538 | } | 562 | } |
| 539 | 563 | ||
| @@ -581,6 +605,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) | |||
| 581 | multi_t2_fnd: | 605 | multi_t2_fnd: |
| 582 | task_to_wake = mid_entry->tsk; | 606 | task_to_wake = mid_entry->tsk; |
| 583 | mid_entry->midState = MID_RESPONSE_RECEIVED; | 607 | mid_entry->midState = MID_RESPONSE_RECEIVED; |
| 608 | #ifdef CONFIG_CIFS_STATS2 | ||
| 609 | mid_entry->when_received = jiffies; | ||
| 610 | #endif | ||
| 584 | break; | 611 | break; |
| 585 | } | 612 | } |
| 586 | } | 613 | } |
| @@ -598,7 +625,8 @@ multi_t2_fnd: | |||
| 598 | } else if ((is_valid_oplock_break(smb_buffer) == FALSE) | 625 | } else if ((is_valid_oplock_break(smb_buffer) == FALSE) |
| 599 | && (isMultiRsp == FALSE)) { | 626 | && (isMultiRsp == FALSE)) { |
| 600 | cERROR(1, ("No task to wake, unknown frame rcvd!")); | 627 | cERROR(1, ("No task to wake, unknown frame rcvd!")); |
| 601 | cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)); | 628 | cifs_dump_mem("Received Data is: ",(char *)smb_buffer, |
| 629 | sizeof(struct smb_hdr)); | ||
| 602 | } | 630 | } |
| 603 | } /* end while !EXITING */ | 631 | } /* end while !EXITING */ |
| 604 | 632 | ||
| @@ -676,7 +704,7 @@ multi_t2_fnd: | |||
| 676 | msleep(125); | 704 | msleep(125); |
| 677 | } | 705 | } |
| 678 | 706 | ||
| 679 | if (list_empty(&server->pending_mid_q)) { | 707 | if (!list_empty(&server->pending_mid_q)) { |
| 680 | /* mpx threads have not exited yet give them | 708 | /* mpx threads have not exited yet give them |
| 681 | at least the smb send timeout time for long ops */ | 709 | at least the smb send timeout time for long ops */ |
| 682 | /* due to delays on oplock break requests, we need | 710 | /* due to delays on oplock break requests, we need |
| @@ -713,7 +741,7 @@ multi_t2_fnd: | |||
| 713 | GFP_KERNEL); | 741 | GFP_KERNEL); |
| 714 | } | 742 | } |
| 715 | 743 | ||
| 716 | msleep(250); | 744 | complete_and_exit(&cifsd_complete, 0); |
| 717 | return 0; | 745 | return 0; |
| 718 | } | 746 | } |
| 719 | 747 | ||
| @@ -737,7 +765,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 737 | toupper(system_utsname.nodename[i]); | 765 | toupper(system_utsname.nodename[i]); |
| 738 | } | 766 | } |
| 739 | vol->source_rfc1001_name[15] = 0; | 767 | vol->source_rfc1001_name[15] = 0; |
| 740 | 768 | /* null target name indicates to use *SMBSERVR default called name | |
| 769 | if we end up sending RFC1001 session initialize */ | ||
| 770 | vol->target_rfc1001_name[0] = 0; | ||
| 741 | vol->linux_uid = current->uid; /* current->euid instead? */ | 771 | vol->linux_uid = current->uid; /* current->euid instead? */ |
| 742 | vol->linux_gid = current->gid; | 772 | vol->linux_gid = current->gid; |
| 743 | vol->dir_mode = S_IRWXUGO; | 773 | vol->dir_mode = S_IRWXUGO; |
| @@ -747,6 +777,9 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 747 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ | 777 | /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ |
| 748 | vol->rw = TRUE; | 778 | vol->rw = TRUE; |
| 749 | 779 | ||
| 780 | /* default is always to request posix paths. */ | ||
| 781 | vol->posix_paths = 1; | ||
| 782 | |||
| 750 | if (!options) | 783 | if (!options) |
| 751 | return 1; | 784 | return 1; |
| 752 | 785 | ||
| @@ -987,7 +1020,31 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 987 | /* The string has 16th byte zero still from | 1020 | /* The string has 16th byte zero still from |
| 988 | set at top of the function */ | 1021 | set at top of the function */ |
| 989 | if((i==15) && (value[i] != 0)) | 1022 | if((i==15) && (value[i] != 0)) |
| 990 | printk(KERN_WARNING "CIFS: netbiosname longer than 15 and was truncated.\n"); | 1023 | printk(KERN_WARNING "CIFS: netbiosname longer than 15 truncated.\n"); |
| 1024 | } | ||
| 1025 | } else if (strnicmp(data, "servern", 7) == 0) { | ||
| 1026 | /* servernetbiosname specified override *SMBSERVER */ | ||
| 1027 | if (!value || !*value || (*value == ' ')) { | ||
| 1028 | cFYI(1,("empty server netbiosname specified")); | ||
| 1029 | } else { | ||
| 1030 | /* last byte, type, is 0x20 for servr type */ | ||
| 1031 | memset(vol->target_rfc1001_name,0x20,16); | ||
| 1032 | |||
| 1033 | for(i=0;i<15;i++) { | ||
| 1034 | /* BB are there cases in which a comma can be | ||
| 1035 | valid in this workstation netbios name (and need | ||
| 1036 | special handling)? */ | ||
| 1037 | |||
| 1038 | /* user or mount helper must uppercase netbiosname */ | ||
| 1039 | if (value[i]==0) | ||
| 1040 | break; | ||
| 1041 | else | ||
| 1042 | vol->target_rfc1001_name[i] = value[i]; | ||
| 1043 | } | ||
| 1044 | /* The string has 16th byte zero still from | ||
| 1045 | set at top of the function */ | ||
| 1046 | if((i==15) && (value[i] != 0)) | ||
| 1047 | printk(KERN_WARNING "CIFS: server netbiosname longer than 15 truncated.\n"); | ||
| 991 | } | 1048 | } |
| 992 | } else if (strnicmp(data, "credentials", 4) == 0) { | 1049 | } else if (strnicmp(data, "credentials", 4) == 0) { |
| 993 | /* ignore */ | 1050 | /* ignore */ |
| @@ -1025,6 +1082,27 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) | |||
| 1025 | vol->remap = 1; | 1082 | vol->remap = 1; |
| 1026 | } else if (strnicmp(data, "nomapchars", 10) == 0) { | 1083 | } else if (strnicmp(data, "nomapchars", 10) == 0) { |
| 1027 | vol->remap = 0; | 1084 | vol->remap = 0; |
| 1085 | } else if (strnicmp(data, "sfu", 3) == 0) { | ||
| 1086 | vol->sfu_emul = 1; | ||
| 1087 | } else if (strnicmp(data, "nosfu", 5) == 0) { | ||
| 1088 | vol->sfu_emul = 0; | ||
| 1089 | } else if (strnicmp(data, "posixpaths", 10) == 0) { | ||
| 1090 | vol->posix_paths = 1; | ||
| 1091 | } else if (strnicmp(data, "noposixpaths", 12) == 0) { | ||
| 1092 | vol->posix_paths = 0; | ||
| 1093 | } else if ((strnicmp(data, "nocase", 6) == 0) || | ||
| 1094 | (strnicmp(data, "ignorecase", 10) == 0)) { | ||
| 1095 | vol->nocase = 1; | ||
| 1096 | } else if (strnicmp(data, "brl", 3) == 0) { | ||
| 1097 | vol->nobrl = 0; | ||
| 1098 | } else if ((strnicmp(data, "nobrl", 5) == 0) || | ||
| 1099 | (strnicmp(data, "nolock", 6) == 0)) { | ||
| 1100 | vol->nobrl = 1; | ||
| 1101 | /* turn off mandatory locking in mode | ||
| 1102 | if remote locking is turned off since the | ||
| 1103 | local vfs will do advisory */ | ||
| 1104 | if(vol->file_mode == (S_IALLUGO & ~(S_ISUID | S_IXGRP))) | ||
| 1105 | vol->file_mode = S_IALLUGO; | ||
| 1028 | } else if (strnicmp(data, "setuids", 7) == 0) { | 1106 | } else if (strnicmp(data, "setuids", 7) == 0) { |
| 1029 | vol->setuids = 1; | 1107 | vol->setuids = 1; |
| 1030 | } else if (strnicmp(data, "nosetuids", 9) == 0) { | 1108 | } else if (strnicmp(data, "nosetuids", 9) == 0) { |
| @@ -1244,7 +1322,7 @@ static void rfc1002mangle(char * target,char * source, unsigned int length) | |||
| 1244 | 1322 | ||
| 1245 | static int | 1323 | static int |
| 1246 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | 1324 | ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, |
| 1247 | char * netbios_name) | 1325 | char * netbios_name, char * target_name) |
| 1248 | { | 1326 | { |
| 1249 | int rc = 0; | 1327 | int rc = 0; |
| 1250 | int connected = 0; | 1328 | int connected = 0; |
| @@ -1309,10 +1387,16 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
| 1309 | /* Eventually check for other socket options to change from | 1387 | /* Eventually check for other socket options to change from |
| 1310 | the default. sock_setsockopt not used because it expects | 1388 | the default. sock_setsockopt not used because it expects |
| 1311 | user space buffer */ | 1389 | user space buffer */ |
| 1390 | cFYI(1,("sndbuf %d rcvbuf %d rcvtimeo 0x%lx",(*csocket)->sk->sk_sndbuf, | ||
| 1391 | (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); | ||
| 1312 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; | 1392 | (*csocket)->sk->sk_rcvtimeo = 7 * HZ; |
| 1393 | /* make the bufsizes depend on wsize/rsize and max requests */ | ||
| 1394 | if((*csocket)->sk->sk_sndbuf < (200 * 1024)) | ||
| 1395 | (*csocket)->sk->sk_sndbuf = 200 * 1024; | ||
| 1396 | if((*csocket)->sk->sk_rcvbuf < (140 * 1024)) | ||
| 1397 | (*csocket)->sk->sk_rcvbuf = 140 * 1024; | ||
| 1313 | 1398 | ||
| 1314 | /* send RFC1001 sessinit */ | 1399 | /* send RFC1001 sessinit */ |
| 1315 | |||
| 1316 | if(psin_server->sin_port == htons(RFC1001_PORT)) { | 1400 | if(psin_server->sin_port == htons(RFC1001_PORT)) { |
| 1317 | /* some servers require RFC1001 sessinit before sending | 1401 | /* some servers require RFC1001 sessinit before sending |
| 1318 | negprot - BB check reconnection in case where second | 1402 | negprot - BB check reconnection in case where second |
| @@ -1322,8 +1406,14 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, | |||
| 1322 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); | 1406 | ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet), GFP_KERNEL); |
| 1323 | if(ses_init_buf) { | 1407 | if(ses_init_buf) { |
| 1324 | ses_init_buf->trailer.session_req.called_len = 32; | 1408 | ses_init_buf->trailer.session_req.called_len = 32; |
| 1325 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | 1409 | if(target_name && (target_name[0] != 0)) { |
| 1326 | DEFAULT_CIFS_CALLED_NAME,16); | 1410 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, |
| 1411 | target_name, 16); | ||
| 1412 | } else { | ||
| 1413 | rfc1002mangle(ses_init_buf->trailer.session_req.called_name, | ||
| 1414 | DEFAULT_CIFS_CALLED_NAME,16); | ||
| 1415 | } | ||
| 1416 | |||
| 1327 | ses_init_buf->trailer.session_req.calling_len = 32; | 1417 | ses_init_buf->trailer.session_req.calling_len = 32; |
| 1328 | /* calling name ends in null (byte 16) from old smb | 1418 | /* calling name ends in null (byte 16) from old smb |
| 1329 | convention. */ | 1419 | convention. */ |
| @@ -1556,7 +1646,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1556 | sin_server.sin_port = htons(volume_info.port); | 1646 | sin_server.sin_port = htons(volume_info.port); |
| 1557 | else | 1647 | else |
| 1558 | sin_server.sin_port = 0; | 1648 | sin_server.sin_port = 0; |
| 1559 | rc = ipv4_connect(&sin_server,&csocket,volume_info.source_rfc1001_name); | 1649 | rc = ipv4_connect(&sin_server,&csocket, |
| 1650 | volume_info.source_rfc1001_name, | ||
| 1651 | volume_info.target_rfc1001_name); | ||
| 1560 | if (rc < 0) { | 1652 | if (rc < 0) { |
| 1561 | cERROR(1, | 1653 | cERROR(1, |
| 1562 | ("Error connecting to IPv4 socket. Aborting operation")); | 1654 | ("Error connecting to IPv4 socket. Aborting operation")); |
| @@ -1606,9 +1698,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1606 | kfree(volume_info.password); | 1698 | kfree(volume_info.password); |
| 1607 | FreeXid(xid); | 1699 | FreeXid(xid); |
| 1608 | return rc; | 1700 | return rc; |
| 1609 | } else | 1701 | } |
| 1610 | rc = 0; | 1702 | wait_for_completion(&cifsd_complete); |
| 1703 | rc = 0; | ||
| 1611 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); | 1704 | memcpy(srvTcp->workstation_RFC1001_name, volume_info.source_rfc1001_name,16); |
| 1705 | memcpy(srvTcp->server_RFC1001_name, volume_info.target_rfc1001_name,16); | ||
| 1612 | srvTcp->sequence_number = 0; | 1706 | srvTcp->sequence_number = 0; |
| 1613 | } | 1707 | } |
| 1614 | } | 1708 | } |
| @@ -1653,17 +1747,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1653 | 1747 | ||
| 1654 | /* search for existing tcon to this server share */ | 1748 | /* search for existing tcon to this server share */ |
| 1655 | if (!rc) { | 1749 | if (!rc) { |
| 1656 | if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) | 1750 | if(volume_info.rsize > CIFSMaxBufSize) { |
| 1751 | cERROR(1,("rsize %d too large, using MaxBufSize", | ||
| 1752 | volume_info.rsize)); | ||
| 1753 | cifs_sb->rsize = CIFSMaxBufSize; | ||
| 1754 | } else if((volume_info.rsize) && (volume_info.rsize <= CIFSMaxBufSize)) | ||
| 1657 | cifs_sb->rsize = volume_info.rsize; | 1755 | cifs_sb->rsize = volume_info.rsize; |
| 1658 | else | 1756 | else /* default */ |
| 1659 | cifs_sb->rsize = srvTcp->maxBuf - MAX_CIFS_HDR_SIZE; /* default */ | 1757 | cifs_sb->rsize = CIFSMaxBufSize; |
| 1660 | if((volume_info.wsize) && (volume_info.wsize <= CIFSMaxBufSize)) | 1758 | |
| 1759 | if(volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { | ||
| 1760 | cERROR(1,("wsize %d too large using 4096 instead", | ||
| 1761 | volume_info.wsize)); | ||
| 1762 | cifs_sb->wsize = 4096; | ||
| 1763 | } else if(volume_info.wsize) | ||
| 1661 | cifs_sb->wsize = volume_info.wsize; | 1764 | cifs_sb->wsize = volume_info.wsize; |
| 1662 | else | 1765 | else |
| 1663 | cifs_sb->wsize = CIFSMaxBufSize; /* default */ | 1766 | cifs_sb->wsize = CIFSMaxBufSize; /* default */ |
| 1664 | if(cifs_sb->rsize < PAGE_CACHE_SIZE) { | 1767 | if(cifs_sb->rsize < PAGE_CACHE_SIZE) { |
| 1665 | cifs_sb->rsize = PAGE_CACHE_SIZE; | 1768 | cifs_sb->rsize = PAGE_CACHE_SIZE; |
| 1666 | cERROR(1,("Attempt to set readsize for mount to less than one page (4096)")); | 1769 | /* Windows ME does this */ |
| 1770 | cFYI(1,("Attempt to set readsize for mount to less than one page (4096)")); | ||
| 1667 | } | 1771 | } |
| 1668 | cifs_sb->mnt_uid = volume_info.linux_uid; | 1772 | cifs_sb->mnt_uid = volume_info.linux_uid; |
| 1669 | cifs_sb->mnt_gid = volume_info.linux_gid; | 1773 | cifs_sb->mnt_gid = volume_info.linux_gid; |
| @@ -1681,8 +1785,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1681 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; | 1785 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; |
| 1682 | if(volume_info.no_xattr) | 1786 | if(volume_info.no_xattr) |
| 1683 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; | 1787 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; |
| 1788 | if(volume_info.sfu_emul) | ||
| 1789 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; | ||
| 1790 | if(volume_info.nobrl) | ||
| 1791 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; | ||
| 1792 | |||
| 1684 | if(volume_info.direct_io) { | 1793 | if(volume_info.direct_io) { |
| 1685 | cERROR(1,("mounting share using direct i/o")); | 1794 | cFYI(1,("mounting share using direct i/o")); |
| 1686 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 1795 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
| 1687 | } | 1796 | } |
| 1688 | 1797 | ||
| @@ -1696,6 +1805,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1696 | to the same server share the last value passed in | 1805 | to the same server share the last value passed in |
| 1697 | for the retry flag is used */ | 1806 | for the retry flag is used */ |
| 1698 | tcon->retry = volume_info.retry; | 1807 | tcon->retry = volume_info.retry; |
| 1808 | tcon->nocase = volume_info.nocase; | ||
| 1699 | } else { | 1809 | } else { |
| 1700 | tcon = tconInfoAlloc(); | 1810 | tcon = tconInfoAlloc(); |
| 1701 | if (tcon == NULL) | 1811 | if (tcon == NULL) |
| @@ -1724,6 +1834,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1724 | if (!rc) { | 1834 | if (!rc) { |
| 1725 | atomic_inc(&pSesInfo->inUse); | 1835 | atomic_inc(&pSesInfo->inUse); |
| 1726 | tcon->retry = volume_info.retry; | 1836 | tcon->retry = volume_info.retry; |
| 1837 | tcon->nocase = volume_info.nocase; | ||
| 1727 | } | 1838 | } |
| 1728 | } | 1839 | } |
| 1729 | } | 1840 | } |
| @@ -1745,8 +1856,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1745 | spin_lock(&GlobalMid_Lock); | 1856 | spin_lock(&GlobalMid_Lock); |
| 1746 | srvTcp->tcpStatus = CifsExiting; | 1857 | srvTcp->tcpStatus = CifsExiting; |
| 1747 | spin_unlock(&GlobalMid_Lock); | 1858 | spin_unlock(&GlobalMid_Lock); |
| 1748 | if(srvTcp->tsk) | 1859 | if(srvTcp->tsk) { |
| 1749 | send_sig(SIGKILL,srvTcp->tsk,1); | 1860 | send_sig(SIGKILL,srvTcp->tsk,1); |
| 1861 | wait_for_completion(&cifsd_complete); | ||
| 1862 | } | ||
| 1750 | } | 1863 | } |
| 1751 | /* If find_unc succeeded then rc == 0 so we can not end */ | 1864 | /* If find_unc succeeded then rc == 0 so we can not end */ |
| 1752 | if (tcon) /* up accidently freeing someone elses tcon struct */ | 1865 | if (tcon) /* up accidently freeing someone elses tcon struct */ |
| @@ -1759,8 +1872,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1759 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); | 1872 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); |
| 1760 | /* if the socketUseCount is now zero */ | 1873 | /* if the socketUseCount is now zero */ |
| 1761 | if((temp_rc == -ESHUTDOWN) && | 1874 | if((temp_rc == -ESHUTDOWN) && |
| 1762 | (pSesInfo->server->tsk)) | 1875 | (pSesInfo->server->tsk)) { |
| 1763 | send_sig(SIGKILL,pSesInfo->server->tsk,1); | 1876 | send_sig(SIGKILL,pSesInfo->server->tsk,1); |
| 1877 | wait_for_completion(&cifsd_complete); | ||
| 1878 | } | ||
| 1764 | } else | 1879 | } else |
| 1765 | cFYI(1, ("No session or bad tcon")); | 1880 | cFYI(1, ("No session or bad tcon")); |
| 1766 | sesInfoFree(pSesInfo); | 1881 | sesInfoFree(pSesInfo); |
| @@ -1783,8 +1898,27 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1783 | cFYI(1,("server negotiated posix acl support")); | 1898 | cFYI(1,("server negotiated posix acl support")); |
| 1784 | sb->s_flags |= MS_POSIXACL; | 1899 | sb->s_flags |= MS_POSIXACL; |
| 1785 | } | 1900 | } |
| 1901 | |||
| 1902 | /* Try and negotiate POSIX pathnames if we can. */ | ||
| 1903 | if (volume_info.posix_paths && (CIFS_UNIX_POSIX_PATHNAMES_CAP & | ||
| 1904 | le64_to_cpu(tcon->fsUnixInfo.Capability))) { | ||
| 1905 | if (!CIFSSMBSetFSUnixInfo(xid, tcon, CIFS_UNIX_POSIX_PATHNAMES_CAP)) { | ||
| 1906 | cFYI(1,("negotiated posix pathnames support")); | ||
| 1907 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_POSIX_PATHS; | ||
| 1908 | } else { | ||
| 1909 | cFYI(1,("posix pathnames support requested but not supported")); | ||
| 1910 | } | ||
| 1911 | } | ||
| 1786 | } | 1912 | } |
| 1787 | } | 1913 | } |
| 1914 | if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) | ||
| 1915 | cifs_sb->wsize = min(cifs_sb->wsize, | ||
| 1916 | (tcon->ses->server->maxBuf - | ||
| 1917 | MAX_CIFS_HDR_SIZE)); | ||
| 1918 | if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) | ||
| 1919 | cifs_sb->rsize = min(cifs_sb->rsize, | ||
| 1920 | (tcon->ses->server->maxBuf - | ||
| 1921 | MAX_CIFS_HDR_SIZE)); | ||
| 1788 | } | 1922 | } |
| 1789 | 1923 | ||
| 1790 | /* volume_info.password is freed above when existing session found | 1924 | /* volume_info.password is freed above when existing session found |
| @@ -1832,6 +1966,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 1832 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 1966 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
| 1833 | NULL /* no tCon exists yet */ , 13 /* wct */ ); | 1967 | NULL /* no tCon exists yet */ , 13 /* wct */ ); |
| 1834 | 1968 | ||
| 1969 | smb_buffer->Mid = GetNextMid(ses->server); | ||
| 1835 | pSMB->req_no_secext.AndXCommand = 0xFF; | 1970 | pSMB->req_no_secext.AndXCommand = 0xFF; |
| 1836 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | 1971 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); |
| 1837 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | 1972 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); |
| @@ -2107,6 +2242,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2107 | /* send SMBsessionSetup here */ | 2242 | /* send SMBsessionSetup here */ |
| 2108 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 2243 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
| 2109 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | 2244 | NULL /* no tCon exists yet */ , 12 /* wct */ ); |
| 2245 | |||
| 2246 | smb_buffer->Mid = GetNextMid(ses->server); | ||
| 2110 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 2247 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| 2111 | pSMB->req.AndXCommand = 0xFF; | 2248 | pSMB->req.AndXCommand = 0xFF; |
| 2112 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | 2249 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); |
| @@ -2373,6 +2510,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | |||
| 2373 | /* send SMBsessionSetup here */ | 2510 | /* send SMBsessionSetup here */ |
| 2374 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 2511 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
| 2375 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | 2512 | NULL /* no tCon exists yet */ , 12 /* wct */ ); |
| 2513 | |||
| 2514 | smb_buffer->Mid = GetNextMid(ses->server); | ||
| 2376 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 2515 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| 2377 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | 2516 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); |
| 2378 | 2517 | ||
| @@ -2715,6 +2854,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | |||
| 2715 | /* send SMBsessionSetup here */ | 2854 | /* send SMBsessionSetup here */ |
| 2716 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | 2855 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, |
| 2717 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | 2856 | NULL /* no tCon exists yet */ , 12 /* wct */ ); |
| 2857 | |||
| 2858 | smb_buffer->Mid = GetNextMid(ses->server); | ||
| 2718 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | 2859 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); |
| 2719 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | 2860 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; |
| 2720 | pSMB->req.AndXCommand = 0xFF; | 2861 | pSMB->req.AndXCommand = 0xFF; |
| @@ -3086,6 +3227,8 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3086 | 3227 | ||
| 3087 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, | 3228 | header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, |
| 3088 | NULL /*no tid */ , 4 /*wct */ ); | 3229 | NULL /*no tid */ , 4 /*wct */ ); |
| 3230 | |||
| 3231 | smb_buffer->Mid = GetNextMid(ses->server); | ||
| 3089 | smb_buffer->Uid = ses->Suid; | 3232 | smb_buffer->Uid = ses->Suid; |
| 3090 | pSMB = (TCONX_REQ *) smb_buffer; | 3233 | pSMB = (TCONX_REQ *) smb_buffer; |
| 3091 | pSMBr = (TCONX_RSP *) smb_buffer_response; | 3234 | pSMBr = (TCONX_RSP *) smb_buffer_response; |
| @@ -3207,8 +3350,10 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
| 3207 | return 0; | 3350 | return 0; |
| 3208 | } else if (rc == -ESHUTDOWN) { | 3351 | } else if (rc == -ESHUTDOWN) { |
| 3209 | cFYI(1,("Waking up socket by sending it signal")); | 3352 | cFYI(1,("Waking up socket by sending it signal")); |
| 3210 | if(cifsd_task) | 3353 | if(cifsd_task) { |
| 3211 | send_sig(SIGKILL,cifsd_task,1); | 3354 | send_sig(SIGKILL,cifsd_task,1); |
| 3355 | wait_for_completion(&cifsd_complete); | ||
| 3356 | } | ||
| 3212 | rc = 0; | 3357 | rc = 0; |
| 3213 | } /* else - we have an smb session | 3358 | } /* else - we have an smb session |
| 3214 | left on this socket do not kill cifsd */ | 3359 | left on this socket do not kill cifsd */ |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d335269bd91c..8dfe717a332a 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
| @@ -48,6 +48,7 @@ build_path_from_dentry(struct dentry *direntry) | |||
| 48 | struct dentry *temp; | 48 | struct dentry *temp; |
| 49 | int namelen = 0; | 49 | int namelen = 0; |
| 50 | char *full_path; | 50 | char *full_path; |
| 51 | char dirsep = CIFS_DIR_SEP(CIFS_SB(direntry->d_sb)); | ||
| 51 | 52 | ||
| 52 | if(direntry == NULL) | 53 | if(direntry == NULL) |
| 53 | return NULL; /* not much we can do if dentry is freed and | 54 | return NULL; /* not much we can do if dentry is freed and |
| @@ -74,7 +75,7 @@ cifs_bp_rename_retry: | |||
| 74 | if (namelen < 0) { | 75 | if (namelen < 0) { |
| 75 | break; | 76 | break; |
| 76 | } else { | 77 | } else { |
| 77 | full_path[namelen] = '\\'; | 78 | full_path[namelen] = dirsep; |
| 78 | strncpy(full_path + namelen + 1, temp->d_name.name, | 79 | strncpy(full_path + namelen + 1, temp->d_name.name, |
| 79 | temp->d_name.len); | 80 | temp->d_name.len); |
| 80 | cFYI(0, (" name: %s ", full_path + namelen)); | 81 | cFYI(0, (" name: %s ", full_path + namelen)); |
| @@ -183,6 +184,13 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 183 | desiredAccess, CREATE_NOT_DIR, | 184 | desiredAccess, CREATE_NOT_DIR, |
| 184 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | 185 | &fileHandle, &oplock, buf, cifs_sb->local_nls, |
| 185 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 186 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 187 | if(rc == -EIO) { | ||
| 188 | /* old server, retry the open legacy style */ | ||
| 189 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | ||
| 190 | desiredAccess, CREATE_NOT_DIR, | ||
| 191 | &fileHandle, &oplock, buf, cifs_sb->local_nls, | ||
| 192 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 193 | } | ||
| 186 | if (rc) { | 194 | if (rc) { |
| 187 | cFYI(1, ("cifs_create returned 0x%x ", rc)); | 195 | cFYI(1, ("cifs_create returned 0x%x ", rc)); |
| 188 | } else { | 196 | } else { |
| @@ -208,7 +216,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 208 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 216 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 209 | } | 217 | } |
| 210 | else { | 218 | else { |
| 211 | /* BB implement via Windows security descriptors */ | 219 | /* BB implement mode setting via Windows security descriptors */ |
| 212 | /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ | 220 | /* eg CIFSSMBWinSetPerms(xid,pTcon,full_path,mode,-1,-1,local_nls);*/ |
| 213 | /* could set r/o dos attribute if mode & 0222 == 0 */ | 221 | /* could set r/o dos attribute if mode & 0222 == 0 */ |
| 214 | } | 222 | } |
| @@ -225,10 +233,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, | |||
| 225 | } | 233 | } |
| 226 | 234 | ||
| 227 | if (rc != 0) { | 235 | if (rc != 0) { |
| 228 | cFYI(1,("Create worked but get_inode_info failed with rc = %d", | 236 | cFYI(1, |
| 237 | ("Create worked but get_inode_info failed rc = %d", | ||
| 229 | rc)); | 238 | rc)); |
| 230 | } else { | 239 | } else { |
| 231 | direntry->d_op = &cifs_dentry_ops; | 240 | if (pTcon->nocase) |
| 241 | direntry->d_op = &cifs_ci_dentry_ops; | ||
| 242 | else | ||
| 243 | direntry->d_op = &cifs_dentry_ops; | ||
| 232 | d_instantiate(direntry, newinode); | 244 | d_instantiate(direntry, newinode); |
| 233 | } | 245 | } |
| 234 | if((nd->flags & LOOKUP_OPEN) == FALSE) { | 246 | if((nd->flags & LOOKUP_OPEN) == FALSE) { |
| @@ -302,8 +314,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
| 302 | up(&direntry->d_sb->s_vfs_rename_sem); | 314 | up(&direntry->d_sb->s_vfs_rename_sem); |
| 303 | if(full_path == NULL) | 315 | if(full_path == NULL) |
| 304 | rc = -ENOMEM; | 316 | rc = -ENOMEM; |
| 305 | 317 | else if (pTcon->ses->capabilities & CAP_UNIX) { | |
| 306 | if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) { | ||
| 307 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { | 318 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { |
| 308 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, | 319 | rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, |
| 309 | mode,(__u64)current->euid,(__u64)current->egid, | 320 | mode,(__u64)current->euid,(__u64)current->egid, |
| @@ -321,10 +332,49 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev | |||
| 321 | if(!rc) { | 332 | if(!rc) { |
| 322 | rc = cifs_get_inode_info_unix(&newinode, full_path, | 333 | rc = cifs_get_inode_info_unix(&newinode, full_path, |
| 323 | inode->i_sb,xid); | 334 | inode->i_sb,xid); |
| 324 | direntry->d_op = &cifs_dentry_ops; | 335 | if (pTcon->nocase) |
| 336 | direntry->d_op = &cifs_ci_dentry_ops; | ||
| 337 | else | ||
| 338 | direntry->d_op = &cifs_dentry_ops; | ||
| 325 | if(rc == 0) | 339 | if(rc == 0) |
| 326 | d_instantiate(direntry, newinode); | 340 | d_instantiate(direntry, newinode); |
| 327 | } | 341 | } |
| 342 | } else { | ||
| 343 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { | ||
| 344 | int oplock = 0; | ||
| 345 | u16 fileHandle; | ||
| 346 | FILE_ALL_INFO * buf; | ||
| 347 | |||
| 348 | cFYI(1,("sfu compat create special file")); | ||
| 349 | |||
| 350 | buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL); | ||
| 351 | if(buf == NULL) { | ||
| 352 | kfree(full_path); | ||
| 353 | FreeXid(xid); | ||
| 354 | return -ENOMEM; | ||
| 355 | } | ||
| 356 | |||
| 357 | rc = CIFSSMBOpen(xid, pTcon, full_path, | ||
| 358 | FILE_CREATE, /* fail if exists */ | ||
| 359 | GENERIC_WRITE /* BB would | ||
| 360 | WRITE_OWNER | WRITE_DAC be better? */, | ||
| 361 | /* Create a file and set the | ||
| 362 | file attribute to SYSTEM */ | ||
| 363 | CREATE_NOT_DIR | CREATE_OPTION_SPECIAL, | ||
| 364 | &fileHandle, &oplock, buf, | ||
| 365 | cifs_sb->local_nls, | ||
| 366 | cifs_sb->mnt_cifs_flags & | ||
| 367 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 368 | |||
| 369 | if(!rc) { | ||
| 370 | /* BB Do not bother to decode buf since no | ||
| 371 | local inode yet to put timestamps in */ | ||
| 372 | CIFSSMBClose(xid, pTcon, fileHandle); | ||
| 373 | d_drop(direntry); | ||
| 374 | } | ||
| 375 | kfree(buf); | ||
| 376 | /* add code here to set EAs */ | ||
| 377 | } | ||
| 328 | } | 378 | } |
| 329 | 379 | ||
| 330 | kfree(full_path); | 380 | kfree(full_path); |
| @@ -381,7 +431,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name | |||
| 381 | parent_dir_inode->i_sb,xid); | 431 | parent_dir_inode->i_sb,xid); |
| 382 | 432 | ||
| 383 | if ((rc == 0) && (newInode != NULL)) { | 433 | if ((rc == 0) && (newInode != NULL)) { |
| 384 | direntry->d_op = &cifs_dentry_ops; | 434 | if (pTcon->nocase) |
| 435 | direntry->d_op = &cifs_ci_dentry_ops; | ||
| 436 | else | ||
| 437 | direntry->d_op = &cifs_dentry_ops; | ||
| 385 | d_add(direntry, newInode); | 438 | d_add(direntry, newInode); |
| 386 | 439 | ||
| 387 | /* since paths are not looked up by component - the parent directories are presumed to be good here */ | 440 | /* since paths are not looked up by component - the parent directories are presumed to be good here */ |
| @@ -440,3 +493,42 @@ struct dentry_operations cifs_dentry_ops = { | |||
| 440 | /* d_delete: cifs_d_delete, *//* not needed except for debugging */ | 493 | /* d_delete: cifs_d_delete, *//* not needed except for debugging */ |
| 441 | /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ | 494 | /* no need for d_hash, d_compare, d_release, d_iput ... yet. BB confirm this BB */ |
| 442 | }; | 495 | }; |
| 496 | |||
| 497 | static int cifs_ci_hash(struct dentry *dentry, struct qstr *q) | ||
| 498 | { | ||
| 499 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | ||
| 500 | unsigned long hash; | ||
| 501 | int i; | ||
| 502 | |||
| 503 | hash = init_name_hash(); | ||
| 504 | for (i = 0; i < q->len; i++) | ||
| 505 | hash = partial_name_hash(nls_tolower(codepage, q->name[i]), | ||
| 506 | hash); | ||
| 507 | q->hash = end_name_hash(hash); | ||
| 508 | |||
| 509 | return 0; | ||
| 510 | } | ||
| 511 | |||
| 512 | static int cifs_ci_compare(struct dentry *dentry, struct qstr *a, | ||
| 513 | struct qstr *b) | ||
| 514 | { | ||
| 515 | struct nls_table *codepage = CIFS_SB(dentry->d_inode->i_sb)->local_nls; | ||
| 516 | |||
| 517 | if ((a->len == b->len) && | ||
| 518 | (nls_strnicmp(codepage, a->name, b->name, a->len) == 0)) { | ||
| 519 | /* | ||
| 520 | * To preserve case, don't let an existing negative dentry's | ||
| 521 | * case take precedence. If a is not a negative dentry, this | ||
| 522 | * should have no side effects | ||
| 523 | */ | ||
| 524 | memcpy((unsigned char *)a->name, b->name, a->len); | ||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | return 1; | ||
| 528 | } | ||
| 529 | |||
| 530 | struct dentry_operations cifs_ci_dentry_ops = { | ||
| 531 | .d_revalidate = cifs_d_revalidate, | ||
| 532 | .d_hash = cifs_ci_hash, | ||
| 533 | .d_compare = cifs_ci_compare, | ||
| 534 | }; | ||
diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 7d2a9202c39a..a7a47bb36bf3 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c | |||
| @@ -78,6 +78,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
| 78 | __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; | 78 | __u32 filter = FILE_NOTIFY_CHANGE_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES; |
| 79 | __u16 netfid; | 79 | __u16 netfid; |
| 80 | 80 | ||
| 81 | |||
| 82 | if(experimEnabled == 0) | ||
| 83 | return 0; | ||
| 84 | |||
| 81 | xid = GetXid(); | 85 | xid = GetXid(); |
| 82 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 86 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
| 83 | pTcon = cifs_sb->tcon; | 87 | pTcon = cifs_sb->tcon; |
| @@ -100,8 +104,10 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
| 100 | } else { | 104 | } else { |
| 101 | filter = convert_to_cifs_notify_flags(arg); | 105 | filter = convert_to_cifs_notify_flags(arg); |
| 102 | if(filter != 0) { | 106 | if(filter != 0) { |
| 103 | rc = CIFSSMBNotify(xid, pTcon, 0 /* no subdirs */, netfid, | 107 | rc = CIFSSMBNotify(xid, pTcon, |
| 104 | filter, cifs_sb->local_nls); | 108 | 0 /* no subdirs */, netfid, |
| 109 | filter, file, arg & DN_MULTISHOT, | ||
| 110 | cifs_sb->local_nls); | ||
| 105 | } else { | 111 | } else { |
| 106 | rc = -EINVAL; | 112 | rc = -EINVAL; |
| 107 | } | 113 | } |
| @@ -109,7 +115,7 @@ int cifs_dir_notify(struct file * file, unsigned long arg) | |||
| 109 | it would close automatically but may be a way | 115 | it would close automatically but may be a way |
| 110 | to do it easily when inode freed or when | 116 | to do it easily when inode freed or when |
| 111 | notify info is cleared/changed */ | 117 | notify info is cleared/changed */ |
| 112 | cERROR(1,("notify rc %d",rc)); | 118 | cFYI(1,("notify rc %d",rc)); |
| 113 | } | 119 | } |
| 114 | } | 120 | } |
| 115 | 121 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 3497125189df..da4f5e10b3cc 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
| @@ -21,11 +21,15 @@ | |||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 22 | */ | 22 | */ |
| 23 | #include <linux/fs.h> | 23 | #include <linux/fs.h> |
| 24 | #include <linux/backing-dev.h> | ||
| 24 | #include <linux/stat.h> | 25 | #include <linux/stat.h> |
| 25 | #include <linux/fcntl.h> | 26 | #include <linux/fcntl.h> |
| 27 | #include <linux/mpage.h> | ||
| 26 | #include <linux/pagemap.h> | 28 | #include <linux/pagemap.h> |
| 27 | #include <linux/pagevec.h> | 29 | #include <linux/pagevec.h> |
| 28 | #include <linux/smp_lock.h> | 30 | #include <linux/smp_lock.h> |
| 31 | #include <linux/writeback.h> | ||
| 32 | #include <linux/delay.h> | ||
| 29 | #include <asm/div64.h> | 33 | #include <asm/div64.h> |
| 30 | #include "cifsfs.h" | 34 | #include "cifsfs.h" |
| 31 | #include "cifspdu.h" | 35 | #include "cifspdu.h" |
| @@ -47,6 +51,11 @@ static inline struct cifsFileInfo *cifs_init_private( | |||
| 47 | private_data->pInode = inode; | 51 | private_data->pInode = inode; |
| 48 | private_data->invalidHandle = FALSE; | 52 | private_data->invalidHandle = FALSE; |
| 49 | private_data->closePend = FALSE; | 53 | private_data->closePend = FALSE; |
| 54 | /* we have to track num writers to the inode, since writepages | ||
| 55 | does not tell us which handle the write is for so there can | ||
| 56 | be a close (overlapping with write) of the filehandle that | ||
| 57 | cifs_writepages chose to use */ | ||
| 58 | atomic_set(&private_data->wrtPending,0); | ||
| 50 | 59 | ||
| 51 | return private_data; | 60 | return private_data; |
| 52 | } | 61 | } |
| @@ -256,6 +265,13 @@ int cifs_open(struct inode *inode, struct file *file) | |||
| 256 | CREATE_NOT_DIR, &netfid, &oplock, buf, | 265 | CREATE_NOT_DIR, &netfid, &oplock, buf, |
| 257 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | 266 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags |
| 258 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | 267 | & CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 268 | if (rc == -EIO) { | ||
| 269 | /* Old server, try legacy style OpenX */ | ||
| 270 | rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, | ||
| 271 | desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, | ||
| 272 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags | ||
| 273 | & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 274 | } | ||
| 259 | if (rc) { | 275 | if (rc) { |
| 260 | cFYI(1, ("cifs_open returned 0x%x ", rc)); | 276 | cFYI(1, ("cifs_open returned 0x%x ", rc)); |
| 261 | goto out; | 277 | goto out; |
| @@ -463,6 +479,20 @@ int cifs_close(struct inode *inode, struct file *file) | |||
| 463 | /* no sense reconnecting to close a file that is | 479 | /* no sense reconnecting to close a file that is |
| 464 | already closed */ | 480 | already closed */ |
| 465 | if (pTcon->tidStatus != CifsNeedReconnect) { | 481 | if (pTcon->tidStatus != CifsNeedReconnect) { |
| 482 | int timeout = 2; | ||
| 483 | while((atomic_read(&pSMBFile->wrtPending) != 0) | ||
| 484 | && (timeout < 1000) ) { | ||
| 485 | /* Give write a better chance to get to | ||
| 486 | server ahead of the close. We do not | ||
| 487 | want to add a wait_q here as it would | ||
| 488 | increase the memory utilization as | ||
| 489 | the struct would be in each open file, | ||
| 490 | but this should give enough time to | ||
| 491 | clear the socket */ | ||
| 492 | cERROR(1,("close with pending writes")); | ||
| 493 | msleep(timeout); | ||
| 494 | timeout *= 4; | ||
| 495 | } | ||
| 466 | write_unlock(&file->f_owner.lock); | 496 | write_unlock(&file->f_owner.lock); |
| 467 | rc = CIFSSMBClose(xid, pTcon, | 497 | rc = CIFSSMBClose(xid, pTcon, |
| 468 | pSMBFile->netfid); | 498 | pSMBFile->netfid); |
| @@ -744,14 +774,7 @@ ssize_t cifs_user_write(struct file *file, const char __user *write_data, | |||
| 744 | 15 seconds is plenty */ | 774 | 15 seconds is plenty */ |
| 745 | } | 775 | } |
| 746 | 776 | ||
| 747 | #ifdef CONFIG_CIFS_STATS | 777 | cifs_stats_bytes_written(pTcon, total_written); |
| 748 | if (total_written > 0) { | ||
| 749 | atomic_inc(&pTcon->num_writes); | ||
| 750 | spin_lock(&pTcon->stat_lock); | ||
| 751 | pTcon->bytes_written += total_written; | ||
| 752 | spin_unlock(&pTcon->stat_lock); | ||
| 753 | } | ||
| 754 | #endif | ||
| 755 | 778 | ||
| 756 | /* since the write may have blocked check these pointers again */ | 779 | /* since the write may have blocked check these pointers again */ |
| 757 | if (file->f_dentry) { | 780 | if (file->f_dentry) { |
| @@ -791,9 +814,8 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
| 791 | 814 | ||
| 792 | pTcon = cifs_sb->tcon; | 815 | pTcon = cifs_sb->tcon; |
| 793 | 816 | ||
| 794 | /* cFYI(1, | 817 | cFYI(1,("write %zd bytes to offset %lld of %s", write_size, |
| 795 | (" write %d bytes to offset %lld of %s", write_size, | 818 | *poffset, file->f_dentry->d_name.name)); |
| 796 | *poffset, file->f_dentry->d_name.name)); */ | ||
| 797 | 819 | ||
| 798 | if (file->private_data == NULL) | 820 | if (file->private_data == NULL) |
| 799 | return -EBADF; | 821 | return -EBADF; |
| @@ -846,7 +868,26 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
| 846 | if (rc != 0) | 868 | if (rc != 0) |
| 847 | break; | 869 | break; |
| 848 | } | 870 | } |
| 849 | 871 | #ifdef CONFIG_CIFS_EXPERIMENTAL | |
| 872 | /* BB FIXME We can not sign across two buffers yet */ | ||
| 873 | if((experimEnabled) && ((pTcon->ses->server->secMode & | ||
| 874 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { | ||
| 875 | struct kvec iov[2]; | ||
| 876 | unsigned int len; | ||
| 877 | |||
| 878 | len = min((size_t)cifs_sb->wsize, | ||
| 879 | write_size - total_written); | ||
| 880 | /* iov[0] is reserved for smb header */ | ||
| 881 | iov[1].iov_base = (char *)write_data + | ||
| 882 | total_written; | ||
| 883 | iov[1].iov_len = len; | ||
| 884 | rc = CIFSSMBWrite2(xid, pTcon, | ||
| 885 | open_file->netfid, len, | ||
| 886 | *poffset, &bytes_written, | ||
| 887 | iov, 1, long_op); | ||
| 888 | } else | ||
| 889 | /* BB FIXME fixup indentation of line below */ | ||
| 890 | #endif | ||
| 850 | rc = CIFSSMBWrite(xid, pTcon, | 891 | rc = CIFSSMBWrite(xid, pTcon, |
| 851 | open_file->netfid, | 892 | open_file->netfid, |
| 852 | min_t(const int, cifs_sb->wsize, | 893 | min_t(const int, cifs_sb->wsize, |
| @@ -867,14 +908,7 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
| 867 | 15 seconds is plenty */ | 908 | 15 seconds is plenty */ |
| 868 | } | 909 | } |
| 869 | 910 | ||
| 870 | #ifdef CONFIG_CIFS_STATS | 911 | cifs_stats_bytes_written(pTcon, total_written); |
| 871 | if (total_written > 0) { | ||
| 872 | atomic_inc(&pTcon->num_writes); | ||
| 873 | spin_lock(&pTcon->stat_lock); | ||
| 874 | pTcon->bytes_written += total_written; | ||
| 875 | spin_unlock(&pTcon->stat_lock); | ||
| 876 | } | ||
| 877 | #endif | ||
| 878 | 912 | ||
| 879 | /* since the write may have blocked check these pointers again */ | 913 | /* since the write may have blocked check these pointers again */ |
| 880 | if (file->f_dentry) { | 914 | if (file->f_dentry) { |
| @@ -893,6 +927,43 @@ static ssize_t cifs_write(struct file *file, const char *write_data, | |||
| 893 | return total_written; | 927 | return total_written; |
| 894 | } | 928 | } |
| 895 | 929 | ||
| 930 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) | ||
| 931 | { | ||
| 932 | struct cifsFileInfo *open_file; | ||
| 933 | int rc; | ||
| 934 | |||
| 935 | read_lock(&GlobalSMBSeslock); | ||
| 936 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | ||
| 937 | if (open_file->closePend) | ||
| 938 | continue; | ||
| 939 | if (open_file->pfile && | ||
| 940 | ((open_file->pfile->f_flags & O_RDWR) || | ||
| 941 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
| 942 | atomic_inc(&open_file->wrtPending); | ||
| 943 | read_unlock(&GlobalSMBSeslock); | ||
| 944 | if((open_file->invalidHandle) && | ||
| 945 | (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { | ||
| 946 | rc = cifs_reopen_file(&cifs_inode->vfs_inode, | ||
| 947 | open_file->pfile, FALSE); | ||
| 948 | /* if it fails, try another handle - might be */ | ||
| 949 | /* dangerous to hold up writepages with retry */ | ||
| 950 | if(rc) { | ||
| 951 | cFYI(1,("failed on reopen file in wp")); | ||
| 952 | read_lock(&GlobalSMBSeslock); | ||
| 953 | /* can not use this handle, no write | ||
| 954 | pending on this one after all */ | ||
| 955 | atomic_dec | ||
| 956 | (&open_file->wrtPending); | ||
| 957 | continue; | ||
| 958 | } | ||
| 959 | } | ||
| 960 | return open_file; | ||
| 961 | } | ||
| 962 | } | ||
| 963 | read_unlock(&GlobalSMBSeslock); | ||
| 964 | return NULL; | ||
| 965 | } | ||
| 966 | |||
| 896 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | 967 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) |
| 897 | { | 968 | { |
| 898 | struct address_space *mapping = page->mapping; | 969 | struct address_space *mapping = page->mapping; |
| @@ -903,10 +974,7 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
| 903 | struct cifs_sb_info *cifs_sb; | 974 | struct cifs_sb_info *cifs_sb; |
| 904 | struct cifsTconInfo *pTcon; | 975 | struct cifsTconInfo *pTcon; |
| 905 | struct inode *inode; | 976 | struct inode *inode; |
| 906 | struct cifsInodeInfo *cifsInode; | 977 | struct cifsFileInfo *open_file; |
| 907 | struct cifsFileInfo *open_file = NULL; | ||
| 908 | struct list_head *tmp; | ||
| 909 | struct list_head *tmp1; | ||
| 910 | 978 | ||
| 911 | if (!mapping || !mapping->host) | 979 | if (!mapping || !mapping->host) |
| 912 | return -EFAULT; | 980 | return -EFAULT; |
| @@ -934,49 +1002,20 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
| 934 | if (mapping->host->i_size - offset < (loff_t)to) | 1002 | if (mapping->host->i_size - offset < (loff_t)to) |
| 935 | to = (unsigned)(mapping->host->i_size - offset); | 1003 | to = (unsigned)(mapping->host->i_size - offset); |
| 936 | 1004 | ||
| 937 | cifsInode = CIFS_I(mapping->host); | 1005 | open_file = find_writable_file(CIFS_I(mapping->host)); |
| 938 | read_lock(&GlobalSMBSeslock); | 1006 | if (open_file) { |
| 939 | /* BB we should start at the end */ | 1007 | bytes_written = cifs_write(open_file->pfile, write_data, |
| 940 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | 1008 | to-from, &offset); |
| 941 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | 1009 | atomic_dec(&open_file->wrtPending); |
| 942 | if (open_file->closePend) | ||
| 943 | continue; | ||
| 944 | /* We check if file is open for writing first */ | ||
| 945 | if ((open_file->pfile) && | ||
| 946 | ((open_file->pfile->f_flags & O_RDWR) || | ||
| 947 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
| 948 | read_unlock(&GlobalSMBSeslock); | ||
| 949 | bytes_written = cifs_write(open_file->pfile, | ||
| 950 | write_data, to-from, | ||
| 951 | &offset); | ||
| 952 | read_lock(&GlobalSMBSeslock); | ||
| 953 | /* Does mm or vfs already set times? */ | 1010 | /* Does mm or vfs already set times? */ |
| 954 | inode->i_atime = | 1011 | inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb); |
| 955 | inode->i_mtime = current_fs_time(inode->i_sb); | 1012 | if ((bytes_written > 0) && (offset)) { |
| 956 | if ((bytes_written > 0) && (offset)) { | 1013 | rc = 0; |
| 957 | rc = 0; | 1014 | } else if (bytes_written < 0) { |
| 958 | } else if (bytes_written < 0) { | 1015 | if (rc != -EBADF) |
| 959 | if (rc == -EBADF) { | 1016 | rc = bytes_written; |
| 960 | /* have seen a case in which kernel seemed to | ||
| 961 | have closed/freed a file even with writes | ||
| 962 | active so we might as well see if there are | ||
| 963 | other file structs to try for the same | ||
| 964 | inode before giving up */ | ||
| 965 | continue; | ||
| 966 | } else | ||
| 967 | rc = bytes_written; | ||
| 968 | } | ||
| 969 | break; /* now that we found a valid file handle and | ||
| 970 | tried to write to it we are done, no sense | ||
| 971 | continuing to loop looking for another */ | ||
| 972 | } | ||
| 973 | if (tmp->next == NULL) { | ||
| 974 | cFYI(1, ("File instance %p removed", tmp)); | ||
| 975 | break; | ||
| 976 | } | 1017 | } |
| 977 | } | 1018 | } else { |
| 978 | read_unlock(&GlobalSMBSeslock); | ||
| 979 | if (open_file == NULL) { | ||
| 980 | cFYI(1, ("No writeable filehandles for inode")); | 1019 | cFYI(1, ("No writeable filehandles for inode")); |
| 981 | rc = -EIO; | 1020 | rc = -EIO; |
| 982 | } | 1021 | } |
| @@ -985,20 +1024,207 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
| 985 | return rc; | 1024 | return rc; |
| 986 | } | 1025 | } |
| 987 | 1026 | ||
| 988 | #if 0 | 1027 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| 989 | static int cifs_writepages(struct address_space *mapping, | 1028 | static int cifs_writepages(struct address_space *mapping, |
| 990 | struct writeback_control *wbc) | 1029 | struct writeback_control *wbc) |
| 991 | { | 1030 | { |
| 992 | int rc = -EFAULT; | 1031 | struct backing_dev_info *bdi = mapping->backing_dev_info; |
| 1032 | unsigned int bytes_to_write; | ||
| 1033 | unsigned int bytes_written; | ||
| 1034 | struct cifs_sb_info *cifs_sb; | ||
| 1035 | int done = 0; | ||
| 1036 | pgoff_t end = -1; | ||
| 1037 | pgoff_t index; | ||
| 1038 | int is_range = 0; | ||
| 1039 | struct kvec iov[32]; | ||
| 1040 | int len; | ||
| 1041 | int n_iov = 0; | ||
| 1042 | pgoff_t next; | ||
| 1043 | int nr_pages; | ||
| 1044 | __u64 offset = 0; | ||
| 1045 | struct cifsFileInfo *open_file; | ||
| 1046 | struct page *page; | ||
| 1047 | struct pagevec pvec; | ||
| 1048 | int rc = 0; | ||
| 1049 | int scanned = 0; | ||
| 993 | int xid; | 1050 | int xid; |
| 994 | 1051 | ||
| 1052 | cifs_sb = CIFS_SB(mapping->host->i_sb); | ||
| 1053 | |||
| 1054 | /* | ||
| 1055 | * If wsize is smaller that the page cache size, default to writing | ||
| 1056 | * one page at a time via cifs_writepage | ||
| 1057 | */ | ||
| 1058 | if (cifs_sb->wsize < PAGE_CACHE_SIZE) | ||
| 1059 | return generic_writepages(mapping, wbc); | ||
| 1060 | |||
| 1061 | /* BB FIXME we do not have code to sign across multiple buffers yet, | ||
| 1062 | so go to older writepage style write which we can sign if needed */ | ||
| 1063 | if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server)) | ||
| 1064 | if(cifs_sb->tcon->ses->server->secMode & | ||
| 1065 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
| 1066 | return generic_writepages(mapping, wbc); | ||
| 1067 | |||
| 1068 | /* | ||
| 1069 | * BB: Is this meaningful for a non-block-device file system? | ||
| 1070 | * If it is, we should test it again after we do I/O | ||
| 1071 | */ | ||
| 1072 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
| 1073 | wbc->encountered_congestion = 1; | ||
| 1074 | return 0; | ||
| 1075 | } | ||
| 1076 | |||
| 995 | xid = GetXid(); | 1077 | xid = GetXid(); |
| 996 | 1078 | ||
| 997 | /* Find contiguous pages then iterate through repeating | 1079 | pagevec_init(&pvec, 0); |
| 998 | call 16K write then Setpageuptodate or if LARGE_WRITE_X | 1080 | if (wbc->sync_mode == WB_SYNC_NONE) |
| 999 | support then send larger writes via kevec so as to eliminate | 1081 | index = mapping->writeback_index; /* Start from prev offset */ |
| 1000 | a memcpy */ | 1082 | else { |
| 1083 | index = 0; | ||
| 1084 | scanned = 1; | ||
| 1085 | } | ||
| 1086 | if (wbc->start || wbc->end) { | ||
| 1087 | index = wbc->start >> PAGE_CACHE_SHIFT; | ||
| 1088 | end = wbc->end >> PAGE_CACHE_SHIFT; | ||
| 1089 | is_range = 1; | ||
| 1090 | scanned = 1; | ||
| 1091 | } | ||
| 1092 | retry: | ||
| 1093 | while (!done && (index <= end) && | ||
| 1094 | (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, | ||
| 1095 | PAGECACHE_TAG_DIRTY, | ||
| 1096 | min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) { | ||
| 1097 | int first; | ||
| 1098 | unsigned int i; | ||
| 1099 | |||
| 1100 | first = -1; | ||
| 1101 | next = 0; | ||
| 1102 | n_iov = 0; | ||
| 1103 | bytes_to_write = 0; | ||
| 1104 | |||
| 1105 | for (i = 0; i < nr_pages; i++) { | ||
| 1106 | page = pvec.pages[i]; | ||
| 1107 | /* | ||
| 1108 | * At this point we hold neither mapping->tree_lock nor | ||
| 1109 | * lock on the page itself: the page may be truncated or | ||
| 1110 | * invalidated (changing page->mapping to NULL), or even | ||
| 1111 | * swizzled back from swapper_space to tmpfs file | ||
| 1112 | * mapping | ||
| 1113 | */ | ||
| 1114 | |||
| 1115 | if (first < 0) | ||
| 1116 | lock_page(page); | ||
| 1117 | else if (TestSetPageLocked(page)) | ||
| 1118 | break; | ||
| 1119 | |||
| 1120 | if (unlikely(page->mapping != mapping)) { | ||
| 1121 | unlock_page(page); | ||
| 1122 | break; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | if (unlikely(is_range) && (page->index > end)) { | ||
| 1126 | done = 1; | ||
| 1127 | unlock_page(page); | ||
| 1128 | break; | ||
| 1129 | } | ||
| 1130 | |||
| 1131 | if (next && (page->index != next)) { | ||
| 1132 | /* Not next consecutive page */ | ||
| 1133 | unlock_page(page); | ||
| 1134 | break; | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
| 1138 | wait_on_page_writeback(page); | ||
| 1139 | |||
| 1140 | if (PageWriteback(page) || | ||
| 1141 | !test_clear_page_dirty(page)) { | ||
| 1142 | unlock_page(page); | ||
| 1143 | break; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | if (page_offset(page) >= mapping->host->i_size) { | ||
| 1147 | done = 1; | ||
| 1148 | unlock_page(page); | ||
| 1149 | break; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | /* | ||
| 1153 | * BB can we get rid of this? pages are held by pvec | ||
| 1154 | */ | ||
| 1155 | page_cache_get(page); | ||
| 1156 | |||
| 1157 | len = min(mapping->host->i_size - page_offset(page), | ||
| 1158 | (loff_t)PAGE_CACHE_SIZE); | ||
| 1159 | |||
| 1160 | /* reserve iov[0] for the smb header */ | ||
| 1161 | n_iov++; | ||
| 1162 | iov[n_iov].iov_base = kmap(page); | ||
| 1163 | iov[n_iov].iov_len = len; | ||
| 1164 | bytes_to_write += len; | ||
| 1165 | |||
| 1166 | if (first < 0) { | ||
| 1167 | first = i; | ||
| 1168 | offset = page_offset(page); | ||
| 1169 | } | ||
| 1170 | next = page->index + 1; | ||
| 1171 | if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize) | ||
| 1172 | break; | ||
| 1173 | } | ||
| 1174 | if (n_iov) { | ||
| 1175 | /* Search for a writable handle every time we call | ||
| 1176 | * CIFSSMBWrite2. We can't rely on the last handle | ||
| 1177 | * we used to still be valid | ||
| 1178 | */ | ||
| 1179 | open_file = find_writable_file(CIFS_I(mapping->host)); | ||
| 1180 | if (!open_file) { | ||
| 1181 | cERROR(1, ("No writable handles for inode")); | ||
| 1182 | rc = -EBADF; | ||
| 1183 | } else { | ||
| 1184 | rc = CIFSSMBWrite2(xid, cifs_sb->tcon, | ||
| 1185 | open_file->netfid, | ||
| 1186 | bytes_to_write, offset, | ||
| 1187 | &bytes_written, iov, n_iov, | ||
| 1188 | 1); | ||
| 1189 | atomic_dec(&open_file->wrtPending); | ||
| 1190 | if (rc || bytes_written < bytes_to_write) { | ||
| 1191 | cERROR(1,("Write2 ret %d, written = %d", | ||
| 1192 | rc, bytes_written)); | ||
| 1193 | /* BB what if continued retry is | ||
| 1194 | requested via mount flags? */ | ||
| 1195 | set_bit(AS_EIO, &mapping->flags); | ||
| 1196 | SetPageError(page); | ||
| 1197 | } else { | ||
| 1198 | cifs_stats_bytes_written(cifs_sb->tcon, | ||
| 1199 | bytes_written); | ||
| 1200 | } | ||
| 1201 | } | ||
| 1202 | for (i = 0; i < n_iov; i++) { | ||
| 1203 | page = pvec.pages[first + i]; | ||
| 1204 | kunmap(page); | ||
| 1205 | unlock_page(page); | ||
| 1206 | page_cache_release(page); | ||
| 1207 | } | ||
| 1208 | if ((wbc->nr_to_write -= n_iov) <= 0) | ||
| 1209 | done = 1; | ||
| 1210 | index = next; | ||
| 1211 | } | ||
| 1212 | pagevec_release(&pvec); | ||
| 1213 | } | ||
| 1214 | if (!scanned && !done) { | ||
| 1215 | /* | ||
| 1216 | * We hit the last page and there is more work to be done: wrap | ||
| 1217 | * back to the start of the file | ||
| 1218 | */ | ||
| 1219 | scanned = 1; | ||
| 1220 | index = 0; | ||
| 1221 | goto retry; | ||
| 1222 | } | ||
| 1223 | if (!is_range) | ||
| 1224 | mapping->writeback_index = index; | ||
| 1225 | |||
| 1001 | FreeXid(xid); | 1226 | FreeXid(xid); |
| 1227 | |||
| 1002 | return rc; | 1228 | return rc; |
| 1003 | } | 1229 | } |
| 1004 | #endif | 1230 | #endif |
| @@ -1207,12 +1433,10 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
| 1207 | if (rc != 0) | 1433 | if (rc != 0) |
| 1208 | break; | 1434 | break; |
| 1209 | } | 1435 | } |
| 1210 | |||
| 1211 | rc = CIFSSMBRead(xid, pTcon, | 1436 | rc = CIFSSMBRead(xid, pTcon, |
| 1212 | open_file->netfid, | 1437 | open_file->netfid, |
| 1213 | current_read_size, *poffset, | 1438 | current_read_size, *poffset, |
| 1214 | &bytes_read, &smb_read_data); | 1439 | &bytes_read, &smb_read_data); |
| 1215 | |||
| 1216 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; | 1440 | pSMBr = (struct smb_com_read_rsp *)smb_read_data; |
| 1217 | if (copy_to_user(current_offset, | 1441 | if (copy_to_user(current_offset, |
| 1218 | smb_read_data + 4 /* RFC1001 hdr */ | 1442 | smb_read_data + 4 /* RFC1001 hdr */ |
| @@ -1235,12 +1459,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, | |||
| 1235 | return rc; | 1459 | return rc; |
| 1236 | } | 1460 | } |
| 1237 | } else { | 1461 | } else { |
| 1238 | #ifdef CONFIG_CIFS_STATS | 1462 | cifs_stats_bytes_read(pTcon, bytes_read); |
| 1239 | atomic_inc(&pTcon->num_reads); | ||
| 1240 | spin_lock(&pTcon->stat_lock); | ||
| 1241 | pTcon->bytes_read += total_read; | ||
| 1242 | spin_unlock(&pTcon->stat_lock); | ||
| 1243 | #endif | ||
| 1244 | *poffset += bytes_read; | 1463 | *poffset += bytes_read; |
| 1245 | } | 1464 | } |
| 1246 | } | 1465 | } |
| @@ -1280,6 +1499,13 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
| 1280 | total_read += bytes_read, current_offset += bytes_read) { | 1499 | total_read += bytes_read, current_offset += bytes_read) { |
| 1281 | current_read_size = min_t(const int, read_size - total_read, | 1500 | current_read_size = min_t(const int, read_size - total_read, |
| 1282 | cifs_sb->rsize); | 1501 | cifs_sb->rsize); |
| 1502 | /* For windows me and 9x we do not want to request more | ||
| 1503 | than it negotiated since it will refuse the read then */ | ||
| 1504 | if((pTcon->ses) && | ||
| 1505 | !(pTcon->ses->capabilities & CAP_LARGE_FILES)) { | ||
| 1506 | current_read_size = min_t(const int, current_read_size, | ||
| 1507 | pTcon->ses->server->maxBuf - 128); | ||
| 1508 | } | ||
| 1283 | rc = -EAGAIN; | 1509 | rc = -EAGAIN; |
| 1284 | while (rc == -EAGAIN) { | 1510 | while (rc == -EAGAIN) { |
| 1285 | if ((open_file->invalidHandle) && | 1511 | if ((open_file->invalidHandle) && |
| @@ -1289,11 +1515,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
| 1289 | if (rc != 0) | 1515 | if (rc != 0) |
| 1290 | break; | 1516 | break; |
| 1291 | } | 1517 | } |
| 1292 | |||
| 1293 | rc = CIFSSMBRead(xid, pTcon, | 1518 | rc = CIFSSMBRead(xid, pTcon, |
| 1294 | open_file->netfid, | 1519 | open_file->netfid, |
| 1295 | current_read_size, *poffset, | 1520 | current_read_size, *poffset, |
| 1296 | &bytes_read, ¤t_offset); | 1521 | &bytes_read, ¤t_offset); |
| 1297 | } | 1522 | } |
| 1298 | if (rc || (bytes_read == 0)) { | 1523 | if (rc || (bytes_read == 0)) { |
| 1299 | if (total_read) { | 1524 | if (total_read) { |
| @@ -1303,12 +1528,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, | |||
| 1303 | return rc; | 1528 | return rc; |
| 1304 | } | 1529 | } |
| 1305 | } else { | 1530 | } else { |
| 1306 | #ifdef CONFIG_CIFS_STATS | 1531 | cifs_stats_bytes_read(pTcon, total_read); |
| 1307 | atomic_inc(&pTcon->num_reads); | ||
| 1308 | spin_lock(&pTcon->stat_lock); | ||
| 1309 | pTcon->bytes_read += total_read; | ||
| 1310 | spin_unlock(&pTcon->stat_lock); | ||
| 1311 | #endif | ||
| 1312 | *poffset += bytes_read; | 1532 | *poffset += bytes_read; |
| 1313 | } | 1533 | } |
| 1314 | } | 1534 | } |
| @@ -1452,10 +1672,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
| 1452 | } | 1672 | } |
| 1453 | 1673 | ||
| 1454 | rc = CIFSSMBRead(xid, pTcon, | 1674 | rc = CIFSSMBRead(xid, pTcon, |
| 1455 | open_file->netfid, | 1675 | open_file->netfid, |
| 1456 | read_size, offset, | 1676 | read_size, offset, |
| 1457 | &bytes_read, &smb_read_data); | 1677 | &bytes_read, &smb_read_data); |
| 1458 | /* BB need to check return code here */ | 1678 | |
| 1679 | /* BB more RC checks ? */ | ||
| 1459 | if (rc== -EAGAIN) { | 1680 | if (rc== -EAGAIN) { |
| 1460 | if (smb_read_data) { | 1681 | if (smb_read_data) { |
| 1461 | cifs_buf_release(smb_read_data); | 1682 | cifs_buf_release(smb_read_data); |
| @@ -1480,12 +1701,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
| 1480 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); | 1701 | le16_to_cpu(pSMBr->DataOffset), &lru_pvec); |
| 1481 | 1702 | ||
| 1482 | i += bytes_read >> PAGE_CACHE_SHIFT; | 1703 | i += bytes_read >> PAGE_CACHE_SHIFT; |
| 1483 | #ifdef CONFIG_CIFS_STATS | 1704 | cifs_stats_bytes_read(pTcon, bytes_read); |
| 1484 | atomic_inc(&pTcon->num_reads); | ||
| 1485 | spin_lock(&pTcon->stat_lock); | ||
| 1486 | pTcon->bytes_read += bytes_read; | ||
| 1487 | spin_unlock(&pTcon->stat_lock); | ||
| 1488 | #endif | ||
| 1489 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { | 1705 | if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { |
| 1490 | i++; /* account for partial page */ | 1706 | i++; /* account for partial page */ |
| 1491 | 1707 | ||
| @@ -1603,40 +1819,21 @@ static int cifs_readpage(struct file *file, struct page *page) | |||
| 1603 | page caching in the current Linux kernel design */ | 1819 | page caching in the current Linux kernel design */ |
| 1604 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) | 1820 | int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) |
| 1605 | { | 1821 | { |
| 1606 | struct list_head *tmp; | ||
| 1607 | struct list_head *tmp1; | ||
| 1608 | struct cifsFileInfo *open_file = NULL; | 1822 | struct cifsFileInfo *open_file = NULL; |
| 1609 | int rc = TRUE; | ||
| 1610 | 1823 | ||
| 1611 | if (cifsInode == NULL) | 1824 | if (cifsInode) |
| 1612 | return rc; | 1825 | open_file = find_writable_file(cifsInode); |
| 1613 | 1826 | ||
| 1614 | read_lock(&GlobalSMBSeslock); | 1827 | if(open_file) { |
| 1615 | list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) { | 1828 | /* there is not actually a write pending so let |
| 1616 | open_file = list_entry(tmp, struct cifsFileInfo, flist); | 1829 | this handle go free and allow it to |
| 1617 | if (open_file == NULL) | 1830 | be closable if needed */ |
| 1618 | break; | 1831 | atomic_dec(&open_file->wrtPending); |
| 1619 | if (open_file->closePend) | 1832 | return 0; |
| 1620 | continue; | 1833 | } else |
| 1621 | /* We check if file is open for writing, | 1834 | return 1; |
| 1622 | BB we could supplement this with a check to see if file size | ||
| 1623 | changes have been flushed to server - ie inode metadata dirty */ | ||
| 1624 | if ((open_file->pfile) && | ||
| 1625 | ((open_file->pfile->f_flags & O_RDWR) || | ||
| 1626 | (open_file->pfile->f_flags & O_WRONLY))) { | ||
| 1627 | rc = FALSE; | ||
| 1628 | break; | ||
| 1629 | } | ||
| 1630 | if (tmp->next == NULL) { | ||
| 1631 | cFYI(1, ("File instance %p removed", tmp)); | ||
| 1632 | break; | ||
| 1633 | } | ||
| 1634 | } | ||
| 1635 | read_unlock(&GlobalSMBSeslock); | ||
| 1636 | return rc; | ||
| 1637 | } | 1835 | } |
| 1638 | 1836 | ||
| 1639 | |||
| 1640 | static int cifs_prepare_write(struct file *file, struct page *page, | 1837 | static int cifs_prepare_write(struct file *file, struct page *page, |
| 1641 | unsigned from, unsigned to) | 1838 | unsigned from, unsigned to) |
| 1642 | { | 1839 | { |
| @@ -1676,6 +1873,9 @@ struct address_space_operations cifs_addr_ops = { | |||
| 1676 | .readpage = cifs_readpage, | 1873 | .readpage = cifs_readpage, |
| 1677 | .readpages = cifs_readpages, | 1874 | .readpages = cifs_readpages, |
| 1678 | .writepage = cifs_writepage, | 1875 | .writepage = cifs_writepage, |
| 1876 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
| 1877 | .writepages = cifs_writepages, | ||
| 1878 | #endif | ||
| 1679 | .prepare_write = cifs_prepare_write, | 1879 | .prepare_write = cifs_prepare_write, |
| 1680 | .commit_write = cifs_commit_write, | 1880 | .commit_write = cifs_commit_write, |
| 1681 | .set_page_dirty = __set_page_dirty_nobuffers, | 1881 | .set_page_dirty = __set_page_dirty_nobuffers, |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 8d336a900255..912d401600f6 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -166,7 +166,13 @@ int cifs_get_inode_info_unix(struct inode **pinode, | |||
| 166 | inode->i_fop = &cifs_file_direct_ops; | 166 | inode->i_fop = &cifs_file_direct_ops; |
| 167 | else | 167 | else |
| 168 | inode->i_fop = &cifs_file_ops; | 168 | inode->i_fop = &cifs_file_ops; |
| 169 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 170 | inode->i_fop->lock = NULL; | ||
| 169 | inode->i_data.a_ops = &cifs_addr_ops; | 171 | inode->i_data.a_ops = &cifs_addr_ops; |
| 172 | /* check if server can support readpages */ | ||
| 173 | if(pTcon->ses->server->maxBuf < | ||
| 174 | 4096 + MAX_CIFS_HDR_SIZE) | ||
| 175 | inode->i_data.a_ops->readpages = NULL; | ||
| 170 | } else if (S_ISDIR(inode->i_mode)) { | 176 | } else if (S_ISDIR(inode->i_mode)) { |
| 171 | cFYI(1, (" Directory inode")); | 177 | cFYI(1, (" Directory inode")); |
| 172 | inode->i_op = &cifs_dir_inode_ops; | 178 | inode->i_op = &cifs_dir_inode_ops; |
| @@ -213,8 +219,18 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 213 | pfindData = (FILE_ALL_INFO *)buf; | 219 | pfindData = (FILE_ALL_INFO *)buf; |
| 214 | /* could do find first instead but this returns more info */ | 220 | /* could do find first instead but this returns more info */ |
| 215 | rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, | 221 | rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, |
| 216 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & | 222 | cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & |
| 217 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 223 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 224 | /* BB optimize code so we do not make the above call | ||
| 225 | when server claims no NT SMB support and the above call | ||
| 226 | failed at least once - set flag in tcon or mount */ | ||
| 227 | if((rc == -EOPNOTSUPP) || (rc == -EINVAL)) { | ||
| 228 | rc = SMBQueryInformation(xid, pTcon, search_path, | ||
| 229 | pfindData, cifs_sb->local_nls, | ||
| 230 | cifs_sb->mnt_cifs_flags & | ||
| 231 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 232 | } | ||
| 233 | |||
| 218 | } | 234 | } |
| 219 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ | 235 | /* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */ |
| 220 | if (rc) { | 236 | if (rc) { |
| @@ -320,6 +336,16 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 320 | on dirs */ | 336 | on dirs */ |
| 321 | inode->i_mode = cifs_sb->mnt_dir_mode; | 337 | inode->i_mode = cifs_sb->mnt_dir_mode; |
| 322 | inode->i_mode |= S_IFDIR; | 338 | inode->i_mode |= S_IFDIR; |
| 339 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
| 340 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && | ||
| 341 | /* No need to le64 convert size of zero */ | ||
| 342 | (pfindData->EndOfFile == 0)) { | ||
| 343 | inode->i_mode = cifs_sb->mnt_file_mode; | ||
| 344 | inode->i_mode |= S_IFIFO; | ||
| 345 | /* BB Finish for SFU style symlinks and devies */ | ||
| 346 | /* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
| 347 | (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */ | ||
| 348 | |||
| 323 | } else { | 349 | } else { |
| 324 | inode->i_mode |= S_IFREG; | 350 | inode->i_mode |= S_IFREG; |
| 325 | /* treat the dos attribute of read-only as read-only | 351 | /* treat the dos attribute of read-only as read-only |
| @@ -359,7 +385,12 @@ int cifs_get_inode_info(struct inode **pinode, | |||
| 359 | inode->i_fop = &cifs_file_direct_ops; | 385 | inode->i_fop = &cifs_file_direct_ops; |
| 360 | else | 386 | else |
| 361 | inode->i_fop = &cifs_file_ops; | 387 | inode->i_fop = &cifs_file_ops; |
| 388 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 389 | inode->i_fop->lock = NULL; | ||
| 362 | inode->i_data.a_ops = &cifs_addr_ops; | 390 | inode->i_data.a_ops = &cifs_addr_ops; |
| 391 | if(pTcon->ses->server->maxBuf < | ||
| 392 | 4096 + MAX_CIFS_HDR_SIZE) | ||
| 393 | inode->i_data.a_ops->readpages = NULL; | ||
| 363 | } else if (S_ISDIR(inode->i_mode)) { | 394 | } else if (S_ISDIR(inode->i_mode)) { |
| 364 | cFYI(1, (" Directory inode ")); | 395 | cFYI(1, (" Directory inode ")); |
| 365 | inode->i_op = &cifs_dir_inode_ops; | 396 | inode->i_op = &cifs_dir_inode_ops; |
| @@ -577,7 +608,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) | |||
| 577 | rc = cifs_get_inode_info(&newinode, full_path, NULL, | 608 | rc = cifs_get_inode_info(&newinode, full_path, NULL, |
| 578 | inode->i_sb,xid); | 609 | inode->i_sb,xid); |
| 579 | 610 | ||
| 580 | direntry->d_op = &cifs_dentry_ops; | 611 | if (pTcon->nocase) |
| 612 | direntry->d_op = &cifs_ci_dentry_ops; | ||
| 613 | else | ||
| 614 | direntry->d_op = &cifs_dentry_ops; | ||
| 581 | d_instantiate(direntry, newinode); | 615 | d_instantiate(direntry, newinode); |
| 582 | if (direntry->d_inode) | 616 | if (direntry->d_inode) |
| 583 | direntry->d_inode->i_nlink = 2; | 617 | direntry->d_inode->i_nlink = 2; |
| @@ -928,7 +962,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 928 | struct cifsTconInfo *pTcon; | 962 | struct cifsTconInfo *pTcon; |
| 929 | char *full_path = NULL; | 963 | char *full_path = NULL; |
| 930 | int rc = -EACCES; | 964 | int rc = -EACCES; |
| 931 | int found = FALSE; | ||
| 932 | struct cifsFileInfo *open_file = NULL; | 965 | struct cifsFileInfo *open_file = NULL; |
| 933 | FILE_BASIC_INFO time_buf; | 966 | FILE_BASIC_INFO time_buf; |
| 934 | int set_time = FALSE; | 967 | int set_time = FALSE; |
| @@ -936,7 +969,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 936 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; | 969 | __u64 uid = 0xFFFFFFFFFFFFFFFFULL; |
| 937 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; | 970 | __u64 gid = 0xFFFFFFFFFFFFFFFFULL; |
| 938 | struct cifsInodeInfo *cifsInode; | 971 | struct cifsInodeInfo *cifsInode; |
| 939 | struct list_head *tmp; | ||
| 940 | 972 | ||
| 941 | xid = GetXid(); | 973 | xid = GetXid(); |
| 942 | 974 | ||
| @@ -961,7 +993,6 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 961 | filemap_fdatawait(direntry->d_inode->i_mapping); | 993 | filemap_fdatawait(direntry->d_inode->i_mapping); |
| 962 | 994 | ||
| 963 | if (attrs->ia_valid & ATTR_SIZE) { | 995 | if (attrs->ia_valid & ATTR_SIZE) { |
| 964 | read_lock(&GlobalSMBSeslock); | ||
| 965 | /* To avoid spurious oplock breaks from server, in the case of | 996 | /* To avoid spurious oplock breaks from server, in the case of |
| 966 | inodes that we already have open, avoid doing path based | 997 | inodes that we already have open, avoid doing path based |
| 967 | setting of file size if we can do it by handle. | 998 | setting of file size if we can do it by handle. |
| @@ -969,40 +1000,23 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 969 | when the local oplock break takes longer to flush | 1000 | when the local oplock break takes longer to flush |
| 970 | writebehind data than the SMB timeout for the SetPathInfo | 1001 | writebehind data than the SMB timeout for the SetPathInfo |
| 971 | request would allow */ | 1002 | request would allow */ |
| 972 | list_for_each(tmp, &cifsInode->openFileList) { | 1003 | open_file = find_writable_file(cifsInode); |
| 973 | open_file = list_entry(tmp, struct cifsFileInfo, | 1004 | if (open_file) { |
| 974 | flist); | 1005 | __u16 nfid = open_file->netfid; |
| 975 | /* We check if file is open for writing first */ | 1006 | __u32 npid = open_file->pid; |
| 976 | if ((open_file->pfile) && | 1007 | rc = CIFSSMBSetFileSize(xid, pTcon, attrs->ia_size, |
| 977 | ((open_file->pfile->f_flags & O_RDWR) || | 1008 | nfid, npid, FALSE); |
| 978 | (open_file->pfile->f_flags & O_WRONLY))) { | 1009 | atomic_dec(&open_file->wrtPending); |
| 979 | if (open_file->invalidHandle == FALSE) { | 1010 | cFYI(1,("SetFSize for attrs rc = %d", rc)); |
| 980 | /* we found a valid, writeable network | 1011 | if(rc == -EINVAL) { |
| 981 | file handle to use to try to set the | 1012 | int bytes_written; |
| 982 | file size */ | 1013 | rc = CIFSSMBWrite(xid, pTcon, |
| 983 | __u16 nfid = open_file->netfid; | 1014 | nfid, 0, attrs->ia_size, |
| 984 | __u32 npid = open_file->pid; | 1015 | &bytes_written, NULL, NULL, |
| 985 | read_unlock(&GlobalSMBSeslock); | 1016 | 1 /* 45 seconds */); |
| 986 | found = TRUE; | 1017 | cFYI(1,("Wrt seteof rc %d", rc)); |
| 987 | rc = CIFSSMBSetFileSize(xid, pTcon, | ||
| 988 | attrs->ia_size, nfid, npid, | ||
| 989 | FALSE); | ||
| 990 | cFYI(1, ("SetFileSize by handle " | ||
| 991 | "(setattrs) rc = %d", rc)); | ||
| 992 | /* Do not need reopen and retry on | ||
| 993 | EAGAIN since we will retry by | ||
| 994 | pathname below */ | ||
| 995 | |||
| 996 | /* now that we found one valid file | ||
| 997 | handle no sense continuing to loop | ||
| 998 | trying others, so break here */ | ||
| 999 | break; | ||
| 1000 | } | ||
| 1001 | } | 1018 | } |
| 1002 | } | 1019 | } |
| 1003 | if (found == FALSE) | ||
| 1004 | read_unlock(&GlobalSMBSeslock); | ||
| 1005 | |||
| 1006 | if (rc != 0) { | 1020 | if (rc != 0) { |
| 1007 | /* Set file size by pathname rather than by handle | 1021 | /* Set file size by pathname rather than by handle |
| 1008 | either because no valid, writeable file handle for | 1022 | either because no valid, writeable file handle for |
| @@ -1013,7 +1027,30 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1013 | cifs_sb->local_nls, | 1027 | cifs_sb->local_nls, |
| 1014 | cifs_sb->mnt_cifs_flags & | 1028 | cifs_sb->mnt_cifs_flags & |
| 1015 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1029 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1016 | cFYI(1, (" SetEOF by path (setattrs) rc = %d", rc)); | 1030 | cFYI(1, ("SetEOF by path (setattrs) rc = %d", rc)); |
| 1031 | if(rc == -EINVAL) { | ||
| 1032 | __u16 netfid; | ||
| 1033 | int oplock = FALSE; | ||
| 1034 | |||
| 1035 | rc = SMBLegacyOpen(xid, pTcon, full_path, | ||
| 1036 | FILE_OPEN, | ||
| 1037 | SYNCHRONIZE | FILE_WRITE_ATTRIBUTES, | ||
| 1038 | CREATE_NOT_DIR, &netfid, &oplock, | ||
| 1039 | NULL, cifs_sb->local_nls, | ||
| 1040 | cifs_sb->mnt_cifs_flags & | ||
| 1041 | CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 1042 | if (rc==0) { | ||
| 1043 | int bytes_written; | ||
| 1044 | rc = CIFSSMBWrite(xid, pTcon, | ||
| 1045 | netfid, 0, | ||
| 1046 | attrs->ia_size, | ||
| 1047 | &bytes_written, NULL, | ||
| 1048 | NULL, 1 /* 45 sec */); | ||
| 1049 | cFYI(1,("wrt seteof rc %d",rc)); | ||
| 1050 | CIFSSMBClose(xid, pTcon, netfid); | ||
| 1051 | } | ||
| 1052 | |||
| 1053 | } | ||
| 1017 | } | 1054 | } |
| 1018 | 1055 | ||
| 1019 | /* Server is ok setting allocation size implicitly - no need | 1056 | /* Server is ok setting allocation size implicitly - no need |
| @@ -1026,24 +1063,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1026 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); | 1063 | rc = vmtruncate(direntry->d_inode, attrs->ia_size); |
| 1027 | cifs_truncate_page(direntry->d_inode->i_mapping, | 1064 | cifs_truncate_page(direntry->d_inode->i_mapping, |
| 1028 | direntry->d_inode->i_size); | 1065 | direntry->d_inode->i_size); |
| 1029 | } | 1066 | } else |
| 1067 | goto cifs_setattr_exit; | ||
| 1030 | } | 1068 | } |
| 1031 | if (attrs->ia_valid & ATTR_UID) { | 1069 | if (attrs->ia_valid & ATTR_UID) { |
| 1032 | cFYI(1, (" CIFS - UID changed to %d", attrs->ia_uid)); | 1070 | cFYI(1, ("UID changed to %d", attrs->ia_uid)); |
| 1033 | uid = attrs->ia_uid; | 1071 | uid = attrs->ia_uid; |
| 1034 | /* entry->uid = cpu_to_le16(attr->ia_uid); */ | ||
| 1035 | } | 1072 | } |
| 1036 | if (attrs->ia_valid & ATTR_GID) { | 1073 | if (attrs->ia_valid & ATTR_GID) { |
| 1037 | cFYI(1, (" CIFS - GID changed to %d", attrs->ia_gid)); | 1074 | cFYI(1, ("GID changed to %d", attrs->ia_gid)); |
| 1038 | gid = attrs->ia_gid; | 1075 | gid = attrs->ia_gid; |
| 1039 | /* entry->gid = cpu_to_le16(attr->ia_gid); */ | ||
| 1040 | } | 1076 | } |
| 1041 | 1077 | ||
| 1042 | time_buf.Attributes = 0; | 1078 | time_buf.Attributes = 0; |
| 1043 | if (attrs->ia_valid & ATTR_MODE) { | 1079 | if (attrs->ia_valid & ATTR_MODE) { |
| 1044 | cFYI(1, (" CIFS - Mode changed to 0x%x", attrs->ia_mode)); | 1080 | cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); |
| 1045 | mode = attrs->ia_mode; | 1081 | mode = attrs->ia_mode; |
| 1046 | /* entry->mode = cpu_to_le16(attr->ia_mode); */ | ||
| 1047 | } | 1082 | } |
| 1048 | 1083 | ||
| 1049 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) | 1084 | if ((cifs_sb->tcon->ses->capabilities & CAP_UNIX) |
| @@ -1083,18 +1118,24 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1083 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); | 1118 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_mtime)); |
| 1084 | } else | 1119 | } else |
| 1085 | time_buf.LastWriteTime = 0; | 1120 | time_buf.LastWriteTime = 0; |
| 1086 | 1121 | /* Do not set ctime explicitly unless other time | |
| 1087 | if (attrs->ia_valid & ATTR_CTIME) { | 1122 | stamps are changed explicitly (i.e. by utime() |
| 1123 | since we would then have a mix of client and | ||
| 1124 | server times */ | ||
| 1125 | |||
| 1126 | if (set_time && (attrs->ia_valid & ATTR_CTIME)) { | ||
| 1088 | set_time = TRUE; | 1127 | set_time = TRUE; |
| 1089 | cFYI(1, (" CIFS - CTIME changed ")); /* BB probably no need */ | 1128 | /* Although Samba throws this field away |
| 1129 | it may be useful to Windows - but we do | ||
| 1130 | not want to set ctime unless some other | ||
| 1131 | timestamp is changing */ | ||
| 1132 | cFYI(1, ("CIFS - CTIME changed ")); | ||
| 1090 | time_buf.ChangeTime = | 1133 | time_buf.ChangeTime = |
| 1091 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); | 1134 | cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); |
| 1092 | } else | 1135 | } else |
| 1093 | time_buf.ChangeTime = 0; | 1136 | time_buf.ChangeTime = 0; |
| 1094 | 1137 | ||
| 1095 | if (set_time || time_buf.Attributes) { | 1138 | if (set_time || time_buf.Attributes) { |
| 1096 | /* BB what if setting one attribute fails (such as size) but | ||
| 1097 | time setting works? */ | ||
| 1098 | time_buf.CreationTime = 0; /* do not change */ | 1139 | time_buf.CreationTime = 0; /* do not change */ |
| 1099 | /* In the future we should experiment - try setting timestamps | 1140 | /* In the future we should experiment - try setting timestamps |
| 1100 | via Handle (SetFileInfo) instead of by path */ | 1141 | via Handle (SetFileInfo) instead of by path */ |
| @@ -1133,12 +1174,21 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) | |||
| 1133 | &time_buf, cifs_sb->local_nls); */ | 1174 | &time_buf, cifs_sb->local_nls); */ |
| 1134 | } | 1175 | } |
| 1135 | } | 1176 | } |
| 1177 | /* Even if error on time set, no sense failing the call if | ||
| 1178 | the server would set the time to a reasonable value anyway, | ||
| 1179 | and this check ensures that we are not being called from | ||
| 1180 | sys_utimes in which case we ought to fail the call back to | ||
| 1181 | the user when the server rejects the call */ | ||
| 1182 | if((rc) && (attrs->ia_valid && | ||
| 1183 | (ATTR_MODE | ATTR_GID | ATTR_UID | ATTR_SIZE))) | ||
| 1184 | rc = 0; | ||
| 1136 | } | 1185 | } |
| 1137 | 1186 | ||
| 1138 | /* do not need local check to inode_check_ok since the server does | 1187 | /* do not need local check to inode_check_ok since the server does |
| 1139 | that */ | 1188 | that */ |
| 1140 | if (!rc) | 1189 | if (!rc) |
| 1141 | rc = inode_setattr(direntry->d_inode, attrs); | 1190 | rc = inode_setattr(direntry->d_inode, attrs); |
| 1191 | cifs_setattr_exit: | ||
| 1142 | kfree(full_path); | 1192 | kfree(full_path); |
| 1143 | FreeXid(xid); | 1193 | FreeXid(xid); |
| 1144 | return rc; | 1194 | return rc; |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index ab925ef4f863..b43e071fe110 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
| @@ -198,7 +198,10 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) | |||
| 198 | ("Create symlink worked but get_inode_info failed with rc = %d ", | 198 | ("Create symlink worked but get_inode_info failed with rc = %d ", |
| 199 | rc)); | 199 | rc)); |
| 200 | } else { | 200 | } else { |
| 201 | direntry->d_op = &cifs_dentry_ops; | 201 | if (pTcon->nocase) |
| 202 | direntry->d_op = &cifs_ci_dentry_ops; | ||
| 203 | else | ||
| 204 | direntry->d_op = &cifs_dentry_ops; | ||
| 202 | d_instantiate(direntry, newinode); | 205 | d_instantiate(direntry, newinode); |
| 203 | } | 206 | } |
| 204 | } | 207 | } |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 20ae4153f791..eba1de917f2a 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -34,8 +34,6 @@ extern mempool_t *cifs_sm_req_poolp; | |||
| 34 | extern mempool_t *cifs_req_poolp; | 34 | extern mempool_t *cifs_req_poolp; |
| 35 | extern struct task_struct * oplockThread; | 35 | extern struct task_struct * oplockThread; |
| 36 | 36 | ||
| 37 | static __u16 GlobalMid; /* multiplex id - rotating counter */ | ||
| 38 | |||
| 39 | /* The xid serves as a useful identifier for each incoming vfs request, | 37 | /* The xid serves as a useful identifier for each incoming vfs request, |
| 40 | in a similar way to the mid which is useful to track each sent smb, | 38 | in a similar way to the mid which is useful to track each sent smb, |
| 41 | and CurrentXid can also provide a running counter (although it | 39 | and CurrentXid can also provide a running counter (although it |
| @@ -51,6 +49,8 @@ _GetXid(void) | |||
| 51 | GlobalTotalActiveXid++; | 49 | GlobalTotalActiveXid++; |
| 52 | if (GlobalTotalActiveXid > GlobalMaxActiveXid) | 50 | if (GlobalTotalActiveXid > GlobalMaxActiveXid) |
| 53 | GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ | 51 | GlobalMaxActiveXid = GlobalTotalActiveXid; /* keep high water mark for number of simultaneous vfs ops in our filesystem */ |
| 52 | if(GlobalTotalActiveXid > 65000) | ||
| 53 | cFYI(1,("warning: more than 65000 requests active")); | ||
| 54 | xid = GlobalCurrentXid++; | 54 | xid = GlobalCurrentXid++; |
| 55 | spin_unlock(&GlobalMid_Lock); | 55 | spin_unlock(&GlobalMid_Lock); |
| 56 | return xid; | 56 | return xid; |
| @@ -218,6 +218,76 @@ cifs_small_buf_release(void *buf_to_free) | |||
| 218 | return; | 218 | return; |
| 219 | } | 219 | } |
| 220 | 220 | ||
| 221 | /* | ||
| 222 | Find a free multiplex id (SMB mid). Otherwise there could be | ||
| 223 | mid collisions which might cause problems, demultiplexing the | ||
| 224 | wrong response to this request. Multiplex ids could collide if | ||
| 225 | one of a series requests takes much longer than the others, or | ||
| 226 | if a very large number of long lived requests (byte range | ||
| 227 | locks or FindNotify requests) are pending. No more than | ||
| 228 | 64K-1 requests can be outstanding at one time. If no | ||
| 229 | mids are available, return zero. A future optimization | ||
| 230 | could make the combination of mids and uid the key we use | ||
| 231 | to demultiplex on (rather than mid alone). | ||
| 232 | In addition to the above check, the cifs demultiplex | ||
| 233 | code already used the command code as a secondary | ||
| 234 | check of the frame and if signing is negotiated the | ||
| 235 | response would be discarded if the mid were the same | ||
| 236 | but the signature was wrong. Since the mid is not put in the | ||
| 237 | pending queue until later (when it is about to be dispatched) | ||
| 238 | we do have to limit the number of outstanding requests | ||
| 239 | to somewhat less than 64K-1 although it is hard to imagine | ||
| 240 | so many threads being in the vfs at one time. | ||
| 241 | */ | ||
| 242 | __u16 GetNextMid(struct TCP_Server_Info *server) | ||
| 243 | { | ||
| 244 | __u16 mid = 0; | ||
| 245 | __u16 last_mid; | ||
| 246 | int collision; | ||
| 247 | |||
| 248 | if(server == NULL) | ||
| 249 | return mid; | ||
| 250 | |||
| 251 | spin_lock(&GlobalMid_Lock); | ||
| 252 | last_mid = server->CurrentMid; /* we do not want to loop forever */ | ||
| 253 | server->CurrentMid++; | ||
| 254 | /* This nested loop looks more expensive than it is. | ||
| 255 | In practice the list of pending requests is short, | ||
| 256 | fewer than 50, and the mids are likely to be unique | ||
| 257 | on the first pass through the loop unless some request | ||
| 258 | takes longer than the 64 thousand requests before it | ||
| 259 | (and it would also have to have been a request that | ||
| 260 | did not time out) */ | ||
| 261 | while(server->CurrentMid != last_mid) { | ||
| 262 | struct list_head *tmp; | ||
| 263 | struct mid_q_entry *mid_entry; | ||
| 264 | |||
| 265 | collision = 0; | ||
| 266 | if(server->CurrentMid == 0) | ||
| 267 | server->CurrentMid++; | ||
| 268 | |||
| 269 | list_for_each(tmp, &server->pending_mid_q) { | ||
| 270 | mid_entry = list_entry(tmp, struct mid_q_entry, qhead); | ||
| 271 | |||
| 272 | if ((mid_entry->mid == server->CurrentMid) && | ||
| 273 | (mid_entry->midState == MID_REQUEST_SUBMITTED)) { | ||
| 274 | /* This mid is in use, try a different one */ | ||
| 275 | collision = 1; | ||
| 276 | break; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | if(collision == 0) { | ||
| 280 | mid = server->CurrentMid; | ||
| 281 | break; | ||
| 282 | } | ||
| 283 | server->CurrentMid++; | ||
| 284 | } | ||
| 285 | spin_unlock(&GlobalMid_Lock); | ||
| 286 | return mid; | ||
| 287 | } | ||
| 288 | |||
| 289 | /* NB: MID can not be set if treeCon not passed in, in that | ||
| 290 | case it is responsbility of caller to set the mid */ | ||
| 221 | void | 291 | void |
| 222 | header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | 292 | header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , |
| 223 | const struct cifsTconInfo *treeCon, int word_count | 293 | const struct cifsTconInfo *treeCon, int word_count |
| @@ -233,7 +303,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
| 233 | (2 * word_count) + sizeof (struct smb_hdr) - | 303 | (2 * word_count) + sizeof (struct smb_hdr) - |
| 234 | 4 /* RFC 1001 length field does not count */ + | 304 | 4 /* RFC 1001 length field does not count */ + |
| 235 | 2 /* for bcc field itself */ ; | 305 | 2 /* for bcc field itself */ ; |
| 236 | /* Note that this is the only network field that has to be converted to big endian and it is done just before we send it */ | 306 | /* Note that this is the only network field that has to be converted |
| 307 | to big endian and it is done just before we send it */ | ||
| 237 | 308 | ||
| 238 | buffer->Protocol[0] = 0xFF; | 309 | buffer->Protocol[0] = 0xFF; |
| 239 | buffer->Protocol[1] = 'S'; | 310 | buffer->Protocol[1] = 'S'; |
| @@ -245,8 +316,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
| 245 | buffer->Pid = cpu_to_le16((__u16)current->tgid); | 316 | buffer->Pid = cpu_to_le16((__u16)current->tgid); |
| 246 | buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); | 317 | buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16)); |
| 247 | spin_lock(&GlobalMid_Lock); | 318 | spin_lock(&GlobalMid_Lock); |
| 248 | GlobalMid++; | ||
| 249 | buffer->Mid = GlobalMid; | ||
| 250 | spin_unlock(&GlobalMid_Lock); | 319 | spin_unlock(&GlobalMid_Lock); |
| 251 | if (treeCon) { | 320 | if (treeCon) { |
| 252 | buffer->Tid = treeCon->tid; | 321 | buffer->Tid = treeCon->tid; |
| @@ -256,8 +325,9 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
| 256 | if (treeCon->ses->capabilities & CAP_STATUS32) { | 325 | if (treeCon->ses->capabilities & CAP_STATUS32) { |
| 257 | buffer->Flags2 |= SMBFLG2_ERR_STATUS; | 326 | buffer->Flags2 |= SMBFLG2_ERR_STATUS; |
| 258 | } | 327 | } |
| 259 | 328 | /* Uid is not converted */ | |
| 260 | buffer->Uid = treeCon->ses->Suid; /* always in LE format */ | 329 | buffer->Uid = treeCon->ses->Suid; |
| 330 | buffer->Mid = GetNextMid(treeCon->ses->server); | ||
| 261 | if(multiuser_mount != 0) { | 331 | if(multiuser_mount != 0) { |
| 262 | /* For the multiuser case, there are few obvious technically */ | 332 | /* For the multiuser case, there are few obvious technically */ |
| 263 | /* possible mechanisms to match the local linux user (uid) */ | 333 | /* possible mechanisms to match the local linux user (uid) */ |
| @@ -305,6 +375,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , | |||
| 305 | } | 375 | } |
| 306 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) | 376 | if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) |
| 307 | buffer->Flags2 |= SMBFLG2_DFS; | 377 | buffer->Flags2 |= SMBFLG2_DFS; |
| 378 | if (treeCon->nocase) | ||
| 379 | buffer->Flags |= SMBFLG_CASELESS; | ||
| 308 | if((treeCon->ses) && (treeCon->ses->server)) | 380 | if((treeCon->ses) && (treeCon->ses->server)) |
| 309 | if(treeCon->ses->server->secMode & | 381 | if(treeCon->ses->server->secMode & |
| 310 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | 382 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) |
| @@ -347,7 +419,8 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) | |||
| 347 | int | 419 | int |
| 348 | checkSMB(struct smb_hdr *smb, __u16 mid, int length) | 420 | checkSMB(struct smb_hdr *smb, __u16 mid, int length) |
| 349 | { | 421 | { |
| 350 | __u32 len = be32_to_cpu(smb->smb_buf_length); | 422 | __u32 len = smb->smb_buf_length; |
| 423 | __u32 clc_len; /* calculated length */ | ||
| 351 | cFYI(0, | 424 | cFYI(0, |
| 352 | ("Entering checkSMB with Length: %x, smb_buf_length: %x ", | 425 | ("Entering checkSMB with Length: %x, smb_buf_length: %x ", |
| 353 | length, len)); | 426 | length, len)); |
| @@ -368,23 +441,29 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) | |||
| 368 | cERROR(1, | 441 | cERROR(1, |
| 369 | ("smb_buf_length greater than MaxBufSize")); | 442 | ("smb_buf_length greater than MaxBufSize")); |
| 370 | cERROR(1, | 443 | cERROR(1, |
| 371 | ("bad smb detected. Illegal length. The mid=%d", | 444 | ("bad smb detected. Illegal length. mid=%d", |
| 372 | smb->Mid)); | 445 | smb->Mid)); |
| 373 | return 1; | 446 | return 1; |
| 374 | } | 447 | } |
| 375 | 448 | ||
| 376 | if (checkSMBhdr(smb, mid)) | 449 | if (checkSMBhdr(smb, mid)) |
| 377 | return 1; | 450 | return 1; |
| 378 | 451 | clc_len = smbCalcSize_LE(smb); | |
| 379 | if ((4 + len != smbCalcSize(smb)) | 452 | if ((4 + len != clc_len) |
| 380 | || (4 + len != (unsigned int)length)) { | 453 | || (4 + len != (unsigned int)length)) { |
| 381 | return 0; | 454 | cERROR(1, ("Calculated size 0x%x vs actual length 0x%x", |
| 382 | } else { | 455 | clc_len, 4 + len)); |
| 383 | cERROR(1, ("smbCalcSize %x ", smbCalcSize(smb))); | 456 | cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid)); |
| 384 | cERROR(1, | 457 | /* Windows XP can return a few bytes too much, presumably |
| 385 | ("bad smb size detected. The Mid=%d", smb->Mid)); | 458 | an illegal pad, at the end of byte range lock responses |
| 386 | return 1; | 459 | so we allow for up to eight byte pad, as long as actual |
| 460 | received length is as long or longer than calculated length */ | ||
| 461 | if((4+len > clc_len) && (len <= clc_len + 3)) | ||
| 462 | return 0; | ||
| 463 | else | ||
| 464 | return 1; | ||
| 387 | } | 465 | } |
| 466 | return 0; | ||
| 388 | } | 467 | } |
| 389 | int | 468 | int |
| 390 | is_valid_oplock_break(struct smb_hdr *buf) | 469 | is_valid_oplock_break(struct smb_hdr *buf) |
| @@ -448,9 +527,7 @@ is_valid_oplock_break(struct smb_hdr *buf) | |||
| 448 | list_for_each(tmp, &GlobalTreeConnectionList) { | 527 | list_for_each(tmp, &GlobalTreeConnectionList) { |
| 449 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 528 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); |
| 450 | if (tcon->tid == buf->Tid) { | 529 | if (tcon->tid == buf->Tid) { |
| 451 | #ifdef CONFIG_CIFS_STATS | 530 | cifs_stats_inc(&tcon->num_oplock_brks); |
| 452 | atomic_inc(&tcon->num_oplock_brks); | ||
| 453 | #endif | ||
| 454 | list_for_each(tmp1,&tcon->openFileList){ | 531 | list_for_each(tmp1,&tcon->openFileList){ |
| 455 | netfile = list_entry(tmp1,struct cifsFileInfo, | 532 | netfile = list_entry(tmp1,struct cifsFileInfo, |
| 456 | tlist); | 533 | tlist); |
| @@ -603,6 +680,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, | |||
| 603 | int i,j,charlen; | 680 | int i,j,charlen; |
| 604 | int len_remaining = maxlen; | 681 | int len_remaining = maxlen; |
| 605 | char src_char; | 682 | char src_char; |
| 683 | __u16 temp; | ||
| 606 | 684 | ||
| 607 | if(!mapChars) | 685 | if(!mapChars) |
| 608 | return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); | 686 | return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); |
| @@ -639,13 +717,14 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, | |||
| 639 | break;*/ | 717 | break;*/ |
| 640 | default: | 718 | default: |
| 641 | charlen = cp->char2uni(source+i, | 719 | charlen = cp->char2uni(source+i, |
| 642 | len_remaining, target+j); | 720 | len_remaining, &temp); |
| 643 | /* if no match, use question mark, which | 721 | /* if no match, use question mark, which |
| 644 | at least in some cases servers as wild card */ | 722 | at least in some cases servers as wild card */ |
| 645 | if(charlen < 1) { | 723 | if(charlen < 1) { |
| 646 | target[j] = cpu_to_le16(0x003f); | 724 | target[j] = cpu_to_le16(0x003f); |
| 647 | charlen = 1; | 725 | charlen = 1; |
| 648 | } | 726 | } else |
| 727 | target[j] = cpu_to_le16(temp); | ||
| 649 | len_remaining -= charlen; | 728 | len_remaining -= charlen; |
| 650 | /* character may take more than one byte in the | 729 | /* character may take more than one byte in the |
| 651 | the source string, but will take exactly two | 730 | the source string, but will take exactly two |
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index a92af41d4411..f7814689844b 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c | |||
| @@ -133,7 +133,6 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = { | |||
| 133 | int | 133 | int |
| 134 | cifs_inet_pton(int address_family, char *cp,void *dst) | 134 | cifs_inet_pton(int address_family, char *cp,void *dst) |
| 135 | { | 135 | { |
| 136 | struct in_addr address; | ||
| 137 | int value; | 136 | int value; |
| 138 | int digit; | 137 | int digit; |
| 139 | int i; | 138 | int i; |
| @@ -190,8 +189,7 @@ cifs_inet_pton(int address_family, char *cp,void *dst) | |||
| 190 | if (value > addr_class_max[end - bytes]) | 189 | if (value > addr_class_max[end - bytes]) |
| 191 | return 0; | 190 | return 0; |
| 192 | 191 | ||
| 193 | address.s_addr = *((__be32 *) bytes) | htonl(value); | 192 | *((__be32 *)dst) = *((__be32 *) bytes) | htonl(value); |
| 194 | *((__be32 *)dst) = address.s_addr; | ||
| 195 | return 1; /* success */ | 193 | return 1; /* success */ |
| 196 | } | 194 | } |
| 197 | 195 | ||
| @@ -815,7 +813,7 @@ map_smb_to_linux_error(struct smb_hdr *smb) | |||
| 815 | if (smb->Flags2 & SMBFLG2_ERR_STATUS) { | 813 | if (smb->Flags2 & SMBFLG2_ERR_STATUS) { |
| 816 | /* translate the newer STATUS codes to old style errors and then to POSIX errors */ | 814 | /* translate the newer STATUS codes to old style errors and then to POSIX errors */ |
| 817 | __u32 err = le32_to_cpu(smb->Status.CifsError); | 815 | __u32 err = le32_to_cpu(smb->Status.CifsError); |
| 818 | if(cifsFYI) | 816 | if(cifsFYI & CIFS_RC) |
| 819 | cifs_print_status(err); | 817 | cifs_print_status(err); |
| 820 | ntstatus_to_dos(err, &smberrclass, &smberrcode); | 818 | ntstatus_to_dos(err, &smberrclass, &smberrcode); |
| 821 | } else { | 819 | } else { |
| @@ -870,7 +868,14 @@ unsigned int | |||
| 870 | smbCalcSize(struct smb_hdr *ptr) | 868 | smbCalcSize(struct smb_hdr *ptr) |
| 871 | { | 869 | { |
| 872 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + | 870 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + |
| 873 | BCC(ptr)); | 871 | 2 /* size of the bcc field */ + BCC(ptr)); |
| 872 | } | ||
| 873 | |||
| 874 | unsigned int | ||
| 875 | smbCalcSize_LE(struct smb_hdr *ptr) | ||
| 876 | { | ||
| 877 | return (sizeof (struct smb_hdr) + (2 * ptr->WordCount) + | ||
| 878 | 2 /* size of the bcc field */ + le16_to_cpu(BCC_LE(ptr))); | ||
| 874 | } | 879 | } |
| 875 | 880 | ||
| 876 | /* The following are taken from fs/ntfs/util.c */ | 881 | /* The following are taken from fs/ntfs/util.c */ |
diff --git a/fs/cifs/ntlmssp.h b/fs/cifs/ntlmssp.h index 6facb41117a3..803389b64a2c 100644 --- a/fs/cifs/ntlmssp.h +++ b/fs/cifs/ntlmssp.h | |||
| @@ -19,8 +19,6 @@ | |||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | #pragma pack(1) | ||
| 23 | |||
| 24 | #define NTLMSSP_SIGNATURE "NTLMSSP" | 22 | #define NTLMSSP_SIGNATURE "NTLMSSP" |
| 25 | /* Message Types */ | 23 | /* Message Types */ |
| 26 | #define NtLmNegotiate cpu_to_le32(1) | 24 | #define NtLmNegotiate cpu_to_le32(1) |
| @@ -63,7 +61,7 @@ typedef struct _SECURITY_BUFFER { | |||
| 63 | __le16 Length; | 61 | __le16 Length; |
| 64 | __le16 MaximumLength; | 62 | __le16 MaximumLength; |
| 65 | __le32 Buffer; /* offset to buffer */ | 63 | __le32 Buffer; /* offset to buffer */ |
| 66 | } SECURITY_BUFFER; | 64 | } __attribute__((packed)) SECURITY_BUFFER; |
| 67 | 65 | ||
| 68 | typedef struct _NEGOTIATE_MESSAGE { | 66 | typedef struct _NEGOTIATE_MESSAGE { |
| 69 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | 67 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; |
| @@ -73,7 +71,7 @@ typedef struct _NEGOTIATE_MESSAGE { | |||
| 73 | SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ | 71 | SECURITY_BUFFER WorkstationName; /* RFC 1001 and ASCII */ |
| 74 | char DomainString[0]; | 72 | char DomainString[0]; |
| 75 | /* followed by WorkstationString */ | 73 | /* followed by WorkstationString */ |
| 76 | } NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; | 74 | } __attribute__((packed)) NEGOTIATE_MESSAGE, *PNEGOTIATE_MESSAGE; |
| 77 | 75 | ||
| 78 | typedef struct _CHALLENGE_MESSAGE { | 76 | typedef struct _CHALLENGE_MESSAGE { |
| 79 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | 77 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; |
| @@ -83,7 +81,7 @@ typedef struct _CHALLENGE_MESSAGE { | |||
| 83 | __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; | 81 | __u8 Challenge[CIFS_CRYPTO_KEY_SIZE]; |
| 84 | __u8 Reserved[8]; | 82 | __u8 Reserved[8]; |
| 85 | SECURITY_BUFFER TargetInfoArray; | 83 | SECURITY_BUFFER TargetInfoArray; |
| 86 | } CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; | 84 | } __attribute__((packed)) CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; |
| 87 | 85 | ||
| 88 | typedef struct _AUTHENTICATE_MESSAGE { | 86 | typedef struct _AUTHENTICATE_MESSAGE { |
| 89 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; | 87 | __u8 Signature[sizeof (NTLMSSP_SIGNATURE)]; |
| @@ -96,6 +94,4 @@ typedef struct _AUTHENTICATE_MESSAGE { | |||
| 96 | SECURITY_BUFFER SessionKey; | 94 | SECURITY_BUFFER SessionKey; |
| 97 | __le32 NegotiateFlags; | 95 | __le32 NegotiateFlags; |
| 98 | char UserString[0]; | 96 | char UserString[0]; |
| 99 | } AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; | 97 | } __attribute__((packed)) AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; |
| 100 | |||
| 101 | #pragma pack() /* resume default structure packing */ | ||
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 22557716f9af..a86bd1c07602 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c | |||
| @@ -91,7 +91,10 @@ static int construct_dentry(struct qstr *qstring, struct file *file, | |||
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | *ptmp_inode = new_inode(file->f_dentry->d_sb); | 93 | *ptmp_inode = new_inode(file->f_dentry->d_sb); |
| 94 | tmp_dentry->d_op = &cifs_dentry_ops; | 94 | if (pTcon->nocase) |
| 95 | tmp_dentry->d_op = &cifs_ci_dentry_ops; | ||
| 96 | else | ||
| 97 | tmp_dentry->d_op = &cifs_dentry_ops; | ||
| 95 | if(*ptmp_inode == NULL) | 98 | if(*ptmp_inode == NULL) |
| 96 | return rc; | 99 | return rc; |
| 97 | rc = 1; | 100 | rc = 1; |
| @@ -148,6 +151,13 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
| 148 | tmp_inode->i_mode = cifs_sb->mnt_dir_mode; | 151 | tmp_inode->i_mode = cifs_sb->mnt_dir_mode; |
| 149 | } | 152 | } |
| 150 | tmp_inode->i_mode |= S_IFDIR; | 153 | tmp_inode->i_mode |= S_IFDIR; |
| 154 | } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
| 155 | (attr & ATTR_SYSTEM) && (end_of_file == 0)) { | ||
| 156 | *pobject_type = DT_FIFO; | ||
| 157 | tmp_inode->i_mode |= S_IFIFO; | ||
| 158 | /* BB Finish for SFU style symlinks and devies */ | ||
| 159 | /* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && | ||
| 160 | (attr & ATTR_SYSTEM) && ) { */ | ||
| 151 | /* we no longer mark these because we could not follow them */ | 161 | /* we no longer mark these because we could not follow them */ |
| 152 | /* } else if (attr & ATTR_REPARSE) { | 162 | /* } else if (attr & ATTR_REPARSE) { |
| 153 | *pobject_type = DT_LNK; | 163 | *pobject_type = DT_LNK; |
| @@ -187,11 +197,17 @@ static void fill_in_inode(struct inode *tmp_inode, | |||
| 187 | tmp_inode->i_fop = &cifs_file_direct_ops; | 197 | tmp_inode->i_fop = &cifs_file_direct_ops; |
| 188 | else | 198 | else |
| 189 | tmp_inode->i_fop = &cifs_file_ops; | 199 | tmp_inode->i_fop = &cifs_file_ops; |
| 200 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 201 | tmp_inode->i_fop->lock = NULL; | ||
| 190 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 202 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
| 191 | 203 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | |
| 204 | (cifs_sb->tcon->ses->server->maxBuf < | ||
| 205 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
| 206 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
| 192 | if(isNewInode) | 207 | if(isNewInode) |
| 193 | return; /* No sense invalidating pages for new inode since we | 208 | return; /* No sense invalidating pages for new inode |
| 194 | have not started caching readahead file data yet */ | 209 | since have not started caching readahead file |
| 210 | data yet */ | ||
| 195 | 211 | ||
| 196 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && | 212 | if (timespec_equal(&tmp_inode->i_mtime, &local_mtime) && |
| 197 | (local_size == tmp_inode->i_size)) { | 213 | (local_size == tmp_inode->i_size)) { |
| @@ -290,7 +306,13 @@ static void unix_fill_in_inode(struct inode *tmp_inode, | |||
| 290 | tmp_inode->i_fop = &cifs_file_direct_ops; | 306 | tmp_inode->i_fop = &cifs_file_direct_ops; |
| 291 | else | 307 | else |
| 292 | tmp_inode->i_fop = &cifs_file_ops; | 308 | tmp_inode->i_fop = &cifs_file_ops; |
| 309 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) | ||
| 310 | tmp_inode->i_fop->lock = NULL; | ||
| 293 | tmp_inode->i_data.a_ops = &cifs_addr_ops; | 311 | tmp_inode->i_data.a_ops = &cifs_addr_ops; |
| 312 | if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && | ||
| 313 | (cifs_sb->tcon->ses->server->maxBuf < | ||
| 314 | 4096 + MAX_CIFS_HDR_SIZE)) | ||
| 315 | tmp_inode->i_data.a_ops->readpages = NULL; | ||
| 294 | 316 | ||
| 295 | if(isNewInode) | 317 | if(isNewInode) |
| 296 | return; /* No sense invalidating pages for new inode since we | 318 | return; /* No sense invalidating pages for new inode since we |
| @@ -374,7 +396,8 @@ ffirst_retry: | |||
| 374 | 396 | ||
| 375 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, | 397 | rc = CIFSFindFirst(xid, pTcon,full_path,cifs_sb->local_nls, |
| 376 | &cifsFile->netfid, &cifsFile->srch_inf, | 398 | &cifsFile->netfid, &cifsFile->srch_inf, |
| 377 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | 399 | cifs_sb->mnt_cifs_flags & |
| 400 | CIFS_MOUNT_MAP_SPECIAL_CHR, CIFS_DIR_SEP(cifs_sb)); | ||
| 378 | if(rc == 0) | 401 | if(rc == 0) |
| 379 | cifsFile->invalidHandle = FALSE; | 402 | cifsFile->invalidHandle = FALSE; |
| 380 | if((rc == -EOPNOTSUPP) && | 403 | if((rc == -EOPNOTSUPP) && |
| @@ -491,6 +514,30 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) | |||
| 491 | return rc; | 514 | return rc; |
| 492 | } | 515 | } |
| 493 | 516 | ||
| 517 | /* Check if directory that we are searching has changed so we can decide | ||
| 518 | whether we can use the cached search results from the previous search */ | ||
| 519 | static int is_dir_changed(struct file * file) | ||
| 520 | { | ||
| 521 | struct inode * inode; | ||
| 522 | struct cifsInodeInfo *cifsInfo; | ||
| 523 | |||
| 524 | if(file->f_dentry == NULL) | ||
| 525 | return 0; | ||
| 526 | |||
| 527 | inode = file->f_dentry->d_inode; | ||
| 528 | |||
| 529 | if(inode == NULL) | ||
| 530 | return 0; | ||
| 531 | |||
| 532 | cifsInfo = CIFS_I(inode); | ||
| 533 | |||
| 534 | if(cifsInfo->time == 0) | ||
| 535 | return 1; /* directory was changed, perhaps due to unlink */ | ||
| 536 | else | ||
| 537 | return 0; | ||
| 538 | |||
| 539 | } | ||
| 540 | |||
| 494 | /* find the corresponding entry in the search */ | 541 | /* find the corresponding entry in the search */ |
| 495 | /* Note that the SMB server returns search entries for . and .. which | 542 | /* Note that the SMB server returns search entries for . and .. which |
| 496 | complicates logic here if we choose to parse for them and we do not | 543 | complicates logic here if we choose to parse for them and we do not |
| @@ -507,7 +554,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 507 | struct cifsFileInfo * cifsFile = file->private_data; | 554 | struct cifsFileInfo * cifsFile = file->private_data; |
| 508 | /* check if index in the buffer */ | 555 | /* check if index in the buffer */ |
| 509 | 556 | ||
| 510 | if((cifsFile == NULL) || (ppCurrentEntry == NULL) || (num_to_ret == NULL)) | 557 | if((cifsFile == NULL) || (ppCurrentEntry == NULL) || |
| 558 | (num_to_ret == NULL)) | ||
| 511 | return -ENOENT; | 559 | return -ENOENT; |
| 512 | 560 | ||
| 513 | *ppCurrentEntry = NULL; | 561 | *ppCurrentEntry = NULL; |
| @@ -515,7 +563,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 515 | cifsFile->srch_inf.index_of_last_entry - | 563 | cifsFile->srch_inf.index_of_last_entry - |
| 516 | cifsFile->srch_inf.entries_in_buffer; | 564 | cifsFile->srch_inf.entries_in_buffer; |
| 517 | /* dump_cifs_file_struct(file, "In fce ");*/ | 565 | /* dump_cifs_file_struct(file, "In fce ");*/ |
| 518 | if(index_to_find < first_entry_in_buffer) { | 566 | if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && |
| 567 | is_dir_changed(file)) || | ||
| 568 | (index_to_find < first_entry_in_buffer)) { | ||
| 519 | /* close and restart search */ | 569 | /* close and restart search */ |
| 520 | cFYI(1,("search backing up - close and restart search")); | 570 | cFYI(1,("search backing up - close and restart search")); |
| 521 | cifsFile->invalidHandle = TRUE; | 571 | cifsFile->invalidHandle = TRUE; |
| @@ -536,7 +586,8 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 536 | while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && | 586 | while((index_to_find >= cifsFile->srch_inf.index_of_last_entry) && |
| 537 | (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ | 587 | (rc == 0) && (cifsFile->srch_inf.endOfSearch == FALSE)){ |
| 538 | cFYI(1,("calling findnext2")); | 588 | cFYI(1,("calling findnext2")); |
| 539 | rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, &cifsFile->srch_inf); | 589 | rc = CIFSFindNext(xid,pTcon,cifsFile->netfid, |
| 590 | &cifsFile->srch_inf); | ||
| 540 | if(rc) | 591 | if(rc) |
| 541 | return -ENOENT; | 592 | return -ENOENT; |
| 542 | } | 593 | } |
| @@ -548,14 +599,13 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 548 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + | 599 | char * end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + |
| 549 | smbCalcSize((struct smb_hdr *) | 600 | smbCalcSize((struct smb_hdr *) |
| 550 | cifsFile->srch_inf.ntwrk_buf_start); | 601 | cifsFile->srch_inf.ntwrk_buf_start); |
| 551 | /* dump_cifs_file_struct(file,"found entry in fce "); */ | ||
| 552 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry | 602 | first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry |
| 553 | - cifsFile->srch_inf.entries_in_buffer; | 603 | - cifsFile->srch_inf.entries_in_buffer; |
| 554 | pos_in_buf = index_to_find - first_entry_in_buffer; | 604 | pos_in_buf = index_to_find - first_entry_in_buffer; |
| 555 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); | 605 | cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); |
| 556 | current_entry = cifsFile->srch_inf.srch_entries_start; | 606 | current_entry = cifsFile->srch_inf.srch_entries_start; |
| 557 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { | 607 | for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { |
| 558 | /* go entry to next entry figuring out which we need to start with */ | 608 | /* go entry by entry figuring out which is first */ |
| 559 | /* if( . or ..) | 609 | /* if( . or ..) |
| 560 | skip */ | 610 | skip */ |
| 561 | rc = cifs_entry_is_dot(current_entry,cifsFile); | 611 | rc = cifs_entry_is_dot(current_entry,cifsFile); |
| @@ -582,11 +632,10 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, | |||
| 582 | } | 632 | } |
| 583 | 633 | ||
| 584 | if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { | 634 | if(pos_in_buf >= cifsFile->srch_inf.entries_in_buffer) { |
| 585 | cFYI(1,("can not return entries when pos_in_buf beyond last entry")); | 635 | cFYI(1,("can not return entries pos_in_buf beyond last entry")); |
| 586 | *num_to_ret = 0; | 636 | *num_to_ret = 0; |
| 587 | } else | 637 | } else |
| 588 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; | 638 | *num_to_ret = cifsFile->srch_inf.entries_in_buffer - pos_in_buf; |
| 589 | /* dump_cifs_file_struct(file, "end fce ");*/ | ||
| 590 | 639 | ||
| 591 | return rc; | 640 | return rc; |
| 592 | } | 641 | } |
| @@ -721,7 +770,8 @@ static int cifs_filldir(char *pfindEntry, struct file *file, | |||
| 721 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); | 770 | (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); |
| 722 | } | 771 | } |
| 723 | 772 | ||
| 724 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos,tmp_inode->i_ino,obj_type); | 773 | rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, |
| 774 | tmp_inode->i_ino,obj_type); | ||
| 725 | if(rc) { | 775 | if(rc) { |
| 726 | cFYI(1,("filldir rc = %d",rc)); | 776 | cFYI(1,("filldir rc = %d",rc)); |
| 727 | } | 777 | } |
| @@ -805,15 +855,12 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 805 | FreeXid(xid); | 855 | FreeXid(xid); |
| 806 | return -EIO; | 856 | return -EIO; |
| 807 | } | 857 | } |
| 808 | /* dump_cifs_file_struct(file, "Begin rdir "); */ | ||
| 809 | 858 | ||
| 810 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); | 859 | cifs_sb = CIFS_SB(file->f_dentry->d_sb); |
| 811 | pTcon = cifs_sb->tcon; | 860 | pTcon = cifs_sb->tcon; |
| 812 | if(pTcon == NULL) | 861 | if(pTcon == NULL) |
| 813 | return -EINVAL; | 862 | return -EINVAL; |
| 814 | 863 | ||
| 815 | /* cFYI(1,("readdir2 pos: %lld",file->f_pos)); */ | ||
| 816 | |||
| 817 | switch ((int) file->f_pos) { | 864 | switch ((int) file->f_pos) { |
| 818 | case 0: | 865 | case 0: |
| 819 | /*if (filldir(direntry, ".", 1, file->f_pos, | 866 | /*if (filldir(direntry, ".", 1, file->f_pos, |
| @@ -866,7 +913,6 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 866 | cifsFile->search_resume_name = NULL; */ | 913 | cifsFile->search_resume_name = NULL; */ |
| 867 | 914 | ||
| 868 | /* BB account for . and .. in f_pos as special case */ | 915 | /* BB account for . and .. in f_pos as special case */ |
| 869 | /* dump_cifs_file_struct(file, "rdir after default ");*/ | ||
| 870 | 916 | ||
| 871 | rc = find_cifs_entry(xid,pTcon, file, | 917 | rc = find_cifs_entry(xid,pTcon, file, |
| 872 | ¤t_entry,&num_to_fill); | 918 | ¤t_entry,&num_to_fill); |
| @@ -906,14 +952,14 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) | |||
| 906 | cifs_save_resume_key(current_entry,cifsFile); | 952 | cifs_save_resume_key(current_entry,cifsFile); |
| 907 | break; | 953 | break; |
| 908 | } else | 954 | } else |
| 909 | current_entry = nxt_dir_entry(current_entry,end_of_smb); | 955 | current_entry = nxt_dir_entry(current_entry, |
| 956 | end_of_smb); | ||
| 910 | } | 957 | } |
| 911 | kfree(tmp_buf); | 958 | kfree(tmp_buf); |
| 912 | break; | 959 | break; |
| 913 | } /* end switch */ | 960 | } /* end switch */ |
| 914 | 961 | ||
| 915 | rddir2_exit: | 962 | rddir2_exit: |
| 916 | /* dump_cifs_file_struct(file, "end rdir "); */ | ||
| 917 | FreeXid(xid); | 963 | FreeXid(xid); |
| 918 | return rc; | 964 | return rc; |
| 919 | } | 965 | } |
diff --git a/fs/cifs/rfc1002pdu.h b/fs/cifs/rfc1002pdu.h index 806c0ed06da9..9222033cad8e 100644 --- a/fs/cifs/rfc1002pdu.h +++ b/fs/cifs/rfc1002pdu.h | |||
| @@ -21,8 +21,6 @@ | |||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #pragma pack(1) | ||
| 25 | |||
| 26 | /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ | 24 | /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ |
| 27 | 25 | ||
| 28 | /* RFC 1002 session packet types */ | 26 | /* RFC 1002 session packet types */ |
| @@ -48,17 +46,17 @@ struct rfc1002_session_packet { | |||
| 48 | __u8 calling_len; | 46 | __u8 calling_len; |
| 49 | __u8 calling_name[32]; | 47 | __u8 calling_name[32]; |
| 50 | __u8 scope2; /* null */ | 48 | __u8 scope2; /* null */ |
| 51 | } session_req; | 49 | } __attribute__((packed)) session_req; |
| 52 | struct { | 50 | struct { |
| 53 | __u32 retarget_ip_addr; | 51 | __u32 retarget_ip_addr; |
| 54 | __u16 port; | 52 | __u16 port; |
| 55 | } retarget_resp; | 53 | } __attribute__((packed)) retarget_resp; |
| 56 | __u8 neg_ses_resp_error_code; | 54 | __u8 neg_ses_resp_error_code; |
| 57 | /* POSITIVE_SESSION_RESPONSE packet does not include trailer. | 55 | /* POSITIVE_SESSION_RESPONSE packet does not include trailer. |
| 58 | SESSION_KEEP_ALIVE packet also does not include a trailer. | 56 | SESSION_KEEP_ALIVE packet also does not include a trailer. |
| 59 | Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ | 57 | Trailer for the SESSION_MESSAGE packet is SMB/CIFS header */ |
| 60 | } trailer; | 58 | } __attribute__((packed)) trailer; |
| 61 | }; | 59 | } __attribute__((packed)); |
| 62 | 60 | ||
| 63 | /* Negative Session Response error codes */ | 61 | /* Negative Session Response error codes */ |
| 64 | #define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ | 62 | #define RFC1002_NOT_LISTENING_CALLED 0x80 /* not listening on called name */ |
| @@ -74,6 +72,3 @@ server netbios name). Currently server names are resolved only via DNS | |||
| 74 | (tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/ | 72 | (tcp name) or ip address or an /etc/hosts equivalent mapping to ip address.*/ |
| 75 | 73 | ||
| 76 | #define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER " | 74 | #define DEFAULT_CIFS_CALLED_NAME "*SMBSERVER " |
| 77 | |||
| 78 | #pragma pack() /* resume default structure packing */ | ||
| 79 | |||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0046c219833d..981ea0d8b9cd 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
| @@ -49,7 +49,8 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
| 49 | return NULL; | 49 | return NULL; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp,SLAB_KERNEL | SLAB_NOFS); | 52 | temp = (struct mid_q_entry *) mempool_alloc(cifs_mid_poolp, |
| 53 | SLAB_KERNEL | SLAB_NOFS); | ||
| 53 | if (temp == NULL) | 54 | if (temp == NULL) |
| 54 | return temp; | 55 | return temp; |
| 55 | else { | 56 | else { |
| @@ -58,7 +59,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
| 58 | temp->pid = current->pid; | 59 | temp->pid = current->pid; |
| 59 | temp->command = smb_buffer->Command; | 60 | temp->command = smb_buffer->Command; |
| 60 | cFYI(1, ("For smb_command %d", temp->command)); | 61 | cFYI(1, ("For smb_command %d", temp->command)); |
| 61 | do_gettimeofday(&temp->when_sent); | 62 | /* do_gettimeofday(&temp->when_sent);*/ /* easier to use jiffies */ |
| 63 | /* when mid allocated can be before when sent */ | ||
| 64 | temp->when_alloc = jiffies; | ||
| 62 | temp->ses = ses; | 65 | temp->ses = ses; |
| 63 | temp->tsk = current; | 66 | temp->tsk = current; |
| 64 | } | 67 | } |
| @@ -74,6 +77,9 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) | |||
| 74 | static void | 77 | static void |
| 75 | DeleteMidQEntry(struct mid_q_entry *midEntry) | 78 | DeleteMidQEntry(struct mid_q_entry *midEntry) |
| 76 | { | 79 | { |
| 80 | #ifdef CONFIG_CIFS_STATS2 | ||
| 81 | unsigned long now; | ||
| 82 | #endif | ||
| 77 | spin_lock(&GlobalMid_Lock); | 83 | spin_lock(&GlobalMid_Lock); |
| 78 | midEntry->midState = MID_FREE; | 84 | midEntry->midState = MID_FREE; |
| 79 | list_del(&midEntry->qhead); | 85 | list_del(&midEntry->qhead); |
| @@ -83,6 +89,22 @@ DeleteMidQEntry(struct mid_q_entry *midEntry) | |||
| 83 | cifs_buf_release(midEntry->resp_buf); | 89 | cifs_buf_release(midEntry->resp_buf); |
| 84 | else | 90 | else |
| 85 | cifs_small_buf_release(midEntry->resp_buf); | 91 | cifs_small_buf_release(midEntry->resp_buf); |
| 92 | #ifdef CONFIG_CIFS_STATS2 | ||
| 93 | now = jiffies; | ||
| 94 | /* commands taking longer than one second are indications that | ||
| 95 | something is wrong, unless it is quite a slow link or server */ | ||
| 96 | if((now - midEntry->when_alloc) > HZ) { | ||
| 97 | if((cifsFYI & CIFS_TIMER) && | ||
| 98 | (midEntry->command != SMB_COM_LOCKING_ANDX)) { | ||
| 99 | printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %d", | ||
| 100 | midEntry->command, midEntry->mid); | ||
| 101 | printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n", | ||
| 102 | now - midEntry->when_alloc, | ||
| 103 | now - midEntry->when_sent, | ||
| 104 | now - midEntry->when_received); | ||
| 105 | } | ||
| 106 | } | ||
| 107 | #endif | ||
| 86 | mempool_free(midEntry, cifs_mid_poolp); | 108 | mempool_free(midEntry, cifs_mid_poolp); |
| 87 | } | 109 | } |
| 88 | 110 | ||
| @@ -146,32 +168,37 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
| 146 | Flags2 is converted in SendReceive */ | 168 | Flags2 is converted in SendReceive */ |
| 147 | 169 | ||
| 148 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 170 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
| 149 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 171 | cFYI(1, ("Sending smb of length %d", smb_buf_length)); |
| 150 | dump_smb(smb_buffer, len); | 172 | dump_smb(smb_buffer, len); |
| 151 | 173 | ||
| 152 | while (len > 0) { | 174 | while (len > 0) { |
| 153 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); | 175 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, 1, len); |
| 154 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 176 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
| 155 | i++; | 177 | i++; |
| 156 | if(i > 60) { | 178 | /* smaller timeout here than send2 since smaller size */ |
| 179 | /* Although it may not be required, this also is smaller | ||
| 180 | oplock break time */ | ||
| 181 | if(i > 12) { | ||
| 157 | cERROR(1, | 182 | cERROR(1, |
| 158 | ("sends on sock %p stuck for 30 seconds", | 183 | ("sends on sock %p stuck for 7 seconds", |
| 159 | ssocket)); | 184 | ssocket)); |
| 160 | rc = -EAGAIN; | 185 | rc = -EAGAIN; |
| 161 | break; | 186 | break; |
| 162 | } | 187 | } |
| 163 | msleep(500); | 188 | msleep(1 << i); |
| 164 | continue; | 189 | continue; |
| 165 | } | 190 | } |
| 166 | if (rc < 0) | 191 | if (rc < 0) |
| 167 | break; | 192 | break; |
| 193 | else | ||
| 194 | i = 0; /* reset i after each successful send */ | ||
| 168 | iov.iov_base += rc; | 195 | iov.iov_base += rc; |
| 169 | iov.iov_len -= rc; | 196 | iov.iov_len -= rc; |
| 170 | len -= rc; | 197 | len -= rc; |
| 171 | } | 198 | } |
| 172 | 199 | ||
| 173 | if (rc < 0) { | 200 | if (rc < 0) { |
| 174 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 201 | cERROR(1,("Error %d sending data on socket to server", rc)); |
| 175 | } else { | 202 | } else { |
| 176 | rc = 0; | 203 | rc = 0; |
| 177 | } | 204 | } |
| @@ -179,26 +206,21 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
| 179 | return rc; | 206 | return rc; |
| 180 | } | 207 | } |
| 181 | 208 | ||
| 182 | #ifdef CIFS_EXPERIMENTAL | 209 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| 183 | /* BB finish off this function, adding support for writing set of pages as iovec */ | 210 | static int |
| 184 | /* and also adding support for operations that need to parse the response smb */ | 211 | smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, |
| 185 | 212 | struct sockaddr *sin) | |
| 186 | int | ||
| 187 | smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | ||
| 188 | unsigned int smb_buf_length, struct kvec * write_vector | ||
| 189 | /* page list */, struct sockaddr *sin) | ||
| 190 | { | 213 | { |
| 191 | int rc = 0; | 214 | int rc = 0; |
| 192 | int i = 0; | 215 | int i = 0; |
| 193 | struct msghdr smb_msg; | 216 | struct msghdr smb_msg; |
| 194 | number_of_pages += 1; /* account for SMB header */ | 217 | struct smb_hdr *smb_buffer = iov[0].iov_base; |
| 195 | struct kvec * piov = kmalloc(number_of_pages * sizeof(struct kvec)); | 218 | unsigned int len = iov[0].iov_len; |
| 196 | unsigned len = smb_buf_length + 4; | 219 | unsigned int total_len; |
| 197 | 220 | int first_vec = 0; | |
| 221 | |||
| 198 | if(ssocket == NULL) | 222 | if(ssocket == NULL) |
| 199 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 223 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
| 200 | iov.iov_base = smb_buffer; | ||
| 201 | iov.iov_len = len; | ||
| 202 | 224 | ||
| 203 | smb_msg.msg_name = sin; | 225 | smb_msg.msg_name = sin; |
| 204 | smb_msg.msg_namelen = sizeof (struct sockaddr); | 226 | smb_msg.msg_namelen = sizeof (struct sockaddr); |
| @@ -211,49 +233,80 @@ smb_sendv(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
| 211 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send | 233 | cifssmb.c and RFC1001 len is converted to bigendian in smb_send |
| 212 | Flags2 is converted in SendReceive */ | 234 | Flags2 is converted in SendReceive */ |
| 213 | 235 | ||
| 236 | |||
| 237 | total_len = 0; | ||
| 238 | for (i = 0; i < n_vec; i++) | ||
| 239 | total_len += iov[i].iov_len; | ||
| 240 | |||
| 214 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); | 241 | smb_buffer->smb_buf_length = cpu_to_be32(smb_buffer->smb_buf_length); |
| 215 | cFYI(1, ("Sending smb of length %d ", smb_buf_length)); | 242 | cFYI(1, ("Sending smb: total_len %d", total_len)); |
| 216 | dump_smb(smb_buffer, len); | 243 | dump_smb(smb_buffer, len); |
| 217 | 244 | ||
| 218 | while (len > 0) { | 245 | while (total_len) { |
| 219 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov, number_of_pages, | 246 | rc = kernel_sendmsg(ssocket, &smb_msg, &iov[first_vec], |
| 220 | len); | 247 | n_vec - first_vec, total_len); |
| 221 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { | 248 | if ((rc == -ENOSPC) || (rc == -EAGAIN)) { |
| 222 | i++; | 249 | i++; |
| 223 | if(i > 60) { | 250 | if(i >= 14) { |
| 224 | cERROR(1, | 251 | cERROR(1, |
| 225 | ("sends on sock %p stuck for 30 seconds", | 252 | ("sends on sock %p stuck for 15 seconds", |
| 226 | ssocket)); | 253 | ssocket)); |
| 227 | rc = -EAGAIN; | 254 | rc = -EAGAIN; |
| 228 | break; | 255 | break; |
| 229 | } | 256 | } |
| 230 | msleep(500); | 257 | msleep(1 << i); |
| 231 | continue; | 258 | continue; |
| 232 | } | 259 | } |
| 233 | if (rc < 0) | 260 | if (rc < 0) |
| 234 | break; | 261 | break; |
| 235 | iov.iov_base += rc; | 262 | |
| 236 | iov.iov_len -= rc; | 263 | if (rc >= total_len) { |
| 237 | len -= rc; | 264 | WARN_ON(rc > total_len); |
| 265 | break; | ||
| 266 | } | ||
| 267 | if(rc == 0) { | ||
| 268 | /* should never happen, letting socket clear before | ||
| 269 | retrying is our only obvious option here */ | ||
| 270 | cERROR(1,("tcp sent no data")); | ||
| 271 | msleep(500); | ||
| 272 | continue; | ||
| 273 | } | ||
| 274 | total_len -= rc; | ||
| 275 | /* the line below resets i */ | ||
| 276 | for (i = first_vec; i < n_vec; i++) { | ||
| 277 | if (iov[i].iov_len) { | ||
| 278 | if (rc > iov[i].iov_len) { | ||
| 279 | rc -= iov[i].iov_len; | ||
| 280 | iov[i].iov_len = 0; | ||
| 281 | } else { | ||
| 282 | iov[i].iov_base += rc; | ||
| 283 | iov[i].iov_len -= rc; | ||
| 284 | first_vec = i; | ||
| 285 | break; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | } | ||
| 289 | i = 0; /* in case we get ENOSPC on the next send */ | ||
| 238 | } | 290 | } |
| 239 | 291 | ||
| 240 | if (rc < 0) { | 292 | if (rc < 0) { |
| 241 | cERROR(1,("Error %d sending data on socket to server.", rc)); | 293 | cERROR(1,("Error %d sending data on socket to server", rc)); |
| 242 | } else { | 294 | } else |
| 243 | rc = 0; | 295 | rc = 0; |
| 244 | } | ||
| 245 | 296 | ||
| 246 | return rc; | 297 | return rc; |
| 247 | } | 298 | } |
| 248 | 299 | ||
| 249 | |||
| 250 | int | 300 | int |
| 251 | CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | 301 | SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, |
| 252 | struct smb_hdr *in_buf, struct kvec * write_vector /* page list */, int *pbytes_returned, const int long_op) | 302 | struct kvec *iov, int n_vec, int *pbytes_returned, |
| 303 | const int long_op) | ||
| 253 | { | 304 | { |
| 254 | int rc = 0; | 305 | int rc = 0; |
| 255 | unsigned long timeout = 15 * HZ; | 306 | unsigned int receive_len; |
| 256 | struct mid_q_entry *midQ = NULL; | 307 | unsigned long timeout; |
| 308 | struct mid_q_entry *midQ; | ||
| 309 | struct smb_hdr *in_buf = iov[0].iov_base; | ||
| 257 | 310 | ||
| 258 | if (ses == NULL) { | 311 | if (ses == NULL) { |
| 259 | cERROR(1,("Null smb session")); | 312 | cERROR(1,("Null smb session")); |
| @@ -263,14 +316,8 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 263 | cERROR(1,("Null tcp session")); | 316 | cERROR(1,("Null tcp session")); |
| 264 | return -EIO; | 317 | return -EIO; |
| 265 | } | 318 | } |
| 266 | if(pbytes_returned == NULL) | ||
| 267 | return -EIO; | ||
| 268 | else | ||
| 269 | *pbytes_returned = 0; | ||
| 270 | 319 | ||
| 271 | 320 | if(ses->server->tcpStatus == CifsExiting) | |
| 272 | |||
| 273 | if(ses->server->tcpStatus == CIFS_EXITING) | ||
| 274 | return -ENOENT; | 321 | return -ENOENT; |
| 275 | 322 | ||
| 276 | /* Ensure that we do not send more than 50 overlapping requests | 323 | /* Ensure that we do not send more than 50 overlapping requests |
| @@ -282,11 +329,18 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 282 | } else { | 329 | } else { |
| 283 | spin_lock(&GlobalMid_Lock); | 330 | spin_lock(&GlobalMid_Lock); |
| 284 | while(1) { | 331 | while(1) { |
| 285 | if(atomic_read(&ses->server->inFlight) >= cifs_max_pending){ | 332 | if(atomic_read(&ses->server->inFlight) >= |
| 333 | cifs_max_pending){ | ||
| 286 | spin_unlock(&GlobalMid_Lock); | 334 | spin_unlock(&GlobalMid_Lock); |
| 335 | #ifdef CONFIG_CIFS_STATS2 | ||
| 336 | atomic_inc(&ses->server->num_waiters); | ||
| 337 | #endif | ||
| 287 | wait_event(ses->server->request_q, | 338 | wait_event(ses->server->request_q, |
| 288 | atomic_read(&ses->server->inFlight) | 339 | atomic_read(&ses->server->inFlight) |
| 289 | < cifs_max_pending); | 340 | < cifs_max_pending); |
| 341 | #ifdef CONFIG_CIFS_STATS2 | ||
| 342 | atomic_dec(&ses->server->num_waiters); | ||
| 343 | #endif | ||
| 290 | spin_lock(&GlobalMid_Lock); | 344 | spin_lock(&GlobalMid_Lock); |
| 291 | } else { | 345 | } else { |
| 292 | if(ses->server->tcpStatus == CifsExiting) { | 346 | if(ses->server->tcpStatus == CifsExiting) { |
| @@ -314,17 +368,17 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 314 | 368 | ||
| 315 | if (ses->server->tcpStatus == CifsExiting) { | 369 | if (ses->server->tcpStatus == CifsExiting) { |
| 316 | rc = -ENOENT; | 370 | rc = -ENOENT; |
| 317 | goto cifs_out_label; | 371 | goto out_unlock2; |
| 318 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { | 372 | } else if (ses->server->tcpStatus == CifsNeedReconnect) { |
| 319 | cFYI(1,("tcp session dead - return to caller to retry")); | 373 | cFYI(1,("tcp session dead - return to caller to retry")); |
| 320 | rc = -EAGAIN; | 374 | rc = -EAGAIN; |
| 321 | goto cifs_out_label; | 375 | goto out_unlock2; |
| 322 | } else if (ses->status != CifsGood) { | 376 | } else if (ses->status != CifsGood) { |
| 323 | /* check if SMB session is bad because we are setting it up */ | 377 | /* check if SMB session is bad because we are setting it up */ |
| 324 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && | 378 | if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) && |
| 325 | (in_buf->Command != SMB_COM_NEGOTIATE)) { | 379 | (in_buf->Command != SMB_COM_NEGOTIATE)) { |
| 326 | rc = -EAGAIN; | 380 | rc = -EAGAIN; |
| 327 | goto cifs_out_label; | 381 | goto out_unlock2; |
| 328 | } /* else ok - we are setting up session */ | 382 | } /* else ok - we are setting up session */ |
| 329 | } | 383 | } |
| 330 | midQ = AllocMidQEntry(in_buf, ses); | 384 | midQ = AllocMidQEntry(in_buf, ses); |
| @@ -338,51 +392,162 @@ CIFSSendRcv(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 338 | return -ENOMEM; | 392 | return -ENOMEM; |
| 339 | } | 393 | } |
| 340 | 394 | ||
| 341 | if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { | 395 | /* BB FIXME */ |
| 342 | up(&ses->server->tcpSem); | 396 | /* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */ |
| 343 | cERROR(1, | 397 | |
| 344 | ("Illegal length, greater than maximum frame, %d ", | 398 | midQ->midState = MID_REQUEST_SUBMITTED; |
| 345 | in_buf->smb_buf_length)); | 399 | #ifdef CONFIG_CIFS_STATS2 |
| 400 | atomic_inc(&ses->server->inSend); | ||
| 401 | #endif | ||
| 402 | rc = smb_send2(ses->server->ssocket, iov, n_vec, | ||
| 403 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | ||
| 404 | #ifdef CONFIG_CIFS_STATS2 | ||
| 405 | atomic_dec(&ses->server->inSend); | ||
| 406 | midQ->when_sent = jiffies; | ||
| 407 | #endif | ||
| 408 | if(rc < 0) { | ||
| 346 | DeleteMidQEntry(midQ); | 409 | DeleteMidQEntry(midQ); |
| 410 | up(&ses->server->tcpSem); | ||
| 347 | /* If not lock req, update # of requests on wire to server */ | 411 | /* If not lock req, update # of requests on wire to server */ |
| 348 | if(long_op < 3) { | 412 | if(long_op < 3) { |
| 349 | atomic_dec(&ses->server->inFlight); | 413 | atomic_dec(&ses->server->inFlight); |
| 350 | wake_up(&ses->server->request_q); | 414 | wake_up(&ses->server->request_q); |
| 351 | } | 415 | } |
| 352 | return -EIO; | 416 | return rc; |
| 417 | } else | ||
| 418 | up(&ses->server->tcpSem); | ||
| 419 | if (long_op == -1) | ||
| 420 | goto cifs_no_response_exit2; | ||
| 421 | else if (long_op == 2) /* writes past end of file can take loong time */ | ||
| 422 | timeout = 180 * HZ; | ||
| 423 | else if (long_op == 1) | ||
| 424 | timeout = 45 * HZ; /* should be greater than | ||
| 425 | servers oplock break timeout (about 43 seconds) */ | ||
| 426 | else if (long_op > 2) { | ||
| 427 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
| 428 | } else | ||
| 429 | timeout = 15 * HZ; | ||
| 430 | /* wait for 15 seconds or until woken up due to response arriving or | ||
| 431 | due to last connection to this server being unmounted */ | ||
| 432 | if (signal_pending(current)) { | ||
| 433 | /* if signal pending do not hold up user for full smb timeout | ||
| 434 | but we still give response a change to complete */ | ||
| 435 | timeout = 2 * HZ; | ||
| 436 | } | ||
| 437 | |||
| 438 | /* No user interrupts in wait - wreaks havoc with performance */ | ||
| 439 | if(timeout != MAX_SCHEDULE_TIMEOUT) { | ||
| 440 | timeout += jiffies; | ||
| 441 | wait_event(ses->server->response_q, | ||
| 442 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
| 443 | time_after(jiffies, timeout) || | ||
| 444 | ((ses->server->tcpStatus != CifsGood) && | ||
| 445 | (ses->server->tcpStatus != CifsNew))); | ||
| 446 | } else { | ||
| 447 | wait_event(ses->server->response_q, | ||
| 448 | (!(midQ->midState & MID_REQUEST_SUBMITTED)) || | ||
| 449 | ((ses->server->tcpStatus != CifsGood) && | ||
| 450 | (ses->server->tcpStatus != CifsNew))); | ||
| 353 | } | 451 | } |
| 354 | 452 | ||
| 355 | /* BB can we sign efficiently in this path? */ | 453 | spin_lock(&GlobalMid_Lock); |
| 356 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 454 | if (midQ->resp_buf) { |
| 455 | spin_unlock(&GlobalMid_Lock); | ||
| 456 | receive_len = midQ->resp_buf->smb_buf_length; | ||
| 457 | } else { | ||
| 458 | cERROR(1,("No response to cmd %d mid %d", | ||
| 459 | midQ->command, midQ->mid)); | ||
| 460 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | ||
| 461 | if(ses->server->tcpStatus == CifsExiting) | ||
| 462 | rc = -EHOSTDOWN; | ||
| 463 | else { | ||
| 464 | ses->server->tcpStatus = CifsNeedReconnect; | ||
| 465 | midQ->midState = MID_RETRY_NEEDED; | ||
| 466 | } | ||
| 467 | } | ||
| 357 | 468 | ||
| 358 | midQ->midState = MID_REQUEST_SUBMITTED; | 469 | if (rc != -EHOSTDOWN) { |
| 359 | /* rc = smb_sendv(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 470 | if(midQ->midState == MID_RETRY_NEEDED) { |
| 360 | piovec, | 471 | rc = -EAGAIN; |
| 361 | (struct sockaddr *) &(ses->server->addr.sockAddr));*/ | 472 | cFYI(1,("marking request for retry")); |
| 362 | if(rc < 0) { | 473 | } else { |
| 474 | rc = -EIO; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | spin_unlock(&GlobalMid_Lock); | ||
| 363 | DeleteMidQEntry(midQ); | 478 | DeleteMidQEntry(midQ); |
| 364 | up(&ses->server->tcpSem); | ||
| 365 | /* If not lock req, update # of requests on wire to server */ | 479 | /* If not lock req, update # of requests on wire to server */ |
| 366 | if(long_op < 3) { | 480 | if(long_op < 3) { |
| 367 | atomic_dec(&ses->server->inFlight); | 481 | atomic_dec(&ses->server->inFlight); |
| 368 | wake_up(&ses->server->request_q); | 482 | wake_up(&ses->server->request_q); |
| 369 | } | 483 | } |
| 370 | return rc; | 484 | return rc; |
| 371 | } else | 485 | } |
| 372 | up(&ses->server->tcpSem); | 486 | |
| 373 | cifs_out_label: | 487 | if (receive_len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { |
| 374 | if(midQ) | 488 | cERROR(1, ("Frame too large received. Length: %d Xid: %d", |
| 375 | DeleteMidQEntry(midQ); | 489 | receive_len, xid)); |
| 376 | 490 | rc = -EIO; | |
| 491 | } else { /* rcvd frame is ok */ | ||
| 492 | |||
| 493 | if (midQ->resp_buf && | ||
| 494 | (midQ->midState == MID_RESPONSE_RECEIVED)) { | ||
| 495 | in_buf->smb_buf_length = receive_len; | ||
| 496 | /* BB verify that length would not overrun small buf */ | ||
| 497 | memcpy((char *)in_buf + 4, | ||
| 498 | (char *)midQ->resp_buf + 4, | ||
| 499 | receive_len); | ||
| 500 | |||
| 501 | dump_smb(in_buf, 80); | ||
| 502 | /* convert the length into a more usable form */ | ||
| 503 | if((receive_len > 24) && | ||
| 504 | (ses->server->secMode & (SECMODE_SIGN_REQUIRED | | ||
| 505 | SECMODE_SIGN_ENABLED))) { | ||
| 506 | rc = cifs_verify_signature(in_buf, | ||
| 507 | ses->server->mac_signing_key, | ||
| 508 | midQ->sequence_number+1); | ||
| 509 | if(rc) { | ||
| 510 | cERROR(1,("Unexpected SMB signature")); | ||
| 511 | /* BB FIXME add code to kill session */ | ||
| 512 | } | ||
| 513 | } | ||
| 514 | |||
| 515 | *pbytes_returned = in_buf->smb_buf_length; | ||
| 516 | |||
| 517 | /* BB special case reconnect tid and uid here? */ | ||
| 518 | rc = map_smb_to_linux_error(in_buf); | ||
| 519 | |||
| 520 | /* convert ByteCount if necessary */ | ||
| 521 | if (receive_len >= | ||
| 522 | sizeof (struct smb_hdr) - | ||
| 523 | 4 /* do not count RFC1001 header */ + | ||
| 524 | (2 * in_buf->WordCount) + 2 /* bcc */ ) | ||
| 525 | BCC(in_buf) = le16_to_cpu(BCC(in_buf)); | ||
| 526 | } else { | ||
| 527 | rc = -EIO; | ||
| 528 | cFYI(1,("Bad MID state?")); | ||
| 529 | } | ||
| 530 | } | ||
| 531 | cifs_no_response_exit2: | ||
| 532 | DeleteMidQEntry(midQ); | ||
| 533 | |||
| 377 | if(long_op < 3) { | 534 | if(long_op < 3) { |
| 378 | atomic_dec(&ses->server->inFlight); | 535 | atomic_dec(&ses->server->inFlight); |
| 379 | wake_up(&ses->server->request_q); | 536 | wake_up(&ses->server->request_q); |
| 380 | } | 537 | } |
| 381 | 538 | ||
| 382 | return rc; | 539 | return rc; |
| 383 | } | ||
| 384 | 540 | ||
| 541 | out_unlock2: | ||
| 542 | up(&ses->server->tcpSem); | ||
| 543 | /* If not lock req, update # of requests on wire to server */ | ||
| 544 | if(long_op < 3) { | ||
| 545 | atomic_dec(&ses->server->inFlight); | ||
| 546 | wake_up(&ses->server->request_q); | ||
| 547 | } | ||
| 385 | 548 | ||
| 549 | return rc; | ||
| 550 | } | ||
| 386 | #endif /* CIFS_EXPERIMENTAL */ | 551 | #endif /* CIFS_EXPERIMENTAL */ |
| 387 | 552 | ||
| 388 | int | 553 | int |
| @@ -419,9 +584,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 419 | if(atomic_read(&ses->server->inFlight) >= | 584 | if(atomic_read(&ses->server->inFlight) >= |
| 420 | cifs_max_pending){ | 585 | cifs_max_pending){ |
| 421 | spin_unlock(&GlobalMid_Lock); | 586 | spin_unlock(&GlobalMid_Lock); |
| 587 | #ifdef CONFIG_CIFS_STATS2 | ||
| 588 | atomic_inc(&ses->server->num_waiters); | ||
| 589 | #endif | ||
| 422 | wait_event(ses->server->request_q, | 590 | wait_event(ses->server->request_q, |
| 423 | atomic_read(&ses->server->inFlight) | 591 | atomic_read(&ses->server->inFlight) |
| 424 | < cifs_max_pending); | 592 | < cifs_max_pending); |
| 593 | #ifdef CONFIG_CIFS_STATS2 | ||
| 594 | atomic_dec(&ses->server->num_waiters); | ||
| 595 | #endif | ||
| 425 | spin_lock(&GlobalMid_Lock); | 596 | spin_lock(&GlobalMid_Lock); |
| 426 | } else { | 597 | } else { |
| 427 | if(ses->server->tcpStatus == CifsExiting) { | 598 | if(ses->server->tcpStatus == CifsExiting) { |
| @@ -490,8 +661,15 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 490 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); | 661 | rc = cifs_sign_smb(in_buf, ses->server, &midQ->sequence_number); |
| 491 | 662 | ||
| 492 | midQ->midState = MID_REQUEST_SUBMITTED; | 663 | midQ->midState = MID_REQUEST_SUBMITTED; |
| 664 | #ifdef CONFIG_CIFS_STATS2 | ||
| 665 | atomic_inc(&ses->server->inSend); | ||
| 666 | #endif | ||
| 493 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 667 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
| 494 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 668 | (struct sockaddr *) &(ses->server->addr.sockAddr)); |
| 669 | #ifdef CONFIG_CIFS_STATS2 | ||
| 670 | atomic_dec(&ses->server->inSend); | ||
| 671 | midQ->when_sent = jiffies; | ||
| 672 | #endif | ||
| 495 | if(rc < 0) { | 673 | if(rc < 0) { |
| 496 | DeleteMidQEntry(midQ); | 674 | DeleteMidQEntry(midQ); |
| 497 | up(&ses->server->tcpSem); | 675 | up(&ses->server->tcpSem); |
| @@ -506,7 +684,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 506 | if (long_op == -1) | 684 | if (long_op == -1) |
| 507 | goto cifs_no_response_exit; | 685 | goto cifs_no_response_exit; |
| 508 | else if (long_op == 2) /* writes past end of file can take loong time */ | 686 | else if (long_op == 2) /* writes past end of file can take loong time */ |
| 509 | timeout = 300 * HZ; | 687 | timeout = 180 * HZ; |
| 510 | else if (long_op == 1) | 688 | else if (long_op == 1) |
| 511 | timeout = 45 * HZ; /* should be greater than | 689 | timeout = 45 * HZ; /* should be greater than |
| 512 | servers oplock break timeout (about 43 seconds) */ | 690 | servers oplock break timeout (about 43 seconds) */ |
| @@ -540,9 +718,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 540 | spin_lock(&GlobalMid_Lock); | 718 | spin_lock(&GlobalMid_Lock); |
| 541 | if (midQ->resp_buf) { | 719 | if (midQ->resp_buf) { |
| 542 | spin_unlock(&GlobalMid_Lock); | 720 | spin_unlock(&GlobalMid_Lock); |
| 543 | receive_len = be32_to_cpu(*(__be32 *)midQ->resp_buf); | 721 | receive_len = midQ->resp_buf->smb_buf_length; |
| 544 | } else { | 722 | } else { |
| 545 | cERROR(1,("No response buffer")); | 723 | cERROR(1,("No response for cmd %d mid %d", |
| 724 | midQ->command, midQ->mid)); | ||
| 546 | if(midQ->midState == MID_REQUEST_SUBMITTED) { | 725 | if(midQ->midState == MID_REQUEST_SUBMITTED) { |
| 547 | if(ses->server->tcpStatus == CifsExiting) | 726 | if(ses->server->tcpStatus == CifsExiting) |
| 548 | rc = -EHOSTDOWN; | 727 | rc = -EHOSTDOWN; |
| @@ -610,7 +789,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
| 610 | BCC(out_buf) = le16_to_cpu(BCC(out_buf)); | 789 | BCC(out_buf) = le16_to_cpu(BCC(out_buf)); |
| 611 | } else { | 790 | } else { |
| 612 | rc = -EIO; | 791 | rc = -EIO; |
| 613 | cFYI(1,("Bad MID state? ")); | 792 | cERROR(1,("Bad MID state? ")); |
| 614 | } | 793 | } |
| 615 | } | 794 | } |
| 616 | cifs_no_response_exit: | 795 | cifs_no_response_exit: |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index ffab4783ac64..c27f8d4098be 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -247,7 +247,7 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 247 | wait_queue_head_t *wqh; | 247 | wait_queue_head_t *wqh; |
| 248 | 248 | ||
| 249 | if (!atomic_read(&inode->i_count)) | 249 | if (!atomic_read(&inode->i_count)) |
| 250 | WARN_ON(!(inode->i_state & I_WILL_FREE)); | 250 | WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); |
| 251 | else | 251 | else |
| 252 | WARN_ON(inode->i_state & I_WILL_FREE); | 252 | WARN_ON(inode->i_state & I_WILL_FREE); |
| 253 | 253 | ||
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index cf3e6ced2d01..727533891813 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
| @@ -668,10 +668,10 @@ map_buffer_cached: | |||
| 668 | * to, we need to read it in before the write, | 668 | * to, we need to read it in before the write, |
| 669 | * i.e. now. | 669 | * i.e. now. |
| 670 | */ | 670 | */ |
| 671 | if (!buffer_uptodate(bh) && ((bh_pos < pos && | 671 | if (!buffer_uptodate(bh) && bh_pos < end && |
| 672 | bh_end > pos) || | 672 | bh_end > pos && |
| 673 | (bh_end > end && | 673 | (bh_pos < pos || |
| 674 | bh_end > end))) { | 674 | bh_end > end)) { |
| 675 | /* | 675 | /* |
| 676 | * If the buffer is fully or partially | 676 | * If the buffer is fully or partially |
| 677 | * within the initialized size, do an | 677 | * within the initialized size, do an |
| @@ -784,10 +784,11 @@ retry_remap: | |||
| 784 | blocksize_bits); | 784 | blocksize_bits); |
| 785 | cdelta = 0; | 785 | cdelta = 0; |
| 786 | /* | 786 | /* |
| 787 | * If the number of remaining clusters in the | 787 | * If the number of remaining clusters touched |
| 788 | * @pages is smaller or equal to the number of | 788 | * by the write is smaller or equal to the |
| 789 | * cached clusters, unlock the runlist as the | 789 | * number of cached clusters, unlock the |
| 790 | * map cache will be used from now on. | 790 | * runlist as the map cache will be used from |
| 791 | * now on. | ||
| 791 | */ | 792 | */ |
| 792 | if (likely(vcn + vcn_len >= cend)) { | 793 | if (likely(vcn + vcn_len >= cend)) { |
| 793 | if (rl_write_locked) { | 794 | if (rl_write_locked) { |
diff --git a/include/asm-arm/arch-ixp2000/enp2611.h b/include/asm-arm/arch-ixp2000/enp2611.h index 31ae88674968..95128d9f5026 100644 --- a/include/asm-arm/arch-ixp2000/enp2611.h +++ b/include/asm-arm/arch-ixp2000/enp2611.h | |||
| @@ -21,8 +21,20 @@ | |||
| 21 | #ifndef __ENP2611_H | 21 | #ifndef __ENP2611_H |
| 22 | #define __ENP2611_H | 22 | #define __ENP2611_H |
| 23 | 23 | ||
| 24 | #define ENP2611_GPIO_SCL 0x07 | 24 | #define ENP2611_CALEB_PHYS_BASE 0xc5000000 |
| 25 | #define ENP2611_GPIO_SDA 0x06 | 25 | #define ENP2611_CALEB_VIRT_BASE 0xfe000000 |
| 26 | #define ENP2611_CALEB_SIZE 0x00100000 | ||
| 27 | |||
| 28 | #define ENP2611_PM3386_0_PHYS_BASE 0xc6000000 | ||
| 29 | #define ENP2611_PM3386_0_VIRT_BASE 0xfe100000 | ||
| 30 | #define ENP2611_PM3386_0_SIZE 0x00100000 | ||
| 31 | |||
| 32 | #define ENP2611_PM3386_1_PHYS_BASE 0xc6400000 | ||
| 33 | #define ENP2611_PM3386_1_VIRT_BASE 0xfe200000 | ||
| 34 | #define ENP2611_PM3386_1_SIZE 0x00100000 | ||
| 35 | |||
| 36 | #define ENP2611_GPIO_SCL 7 | ||
| 37 | #define ENP2611_GPIO_SDA 6 | ||
| 26 | 38 | ||
| 27 | 39 | ||
| 28 | #endif | 40 | #endif |
diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h index def089d693d2..fc5ac6aec4f2 100644 --- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h +++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h | |||
| @@ -59,14 +59,15 @@ | |||
| 59 | #define IXP2000_CAP_SIZE 0x00100000 | 59 | #define IXP2000_CAP_SIZE 0x00100000 |
| 60 | 60 | ||
| 61 | /* | 61 | /* |
| 62 | * Addresses for specific on-chip peripherals | 62 | * Addresses for specific on-chip peripherals. |
| 63 | */ | 63 | */ |
| 64 | #define IXP2000_SLOWPORT_CSR_VIRT_BASE 0xfef80000 | 64 | #define IXP2000_SLOWPORT_CSR_VIRT_BASE 0xfef80000 |
| 65 | #define IXP2000_GLOBAL_REG_VIRT_BASE 0xfef04000 | 65 | #define IXP2000_GLOBAL_REG_VIRT_BASE 0xfef04000 |
| 66 | #define IXP2000_UART_PHYS_BASE 0xc0030000 | 66 | #define IXP2000_UART_PHYS_BASE 0xc0030000 |
| 67 | #define IXP2000_UART_VIRT_BASE 0xfef30000 | 67 | #define IXP2000_UART_VIRT_BASE 0xfef30000 |
| 68 | #define IXP2000_TIMER_VIRT_BASE 0xfef20000 | 68 | #define IXP2000_TIMER_VIRT_BASE 0xfef20000 |
| 69 | #define IXP2000_GPIO_VIRT_BASE 0Xfef10000 | 69 | #define IXP2000_UENGINE_CSR_VIRT_BASE 0xfef18000 |
| 70 | #define IXP2000_GPIO_VIRT_BASE 0xfef10000 | ||
| 70 | 71 | ||
| 71 | /* | 72 | /* |
| 72 | * Devices outside of the 0xc0000000 -> 0xc0100000 range. The virtual | 73 | * Devices outside of the 0xc0000000 -> 0xc0100000 range. The virtual |
| @@ -252,7 +253,7 @@ | |||
| 252 | #define IXP2000_PCI_XSCALE_INT_ENABLE IXP2000_PCI_CSR(0x15C) | 253 | #define IXP2000_PCI_XSCALE_INT_ENABLE IXP2000_PCI_CSR(0x15C) |
| 253 | 254 | ||
| 254 | #define IXP2000_PCICNTL_PNR (1<<17) /* PCI not Reset bit of PCI_CONTROL */ | 255 | #define IXP2000_PCICNTL_PNR (1<<17) /* PCI not Reset bit of PCI_CONTROL */ |
| 255 | #define IXP2000_PCICNTL_PCF (1<<28) /* PCI Centrolfunction bit */ | 256 | #define IXP2000_PCICNTL_PCF (1<<28) /* PCI Central function bit */ |
| 256 | #define IXP2000_XSCALE_INT (1<<1) /* Interrupt from XScale to PCI */ | 257 | #define IXP2000_XSCALE_INT (1<<1) /* Interrupt from XScale to PCI */ |
| 257 | 258 | ||
| 258 | /* These are from the IRQ register in the PCI ISR register */ | 259 | /* These are from the IRQ register in the PCI ISR register */ |
diff --git a/include/asm-arm/arch-ixp2000/system.h b/include/asm-arm/arch-ixp2000/system.h index 4f489cc0dfa5..ddbbb34b5f95 100644 --- a/include/asm-arm/arch-ixp2000/system.h +++ b/include/asm-arm/arch-ixp2000/system.h | |||
| @@ -26,29 +26,24 @@ static inline void arch_reset(char mode) | |||
| 26 | * RedBoot bank. | 26 | * RedBoot bank. |
| 27 | */ | 27 | */ |
| 28 | if (machine_is_ixdp2401()) { | 28 | if (machine_is_ixdp2401()) { |
| 29 | *IXDP2X01_CPLD_FLASH_REG = ((0 >> IXDP2X01_FLASH_WINDOW_BITS) | 29 | ixp2000_reg_write(IXDP2X01_CPLD_FLASH_REG, |
| 30 | | IXDP2X01_CPLD_FLASH_INTERN); | 30 | ((0 >> IXDP2X01_FLASH_WINDOW_BITS) |
| 31 | *IXDP2X01_CPLD_RESET_REG = 0xffffffff; | 31 | | IXDP2X01_CPLD_FLASH_INTERN)); |
| 32 | ixp2000_reg_wrb(IXDP2X01_CPLD_RESET_REG, 0xffffffff); | ||
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | /* | 35 | /* |
| 35 | * On IXDP2801 we need to write this magic sequence to the CPLD | 36 | * On IXDP2801 we need to write this magic sequence to the CPLD |
| 36 | * to cause a complete reset of the CPU and all external devices | 37 | * to cause a complete reset of the CPU and all external devices |
| 37 | * and moves the flash bank register back to 0. | 38 | * and move the flash bank register back to 0. |
| 38 | */ | 39 | */ |
| 39 | if (machine_is_ixdp2801()) { | 40 | if (machine_is_ixdp2801()) { |
| 40 | unsigned long reset_reg = *IXDP2X01_CPLD_RESET_REG; | 41 | unsigned long reset_reg = *IXDP2X01_CPLD_RESET_REG; |
| 42 | |||
| 41 | reset_reg = 0x55AA0000 | (reset_reg & 0x0000FFFF); | 43 | reset_reg = 0x55AA0000 | (reset_reg & 0x0000FFFF); |
| 42 | *IXDP2X01_CPLD_RESET_REG = reset_reg; | 44 | ixp2000_reg_write(IXDP2X01_CPLD_RESET_REG, reset_reg); |
| 43 | mb(); | 45 | ixp2000_reg_wrb(IXDP2X01_CPLD_RESET_REG, 0x80000000); |
| 44 | *IXDP2X01_CPLD_RESET_REG = 0x80000000; | ||
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | /* | 48 | ixp2000_reg_wrb(IXP2000_RESET0, RSTALL); |
| 48 | * We do a reset all if we are PCI master. We could be a slave and we | ||
| 49 | * don't want to do anything funky on the PCI bus. | ||
| 50 | */ | ||
| 51 | if (*IXP2000_STRAP_OPTIONS & CFG_PCI_BOOT_HOST) { | ||
| 52 | *(IXP2000_RESET0) |= (RSTALL); | ||
| 53 | } | ||
| 54 | } | 49 | } |
diff --git a/include/asm-arm/arch-ixp2000/uengine.h b/include/asm-arm/arch-ixp2000/uengine.h new file mode 100644 index 000000000000..b442d65c6593 --- /dev/null +++ b/include/asm-arm/arch-ixp2000/uengine.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | /* | ||
| 2 | * Generic library functions for the microengines found on the Intel | ||
| 3 | * IXP2000 series of network processors. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2004, 2005 Lennert Buytenhek <buytenh@wantstofly.org> | ||
| 6 | * Dedicated to Marija Kulikova. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU Lesser General Public License as | ||
| 10 | * published by the Free Software Foundation; either version 2.1 of the | ||
| 11 | * License, or (at your option) any later version. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __IXP2000_UENGINE_H | ||
| 15 | #define __IXP2000_UENGINE_H | ||
| 16 | |||
| 17 | extern u32 ixp2000_uengine_mask; | ||
| 18 | |||
| 19 | struct ixp2000_uengine_code | ||
| 20 | { | ||
| 21 | u32 cpu_model_bitmask; | ||
| 22 | u8 cpu_min_revision; | ||
| 23 | u8 cpu_max_revision; | ||
| 24 | |||
| 25 | u32 uengine_parameters; | ||
| 26 | |||
| 27 | struct ixp2000_reg_value { | ||
| 28 | int reg; | ||
| 29 | u32 value; | ||
| 30 | } *initial_reg_values; | ||
| 31 | |||
| 32 | int num_insns; | ||
| 33 | u8 *insns; | ||
| 34 | }; | ||
| 35 | |||
| 36 | u32 ixp2000_uengine_csr_read(int uengine, int offset); | ||
| 37 | void ixp2000_uengine_csr_write(int uengine, int offset, u32 value); | ||
| 38 | void ixp2000_uengine_reset(u32 uengine_mask); | ||
| 39 | void ixp2000_uengine_set_mode(int uengine, u32 mode); | ||
| 40 | void ixp2000_uengine_load_microcode(int uengine, u8 *ucode, int insns); | ||
| 41 | void ixp2000_uengine_init_context(int uengine, int context, int pc); | ||
| 42 | void ixp2000_uengine_start_contexts(int uengine, u8 ctx_mask); | ||
| 43 | void ixp2000_uengine_stop_contexts(int uengine, u8 ctx_mask); | ||
| 44 | int ixp2000_uengine_load(int uengine, struct ixp2000_uengine_code *c); | ||
| 45 | |||
| 46 | #define IXP2000_UENGINE_8_CONTEXTS 0x00000000 | ||
| 47 | #define IXP2000_UENGINE_4_CONTEXTS 0x80000000 | ||
| 48 | #define IXP2000_UENGINE_PRN_UPDATE_EVERY 0x40000000 | ||
| 49 | #define IXP2000_UENGINE_PRN_UPDATE_ON_ACCESS 0x00000000 | ||
| 50 | #define IXP2000_UENGINE_NN_FROM_SELF 0x00100000 | ||
| 51 | #define IXP2000_UENGINE_NN_FROM_PREVIOUS 0x00000000 | ||
| 52 | #define IXP2000_UENGINE_ASSERT_EMPTY_AT_3 0x000c0000 | ||
| 53 | #define IXP2000_UENGINE_ASSERT_EMPTY_AT_2 0x00080000 | ||
| 54 | #define IXP2000_UENGINE_ASSERT_EMPTY_AT_1 0x00040000 | ||
| 55 | #define IXP2000_UENGINE_ASSERT_EMPTY_AT_0 0x00000000 | ||
| 56 | #define IXP2000_UENGINE_LM_ADDR1_GLOBAL 0x00020000 | ||
| 57 | #define IXP2000_UENGINE_LM_ADDR1_PER_CONTEXT 0x00000000 | ||
| 58 | #define IXP2000_UENGINE_LM_ADDR0_GLOBAL 0x00010000 | ||
| 59 | #define IXP2000_UENGINE_LM_ADDR0_PER_CONTEXT 0x00000000 | ||
| 60 | |||
| 61 | |||
| 62 | #endif | ||
diff --git a/include/asm-arm/arch-realview/debug-macro.S b/include/asm-arm/arch-realview/debug-macro.S new file mode 100644 index 000000000000..ed28bd012236 --- /dev/null +++ b/include/asm-arm/arch-realview/debug-macro.S | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* linux/include/asm-arm/arch-realview/debug-macro.S | ||
| 2 | * | ||
| 3 | * Debugging macro include header | ||
| 4 | * | ||
| 5 | * Copyright (C) 1994-1999 Russell King | ||
| 6 | * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <asm/hardware/amba_serial.h> | ||
| 15 | |||
| 16 | .macro addruart,rx | ||
| 17 | mrc p15, 0, \rx, c1, c0 | ||
| 18 | tst \rx, #1 @ MMU enabled? | ||
| 19 | moveq \rx, #0x10000000 | ||
| 20 | movne \rx, #0xf1000000 @ virtual base | ||
| 21 | orr \rx, \rx, #0x00009000 | ||
| 22 | .endm | ||
| 23 | |||
| 24 | .macro senduart,rd,rx | ||
| 25 | strb \rd, [\rx, #UART01x_DR] | ||
| 26 | .endm | ||
| 27 | |||
| 28 | .macro waituart,rd,rx | ||
| 29 | 1001: ldr \rd, [\rx, #0x18] @ UARTFLG | ||
| 30 | tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full | ||
| 31 | bne 1001b | ||
| 32 | .endm | ||
| 33 | |||
| 34 | .macro busyuart,rd,rx | ||
| 35 | 1001: ldr \rd, [\rx, #0x18] @ UARTFLG | ||
| 36 | tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy | ||
| 37 | bne 1001b | ||
| 38 | .endm | ||
diff --git a/include/asm-arm/arch-realview/dma.h b/include/asm-arm/arch-realview/dma.h new file mode 100644 index 000000000000..744491a74bd9 --- /dev/null +++ b/include/asm-arm/arch-realview/dma.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/dma.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2003 ARM Limited. | ||
| 5 | * Copyright (C) 1997,1998 Russell King | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | #ifndef __ASM_ARCH_DMA_H | ||
| 22 | #define __ASM_ARCH_DMA_H | ||
| 23 | |||
| 24 | #define MAX_DMA_ADDRESS 0xffffffff | ||
| 25 | #define MAX_DMA_CHANNELS 0 | ||
| 26 | |||
| 27 | #endif /* _ASM_ARCH_DMA_H */ | ||
diff --git a/include/asm-arm/arch-realview/entry-macro.S b/include/asm-arm/arch-realview/entry-macro.S new file mode 100644 index 000000000000..2712ba77bb3a --- /dev/null +++ b/include/asm-arm/arch-realview/entry-macro.S | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * include/asm-arm/arch-realview/entry-macro.S | ||
| 3 | * | ||
| 4 | * Low-level IRQ helper macros for RealView platforms | ||
| 5 | * | ||
| 6 | * This file is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2. This program is licensed "as is" without any | ||
| 8 | * warranty of any kind, whether express or implied. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <asm/hardware/gic.h> | ||
| 12 | |||
| 13 | .macro disable_fiq | ||
| 14 | .endm | ||
| 15 | |||
| 16 | /* | ||
| 17 | * The interrupt numbering scheme is defined in the | ||
| 18 | * interrupt controller spec. To wit: | ||
| 19 | * | ||
| 20 | * Interrupts 0-15 are IPI | ||
| 21 | * 16-28 are reserved | ||
| 22 | * 29-31 are local. We allow 30 to be used for the watchdog. | ||
| 23 | * 32-1020 are global | ||
| 24 | * 1021-1022 are reserved | ||
| 25 | * 1023 is "spurious" (no interrupt) | ||
| 26 | * | ||
| 27 | * For now, we ignore all local interrupts so only return an interrupt if it's | ||
| 28 | * between 30 and 1020. The test_for_ipi routine below will pick up on IPIs. | ||
| 29 | * | ||
| 30 | * A simple read from the controller will tell us the number of the highest | ||
| 31 | * priority enabled interrupt. We then just need to check whether it is in the | ||
| 32 | * valid range for an IRQ (30-1020 inclusive). | ||
| 33 | */ | ||
| 34 | |||
| 35 | .macro get_irqnr_and_base, irqnr, irqstat, base, tmp | ||
| 36 | |||
| 37 | ldr \base, =IO_ADDRESS(REALVIEW_GIC_CPU_BASE) | ||
| 38 | ldr \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 = src CPU, 9-0 = int # */ | ||
| 39 | |||
| 40 | ldr \tmp, =1021 | ||
| 41 | |||
| 42 | bic \irqnr, \irqstat, #0x1c00 | ||
| 43 | |||
| 44 | cmp \irqnr, #29 | ||
| 45 | cmpcc \irqnr, \irqnr | ||
| 46 | cmpne \irqnr, \tmp | ||
| 47 | cmpcs \irqnr, \irqnr | ||
| 48 | |||
| 49 | .endm | ||
diff --git a/include/asm-arm/arch-realview/hardware.h b/include/asm-arm/arch-realview/hardware.h new file mode 100644 index 000000000000..67879cdb6ef2 --- /dev/null +++ b/include/asm-arm/arch-realview/hardware.h | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/hardware.h | ||
| 3 | * | ||
| 4 | * This file contains the hardware definitions of the RealView boards. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2003 ARM Limited. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | #ifndef __ASM_ARCH_HARDWARE_H | ||
| 23 | #define __ASM_ARCH_HARDWARE_H | ||
| 24 | |||
| 25 | #include <asm/sizes.h> | ||
| 26 | #include <asm/arch/platform.h> | ||
| 27 | |||
| 28 | /* macro to get at IO space when running virtually */ | ||
| 29 | #define IO_ADDRESS(x) (((x) & 0x0fffffff) + (((x) >> 4) & 0x0f000000) + 0xf0000000) | ||
| 30 | |||
| 31 | #endif | ||
diff --git a/include/asm-arm/arch-realview/io.h b/include/asm-arm/arch-realview/io.h new file mode 100644 index 000000000000..d444a68ac330 --- /dev/null +++ b/include/asm-arm/arch-realview/io.h | |||
| @@ -0,0 +1,34 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/io.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2003 ARM Limited | ||
| 5 | * | ||
| 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 | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | #ifndef __ASM_ARM_ARCH_IO_H | ||
| 21 | #define __ASM_ARM_ARCH_IO_H | ||
| 22 | |||
| 23 | #define IO_SPACE_LIMIT 0xffffffff | ||
| 24 | |||
| 25 | static inline void __iomem *__io(unsigned long addr) | ||
| 26 | { | ||
| 27 | return (void __iomem *)addr; | ||
| 28 | } | ||
| 29 | |||
| 30 | #define __io(a) __io(a) | ||
| 31 | #define __mem_pci(a) (a) | ||
| 32 | #define __mem_isa(a) (a) | ||
| 33 | |||
| 34 | #endif | ||
diff --git a/include/asm-arm/arch-realview/irqs.h b/include/asm-arm/arch-realview/irqs.h new file mode 100644 index 000000000000..ff376494e5b1 --- /dev/null +++ b/include/asm-arm/arch-realview/irqs.h | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/irqs.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2003 ARM Limited | ||
| 5 | * Copyright (C) 2000 Deep Blue Solutions Ltd. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <asm/arch/platform.h> | ||
| 23 | |||
| 24 | /* | ||
| 25 | * IRQ interrupts definitions are the same the INT definitions | ||
| 26 | * held within platform.h | ||
| 27 | */ | ||
| 28 | #define IRQ_GIC_START 32 | ||
| 29 | #define IRQ_WDOGINT (IRQ_GIC_START + INT_WDOGINT) | ||
| 30 | #define IRQ_SOFTINT (IRQ_GIC_START + INT_SOFTINT) | ||
| 31 | #define IRQ_COMMRx (IRQ_GIC_START + INT_COMMRx) | ||
| 32 | #define IRQ_COMMTx (IRQ_GIC_START + INT_COMMTx) | ||
| 33 | #define IRQ_TIMERINT0_1 (IRQ_GIC_START + INT_TIMERINT0_1) | ||
| 34 | #define IRQ_TIMERINT2_3 (IRQ_GIC_START + INT_TIMERINT2_3) | ||
| 35 | #define IRQ_GPIOINT0 (IRQ_GIC_START + INT_GPIOINT0) | ||
| 36 | #define IRQ_GPIOINT1 (IRQ_GIC_START + INT_GPIOINT1) | ||
| 37 | #define IRQ_GPIOINT2 (IRQ_GIC_START + INT_GPIOINT2) | ||
| 38 | #define IRQ_GPIOINT3 (IRQ_GIC_START + INT_GPIOINT3) | ||
| 39 | #define IRQ_RTCINT (IRQ_GIC_START + INT_RTCINT) | ||
| 40 | #define IRQ_SSPINT (IRQ_GIC_START + INT_SSPINT) | ||
| 41 | #define IRQ_UARTINT0 (IRQ_GIC_START + INT_UARTINT0) | ||
| 42 | #define IRQ_UARTINT1 (IRQ_GIC_START + INT_UARTINT1) | ||
| 43 | #define IRQ_UARTINT2 (IRQ_GIC_START + INT_UARTINT2) | ||
| 44 | #define IRQ_UART3 (IRQ_GIC_START + INT_UARTINT3) | ||
| 45 | #define IRQ_SCIINT (IRQ_GIC_START + INT_SCIINT) | ||
| 46 | #define IRQ_CLCDINT (IRQ_GIC_START + INT_CLCDINT) | ||
| 47 | #define IRQ_DMAINT (IRQ_GIC_START + INT_DMAINT) | ||
| 48 | #define IRQ_PWRFAILINT (IRQ_GIC_START + INT_PWRFAILINT) | ||
| 49 | #define IRQ_MBXINT (IRQ_GIC_START + INT_MBXINT) | ||
| 50 | #define IRQ_GNDINT (IRQ_GIC_START + INT_GNDINT) | ||
| 51 | #define IRQ_MMCI0B (IRQ_GIC_START + INT_MMCI0B) | ||
| 52 | #define IRQ_MMCI1B (IRQ_GIC_START + INT_MMCI1B) | ||
| 53 | #define IRQ_KMI0 (IRQ_GIC_START + INT_KMI0) | ||
| 54 | #define IRQ_KMI1 (IRQ_GIC_START + INT_KMI1) | ||
| 55 | #define IRQ_SCI3 (IRQ_GIC_START + INT_SCI3) | ||
| 56 | #define IRQ_CLCD (IRQ_GIC_START + INT_CLCD) | ||
| 57 | #define IRQ_TOUCH (IRQ_GIC_START + INT_TOUCH) | ||
| 58 | #define IRQ_KEYPAD (IRQ_GIC_START + INT_KEYPAD) | ||
| 59 | #define IRQ_DoC (IRQ_GIC_START + INT_DoC) | ||
| 60 | #define IRQ_MMCI0A (IRQ_GIC_START + INT_MMCI0A) | ||
| 61 | #define IRQ_MMCI1A (IRQ_GIC_START + INT_MMCI1A) | ||
| 62 | #define IRQ_AACI (IRQ_GIC_START + INT_AACI) | ||
| 63 | #define IRQ_ETH (IRQ_GIC_START + INT_ETH) | ||
| 64 | #define IRQ_USB (IRQ_GIC_START + INT_USB) | ||
| 65 | |||
| 66 | #define IRQMASK_WDOGINT INTMASK_WDOGINT | ||
| 67 | #define IRQMASK_SOFTINT INTMASK_SOFTINT | ||
| 68 | #define IRQMASK_COMMRx INTMASK_COMMRx | ||
| 69 | #define IRQMASK_COMMTx INTMASK_COMMTx | ||
| 70 | #define IRQMASK_TIMERINT0_1 INTMASK_TIMERINT0_1 | ||
| 71 | #define IRQMASK_TIMERINT2_3 INTMASK_TIMERINT2_3 | ||
| 72 | #define IRQMASK_GPIOINT0 INTMASK_GPIOINT0 | ||
| 73 | #define IRQMASK_GPIOINT1 INTMASK_GPIOINT1 | ||
| 74 | #define IRQMASK_GPIOINT2 INTMASK_GPIOINT2 | ||
| 75 | #define IRQMASK_GPIOINT3 INTMASK_GPIOINT3 | ||
| 76 | #define IRQMASK_RTCINT INTMASK_RTCINT | ||
| 77 | #define IRQMASK_SSPINT INTMASK_SSPINT | ||
| 78 | #define IRQMASK_UARTINT0 INTMASK_UARTINT0 | ||
| 79 | #define IRQMASK_UARTINT1 INTMASK_UARTINT1 | ||
| 80 | #define IRQMASK_UARTINT2 INTMASK_UARTINT2 | ||
| 81 | #define IRQMASK_SCIINT INTMASK_SCIINT | ||
| 82 | #define IRQMASK_CLCDINT INTMASK_CLCDINT | ||
| 83 | #define IRQMASK_DMAINT INTMASK_DMAINT | ||
| 84 | #define IRQMASK_PWRFAILINT INTMASK_PWRFAILINT | ||
| 85 | #define IRQMASK_MBXINT INTMASK_MBXINT | ||
| 86 | #define IRQMASK_GNDINT INTMASK_GNDINT | ||
| 87 | #define IRQMASK_MMCI0B INTMASK_MMCI0B | ||
| 88 | #define IRQMASK_MMCI1B INTMASK_MMCI1B | ||
| 89 | #define IRQMASK_KMI0 INTMASK_KMI0 | ||
| 90 | #define IRQMASK_KMI1 INTMASK_KMI1 | ||
| 91 | #define IRQMASK_SCI3 INTMASK_SCI3 | ||
| 92 | #define IRQMASK_UART3 INTMASK_UART3 | ||
| 93 | #define IRQMASK_CLCD INTMASK_CLCD | ||
| 94 | #define IRQMASK_TOUCH INTMASK_TOUCH | ||
| 95 | #define IRQMASK_KEYPAD INTMASK_KEYPAD | ||
| 96 | #define IRQMASK_DoC INTMASK_DoC | ||
| 97 | #define IRQMASK_MMCI0A INTMASK_MMCI0A | ||
| 98 | #define IRQMASK_MMCI1A INTMASK_MMCI1A | ||
| 99 | #define IRQMASK_AACI INTMASK_AACI | ||
| 100 | #define IRQMASK_ETH INTMASK_ETH | ||
| 101 | #define IRQMASK_USB INTMASK_USB | ||
| 102 | |||
| 103 | #define NR_IRQS (IRQ_GIC_START + 64) | ||
diff --git a/include/asm-arm/arch-realview/memory.h b/include/asm-arm/arch-realview/memory.h new file mode 100644 index 000000000000..99667d5cc617 --- /dev/null +++ b/include/asm-arm/arch-realview/memory.h | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/memory.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2003 ARM Limited | ||
| 5 | * | ||
| 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 | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | #ifndef __ASM_ARCH_MEMORY_H | ||
| 21 | #define __ASM_ARCH_MEMORY_H | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Physical DRAM offset. | ||
| 25 | */ | ||
| 26 | #define PHYS_OFFSET (0x00000000UL) | ||
| 27 | |||
| 28 | /* | ||
| 29 | * Virtual view <-> DMA view memory address translations | ||
| 30 | * virt_to_bus: Used to translate the virtual address to an | ||
| 31 | * address suitable to be passed to set_dma_addr | ||
| 32 | * bus_to_virt: Used to convert an address for DMA operations | ||
| 33 | * to an address that the kernel can use. | ||
| 34 | */ | ||
| 35 | #define __virt_to_bus(x) ((x) - PAGE_OFFSET) | ||
| 36 | #define __bus_to_virt(x) ((x) + PAGE_OFFSET) | ||
| 37 | |||
| 38 | #endif | ||
diff --git a/include/asm-arm/arch-realview/param.h b/include/asm-arm/arch-realview/param.h new file mode 100644 index 000000000000..89b1235d32bd --- /dev/null +++ b/include/asm-arm/arch-realview/param.h | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/param.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 ARM Limited | ||
| 5 | * | ||
| 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 | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
diff --git a/include/asm-arm/arch-realview/platform.h b/include/asm-arm/arch-realview/platform.h new file mode 100644 index 000000000000..4b6de13a6b9a --- /dev/null +++ b/include/asm-arm/arch-realview/platform.h | |||
| @@ -0,0 +1,395 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/platform.h | ||
| 3 | * | ||
| 4 | * Copyright (c) ARM Limited 2003. All rights reserved. | ||
| 5 | * | ||
| 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 | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef __address_h | ||
| 22 | #define __address_h 1 | ||
| 23 | |||
| 24 | /* | ||
| 25 | * Memory definitions | ||
| 26 | */ | ||
| 27 | #define REALVIEW_BOOT_ROM_LO 0x30000000 /* DoC Base (64Mb)...*/ | ||
| 28 | #define REALVIEW_BOOT_ROM_HI 0x30000000 | ||
| 29 | #define REALVIEW_BOOT_ROM_BASE REALVIEW_BOOT_ROM_HI /* Normal position */ | ||
| 30 | #define REALVIEW_BOOT_ROM_SIZE SZ_64M | ||
| 31 | |||
| 32 | #define REALVIEW_SSRAM_BASE /* REALVIEW_SSMC_BASE ? */ | ||
| 33 | #define REALVIEW_SSRAM_SIZE SZ_2M | ||
| 34 | |||
| 35 | #define REALVIEW_FLASH_BASE 0x40000000 | ||
| 36 | #define REALVIEW_FLASH_SIZE SZ_64M | ||
| 37 | |||
| 38 | /* | ||
| 39 | * SDRAM | ||
| 40 | */ | ||
| 41 | #define REALVIEW_SDRAM_BASE 0x00000000 | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Logic expansion modules | ||
| 45 | * | ||
| 46 | */ | ||
| 47 | |||
| 48 | |||
| 49 | /* ------------------------------------------------------------------------ | ||
| 50 | * RealView Registers | ||
| 51 | * ------------------------------------------------------------------------ | ||
| 52 | * | ||
| 53 | */ | ||
| 54 | #define REALVIEW_SYS_ID_OFFSET 0x00 | ||
| 55 | #define REALVIEW_SYS_SW_OFFSET 0x04 | ||
| 56 | #define REALVIEW_SYS_LED_OFFSET 0x08 | ||
| 57 | #define REALVIEW_SYS_OSC0_OFFSET 0x0C | ||
| 58 | |||
| 59 | #define REALVIEW_SYS_OSC1_OFFSET 0x10 | ||
| 60 | #define REALVIEW_SYS_OSC2_OFFSET 0x14 | ||
| 61 | #define REALVIEW_SYS_OSC3_OFFSET 0x18 | ||
| 62 | #define REALVIEW_SYS_OSC4_OFFSET 0x1C /* OSC1 for RealView/AB */ | ||
| 63 | |||
| 64 | #define REALVIEW_SYS_LOCK_OFFSET 0x20 | ||
| 65 | #define REALVIEW_SYS_100HZ_OFFSET 0x24 | ||
| 66 | #define REALVIEW_SYS_CFGDATA1_OFFSET 0x28 | ||
| 67 | #define REALVIEW_SYS_CFGDATA2_OFFSET 0x2C | ||
| 68 | #define REALVIEW_SYS_FLAGS_OFFSET 0x30 | ||
| 69 | #define REALVIEW_SYS_FLAGSSET_OFFSET 0x30 | ||
| 70 | #define REALVIEW_SYS_FLAGSCLR_OFFSET 0x34 | ||
| 71 | #define REALVIEW_SYS_NVFLAGS_OFFSET 0x38 | ||
| 72 | #define REALVIEW_SYS_NVFLAGSSET_OFFSET 0x38 | ||
| 73 | #define REALVIEW_SYS_NVFLAGSCLR_OFFSET 0x3C | ||
| 74 | #define REALVIEW_SYS_RESETCTL_OFFSET 0x40 | ||
| 75 | #define REALVIEW_SYS_PCICTL_OFFSET 0x44 | ||
| 76 | #define REALVIEW_SYS_MCI_OFFSET 0x48 | ||
| 77 | #define REALVIEW_SYS_FLASH_OFFSET 0x4C | ||
| 78 | #define REALVIEW_SYS_CLCD_OFFSET 0x50 | ||
| 79 | #define REALVIEW_SYS_CLCDSER_OFFSET 0x54 | ||
| 80 | #define REALVIEW_SYS_BOOTCS_OFFSET 0x58 | ||
| 81 | #define REALVIEW_SYS_24MHz_OFFSET 0x5C | ||
| 82 | #define REALVIEW_SYS_MISC_OFFSET 0x60 | ||
| 83 | #define REALVIEW_SYS_IOSEL_OFFSET 0x70 | ||
| 84 | #define REALVIEW_SYS_TEST_OSC0_OFFSET 0x80 | ||
| 85 | #define REALVIEW_SYS_TEST_OSC1_OFFSET 0x84 | ||
| 86 | #define REALVIEW_SYS_TEST_OSC2_OFFSET 0x88 | ||
| 87 | #define REALVIEW_SYS_TEST_OSC3_OFFSET 0x8C | ||
| 88 | #define REALVIEW_SYS_TEST_OSC4_OFFSET 0x90 | ||
| 89 | |||
| 90 | #define REALVIEW_SYS_BASE 0x10000000 | ||
| 91 | #define REALVIEW_SYS_ID (REALVIEW_SYS_BASE + REALVIEW_SYS_ID_OFFSET) | ||
| 92 | #define REALVIEW_SYS_SW (REALVIEW_SYS_BASE + REALVIEW_SYS_SW_OFFSET) | ||
| 93 | #define REALVIEW_SYS_LED (REALVIEW_SYS_BASE + REALVIEW_SYS_LED_OFFSET) | ||
| 94 | #define REALVIEW_SYS_OSC0 (REALVIEW_SYS_BASE + REALVIEW_SYS_OSC0_OFFSET) | ||
| 95 | #define REALVIEW_SYS_OSC1 (REALVIEW_SYS_BASE + REALVIEW_SYS_OSC1_OFFSET) | ||
| 96 | |||
| 97 | #define REALVIEW_SYS_LOCK (REALVIEW_SYS_BASE + REALVIEW_SYS_LOCK_OFFSET) | ||
| 98 | #define REALVIEW_SYS_100HZ (REALVIEW_SYS_BASE + REALVIEW_SYS_100HZ_OFFSET) | ||
| 99 | #define REALVIEW_SYS_CFGDATA1 (REALVIEW_SYS_BASE + REALVIEW_SYS_CFGDATA1_OFFSET) | ||
| 100 | #define REALVIEW_SYS_CFGDATA2 (REALVIEW_SYS_BASE + REALVIEW_SYS_CFGDATA2_OFFSET) | ||
| 101 | #define REALVIEW_SYS_FLAGS (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGS_OFFSET) | ||
| 102 | #define REALVIEW_SYS_FLAGSSET (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGSSET_OFFSET) | ||
| 103 | #define REALVIEW_SYS_FLAGSCLR (REALVIEW_SYS_BASE + REALVIEW_SYS_FLAGSCLR_OFFSET) | ||
| 104 | #define REALVIEW_SYS_NVFLAGS (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGS_OFFSET) | ||
| 105 | #define REALVIEW_SYS_NVFLAGSSET (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGSSET_OFFSET) | ||
| 106 | #define REALVIEW_SYS_NVFLAGSCLR (REALVIEW_SYS_BASE + REALVIEW_SYS_NVFLAGSCLR_OFFSET) | ||
| 107 | #define REALVIEW_SYS_RESETCTL (REALVIEW_SYS_BASE + REALVIEW_SYS_RESETCTL_OFFSET) | ||
| 108 | #define REALVIEW_SYS_PCICTL (REALVIEW_SYS_BASE + REALVIEW_SYS_PCICTL_OFFSET) | ||
| 109 | #define REALVIEW_SYS_MCI (REALVIEW_SYS_BASE + REALVIEW_SYS_MCI_OFFSET) | ||
| 110 | #define REALVIEW_SYS_FLASH (REALVIEW_SYS_BASE + REALVIEW_SYS_FLASH_OFFSET) | ||
| 111 | #define REALVIEW_SYS_CLCD (REALVIEW_SYS_BASE + REALVIEW_SYS_CLCD_OFFSET) | ||
| 112 | #define REALVIEW_SYS_CLCDSER (REALVIEW_SYS_BASE + REALVIEW_SYS_CLCDSER_OFFSET) | ||
| 113 | #define REALVIEW_SYS_BOOTCS (REALVIEW_SYS_BASE + REALVIEW_SYS_BOOTCS_OFFSET) | ||
| 114 | #define REALVIEW_SYS_24MHz (REALVIEW_SYS_BASE + REALVIEW_SYS_24MHz_OFFSET) | ||
| 115 | #define REALVIEW_SYS_MISC (REALVIEW_SYS_BASE + REALVIEW_SYS_MISC_OFFSET) | ||
| 116 | #define REALVIEW_SYS_IOSEL (REALVIEW_SYS_BASE + REALVIEW_SYS_IOSEL_OFFSET) | ||
| 117 | #define REALVIEW_SYS_TEST_OSC0 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC0_OFFSET) | ||
| 118 | #define REALVIEW_SYS_TEST_OSC1 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC1_OFFSET) | ||
| 119 | #define REALVIEW_SYS_TEST_OSC2 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC2_OFFSET) | ||
| 120 | #define REALVIEW_SYS_TEST_OSC3 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC3_OFFSET) | ||
| 121 | #define REALVIEW_SYS_TEST_OSC4 (REALVIEW_SYS_BASE + REALVIEW_SYS_TEST_OSC4_OFFSET) | ||
| 122 | |||
| 123 | /* | ||
| 124 | * Values for REALVIEW_SYS_RESET_CTRL | ||
| 125 | */ | ||
| 126 | #define REALVIEW_SYS_CTRL_RESET_CONFIGCLR 0x01 | ||
| 127 | #define REALVIEW_SYS_CTRL_RESET_CONFIGINIT 0x02 | ||
| 128 | #define REALVIEW_SYS_CTRL_RESET_DLLRESET 0x03 | ||
| 129 | #define REALVIEW_SYS_CTRL_RESET_PLLRESET 0x04 | ||
| 130 | #define REALVIEW_SYS_CTRL_RESET_POR 0x05 | ||
| 131 | #define REALVIEW_SYS_CTRL_RESET_DoC 0x06 | ||
| 132 | |||
| 133 | #define REALVIEW_SYS_CTRL_LED (1 << 0) | ||
| 134 | |||
| 135 | |||
| 136 | /* ------------------------------------------------------------------------ | ||
| 137 | * RealView control registers | ||
| 138 | * ------------------------------------------------------------------------ | ||
| 139 | */ | ||
| 140 | |||
| 141 | /* | ||
| 142 | * REALVIEW_IDFIELD | ||
| 143 | * | ||
| 144 | * 31:24 = manufacturer (0x41 = ARM) | ||
| 145 | * 23:16 = architecture (0x08 = AHB system bus, ASB processor bus) | ||
| 146 | * 15:12 = FPGA (0x3 = XVC600 or XVC600E) | ||
| 147 | * 11:4 = build value | ||
| 148 | * 3:0 = revision number (0x1 = rev B (AHB)) | ||
| 149 | */ | ||
| 150 | |||
| 151 | /* | ||
| 152 | * REALVIEW_SYS_LOCK | ||
| 153 | * control access to SYS_OSCx, SYS_CFGDATAx, SYS_RESETCTL, | ||
| 154 | * SYS_CLD, SYS_BOOTCS | ||
| 155 | */ | ||
| 156 | #define REALVIEW_SYS_LOCK_LOCKED (1 << 16) | ||
| 157 | #define REALVIEW_SYS_LOCKVAL_MASK 0xFFFF /* write 0xA05F to enable write access */ | ||
| 158 | |||
| 159 | /* | ||
| 160 | * REALVIEW_SYS_FLASH | ||
| 161 | */ | ||
| 162 | #define REALVIEW_FLASHPROG_FLVPPEN (1 << 0) /* Enable writing to flash */ | ||
| 163 | |||
| 164 | /* | ||
| 165 | * REALVIEW_INTREG | ||
| 166 | * - used to acknowledge and control MMCI and UART interrupts | ||
| 167 | */ | ||
| 168 | #define REALVIEW_INTREG_WPROT 0x00 /* MMC protection status (no interrupt generated) */ | ||
| 169 | #define REALVIEW_INTREG_RI0 0x01 /* Ring indicator UART0 is asserted, */ | ||
| 170 | #define REALVIEW_INTREG_CARDIN 0x08 /* MMCI card in detect */ | ||
| 171 | /* write 1 to acknowledge and clear */ | ||
| 172 | #define REALVIEW_INTREG_RI1 0x02 /* Ring indicator UART1 is asserted, */ | ||
| 173 | #define REALVIEW_INTREG_CARDINSERT 0x03 /* Signal insertion of MMC card */ | ||
| 174 | |||
| 175 | /* | ||
| 176 | * REALVIEW peripheral addresses | ||
| 177 | */ | ||
| 178 | #define REALVIEW_SCTL_BASE 0x10001000 /* System controller */ | ||
| 179 | #define REALVIEW_I2C_BASE 0x10002000 /* I2C control */ | ||
| 180 | /* Reserved 0x10003000 */ | ||
| 181 | #define REALVIEW_AACI_BASE 0x10004000 /* Audio */ | ||
| 182 | #define REALVIEW_MMCI0_BASE 0x10005000 /* MMC interface */ | ||
| 183 | #define REALVIEW_KMI0_BASE 0x10006000 /* KMI interface */ | ||
| 184 | #define REALVIEW_KMI1_BASE 0x10007000 /* KMI 2nd interface */ | ||
| 185 | #define REALVIEW_CHAR_LCD_BASE 0x10008000 /* Character LCD */ | ||
| 186 | #define REALVIEW_UART0_BASE 0x10009000 /* UART 0 */ | ||
| 187 | #define REALVIEW_UART1_BASE 0x1000A000 /* UART 1 */ | ||
| 188 | #define REALVIEW_UART2_BASE 0x1000B000 /* UART 2 */ | ||
| 189 | #define REALVIEW_UART3_BASE 0x1000C000 /* UART 3 */ | ||
| 190 | #define REALVIEW_SSP_BASE 0x1000D000 /* Synchronous Serial Port */ | ||
| 191 | #define REALVIEW_SCI_BASE 0x1000E000 /* Smart card controller */ | ||
| 192 | /* Reserved 0x1000F000 */ | ||
| 193 | #define REALVIEW_WATCHDOG_BASE 0x10010000 /* watchdog interface */ | ||
| 194 | #define REALVIEW_TIMER0_1_BASE 0x10011000 /* Timer 0 and 1 */ | ||
| 195 | #define REALVIEW_TIMER2_3_BASE 0x10012000 /* Timer 2 and 3 */ | ||
| 196 | #define REALVIEW_GPIO0_BASE 0x10013000 /* GPIO port 0 */ | ||
| 197 | #define REALVIEW_GPIO1_BASE 0x10014000 /* GPIO port 1 */ | ||
| 198 | #define REALVIEW_GPIO2_BASE 0x10015000 /* GPIO port 2 */ | ||
| 199 | /* Reserved 0x10016000 */ | ||
| 200 | #define REALVIEW_RTC_BASE 0x10017000 /* Real Time Clock */ | ||
| 201 | #define REALVIEW_DMC_BASE 0x10018000 /* DMC configuration */ | ||
| 202 | #define REALVIEW_PCI_CORE_BASE 0x10019000 /* PCI configuration */ | ||
| 203 | /* Reserved 0x1001A000 - 0x1001FFFF */ | ||
| 204 | #define REALVIEW_CLCD_BASE 0x10020000 /* CLCD */ | ||
| 205 | #define REALVIEW_DMAC_BASE 0x10030000 /* DMA controller */ | ||
| 206 | #define REALVIEW_GIC_CPU_BASE 0x10040000 /* Generic interrupt controller CPU interface */ | ||
| 207 | #define REALVIEW_GIC_DIST_BASE 0x10041000 /* Generic interrupt controller distributor */ | ||
| 208 | #define REALVIEW_SMC_BASE 0x10080000 /* SMC */ | ||
| 209 | /* Reserved 0x10090000 - 0x100EFFFF */ | ||
| 210 | |||
| 211 | #define REALVIEW_ETH_BASE 0x4E000000 /* Ethernet */ | ||
| 212 | |||
| 213 | /* PCI space */ | ||
| 214 | #define REALVIEW_PCI_BASE 0x41000000 /* PCI Interface */ | ||
| 215 | #define REALVIEW_PCI_CFG_BASE 0x42000000 | ||
| 216 | #define REALVIEW_PCI_MEM_BASE0 0x44000000 | ||
| 217 | #define REALVIEW_PCI_MEM_BASE1 0x50000000 | ||
| 218 | #define REALVIEW_PCI_MEM_BASE2 0x60000000 | ||
| 219 | /* Sizes of above maps */ | ||
| 220 | #define REALVIEW_PCI_BASE_SIZE 0x01000000 | ||
| 221 | #define REALVIEW_PCI_CFG_BASE_SIZE 0x02000000 | ||
| 222 | #define REALVIEW_PCI_MEM_BASE0_SIZE 0x0c000000 /* 32Mb */ | ||
| 223 | #define REALVIEW_PCI_MEM_BASE1_SIZE 0x10000000 /* 256Mb */ | ||
| 224 | #define REALVIEW_PCI_MEM_BASE2_SIZE 0x10000000 /* 256Mb */ | ||
| 225 | |||
| 226 | #define REALVIEW_SDRAM67_BASE 0x70000000 /* SDRAM banks 6 and 7 */ | ||
| 227 | #define REALVIEW_LT_BASE 0x80000000 /* Logic Tile expansion */ | ||
| 228 | |||
| 229 | /* | ||
| 230 | * Disk on Chip | ||
| 231 | */ | ||
| 232 | #define REALVIEW_DOC_BASE 0x2C000000 | ||
| 233 | #define REALVIEW_DOC_SIZE (16 << 20) | ||
| 234 | #define REALVIEW_DOC_PAGE_SIZE 512 | ||
| 235 | #define REALVIEW_DOC_TOTAL_PAGES (DOC_SIZE / PAGE_SIZE) | ||
| 236 | |||
| 237 | #define ERASE_UNIT_PAGES 32 | ||
| 238 | #define START_PAGE 0x80 | ||
| 239 | |||
| 240 | /* | ||
| 241 | * LED settings, bits [7:0] | ||
| 242 | */ | ||
| 243 | #define REALVIEW_SYS_LED0 (1 << 0) | ||
| 244 | #define REALVIEW_SYS_LED1 (1 << 1) | ||
| 245 | #define REALVIEW_SYS_LED2 (1 << 2) | ||
| 246 | #define REALVIEW_SYS_LED3 (1 << 3) | ||
| 247 | #define REALVIEW_SYS_LED4 (1 << 4) | ||
| 248 | #define REALVIEW_SYS_LED5 (1 << 5) | ||
| 249 | #define REALVIEW_SYS_LED6 (1 << 6) | ||
| 250 | #define REALVIEW_SYS_LED7 (1 << 7) | ||
| 251 | |||
| 252 | #define ALL_LEDS 0xFF | ||
| 253 | |||
| 254 | #define LED_BANK REALVIEW_SYS_LED | ||
| 255 | |||
| 256 | /* | ||
| 257 | * Control registers | ||
| 258 | */ | ||
| 259 | #define REALVIEW_IDFIELD_OFFSET 0x0 /* RealView build information */ | ||
| 260 | #define REALVIEW_FLASHPROG_OFFSET 0x4 /* Flash devices */ | ||
| 261 | #define REALVIEW_INTREG_OFFSET 0x8 /* Interrupt control */ | ||
| 262 | #define REALVIEW_DECODE_OFFSET 0xC /* Fitted logic modules */ | ||
| 263 | |||
| 264 | /* ------------------------------------------------------------------------ | ||
| 265 | * Interrupts - bit assignment (primary) | ||
| 266 | * ------------------------------------------------------------------------ | ||
| 267 | */ | ||
| 268 | #define INT_WDOGINT 0 /* Watchdog timer */ | ||
| 269 | #define INT_SOFTINT 1 /* Software interrupt */ | ||
| 270 | #define INT_COMMRx 2 /* Debug Comm Rx interrupt */ | ||
| 271 | #define INT_COMMTx 3 /* Debug Comm Tx interrupt */ | ||
| 272 | #define INT_TIMERINT0_1 4 /* Timer 0 and 1 */ | ||
| 273 | #define INT_TIMERINT2_3 5 /* Timer 2 and 3 */ | ||
| 274 | #define INT_GPIOINT0 6 /* GPIO 0 */ | ||
| 275 | #define INT_GPIOINT1 7 /* GPIO 1 */ | ||
| 276 | #define INT_GPIOINT2 8 /* GPIO 2 */ | ||
| 277 | /* 9 reserved */ | ||
| 278 | #define INT_RTCINT 10 /* Real Time Clock */ | ||
| 279 | #define INT_SSPINT 11 /* Synchronous Serial Port */ | ||
| 280 | #define INT_UARTINT0 12 /* UART 0 on development chip */ | ||
| 281 | #define INT_UARTINT1 13 /* UART 1 on development chip */ | ||
| 282 | #define INT_UARTINT2 14 /* UART 2 on development chip */ | ||
| 283 | #define INT_UARTINT3 15 /* UART 3 on development chip */ | ||
| 284 | #define INT_SCIINT 16 /* Smart Card Interface */ | ||
| 285 | #define INT_MMCI0A 17 /* Multimedia Card 0A */ | ||
| 286 | #define INT_MMCI0B 18 /* Multimedia Card 0B */ | ||
| 287 | #define INT_AACI 19 /* Audio Codec */ | ||
| 288 | #define INT_KMI0 20 /* Keyboard/Mouse port 0 */ | ||
| 289 | #define INT_KMI1 21 /* Keyboard/Mouse port 1 */ | ||
| 290 | #define INT_CHARLCD 22 /* Character LCD */ | ||
| 291 | #define INT_CLCDINT 23 /* CLCD controller */ | ||
| 292 | #define INT_DMAINT 24 /* DMA controller */ | ||
| 293 | #define INT_PWRFAILINT 25 /* Power failure */ | ||
| 294 | #define INT_PISMO 26 | ||
| 295 | #define INT_DoC 27 /* Disk on Chip memory controller */ | ||
| 296 | #define INT_ETH 28 /* Ethernet controller */ | ||
| 297 | #define INT_USB 29 /* USB controller */ | ||
| 298 | #define INT_TSPENINT 30 /* Touchscreen pen */ | ||
| 299 | #define INT_TSKPADINT 31 /* Touchscreen keypad */ | ||
| 300 | |||
| 301 | /* | ||
| 302 | * Interrupt bit positions | ||
| 303 | * | ||
| 304 | */ | ||
| 305 | #define INTMASK_WDOGINT (1 << INT_WDOGINT) | ||
| 306 | #define INTMASK_SOFTINT (1 << INT_SOFTINT) | ||
| 307 | #define INTMASK_COMMRx (1 << INT_COMMRx) | ||
| 308 | #define INTMASK_COMMTx (1 << INT_COMMTx) | ||
| 309 | #define INTMASK_TIMERINT0_1 (1 << INT_TIMERINT0_1) | ||
| 310 | #define INTMASK_TIMERINT2_3 (1 << INT_TIMERINT2_3) | ||
| 311 | #define INTMASK_GPIOINT0 (1 << INT_GPIOINT0) | ||
| 312 | #define INTMASK_GPIOINT1 (1 << INT_GPIOINT1) | ||
| 313 | #define INTMASK_GPIOINT2 (1 << INT_GPIOINT2) | ||
| 314 | #define INTMASK_RTCINT (1 << INT_RTCINT) | ||
| 315 | #define INTMASK_SSPINT (1 << INT_SSPINT) | ||
| 316 | #define INTMASK_UARTINT0 (1 << INT_UARTINT0) | ||
| 317 | #define INTMASK_UARTINT1 (1 << INT_UARTINT1) | ||
| 318 | #define INTMASK_UARTINT2 (1 << INT_UARTINT2) | ||
| 319 | #define INTMASK_UARTINT3 (1 << INT_UARTINT3) | ||
| 320 | #define INTMASK_SCIINT (1 << INT_SCIINT) | ||
| 321 | #define INTMASK_MMCI0A (1 << INT_MMCI0A) | ||
| 322 | #define INTMASK_MMCI0B (1 << INT_MMCI0B) | ||
| 323 | #define INTMASK_AACI (1 << INT_AACI) | ||
| 324 | #define INTMASK_KMI0 (1 << INT_KMI0) | ||
| 325 | #define INTMASK_KMI1 (1 << INT_KMI1) | ||
| 326 | #define INTMASK_CHARLCD (1 << INT_CHARLCD) | ||
| 327 | #define INTMASK_CLCDINT (1 << INT_CLCDINT) | ||
| 328 | #define INTMASK_DMAINT (1 << INT_DMAINT) | ||
| 329 | #define INTMASK_PWRFAILINT (1 << INT_PWRFAILINT) | ||
| 330 | #define INTMASK_PISMO (1 << INT_PISMO) | ||
| 331 | #define INTMASK_DoC (1 << INT_DoC) | ||
| 332 | #define INTMASK_ETH (1 << INT_ETH) | ||
| 333 | #define INTMASK_USB (1 << INT_USB) | ||
| 334 | #define INTMASK_TSPENINT (1 << INT_TSPENINT) | ||
| 335 | #define INTMASK_TSKPADINT (1 << INT_TSKPADINT) | ||
| 336 | |||
| 337 | #define MAXIRQNUM 31 | ||
| 338 | #define MAXFIQNUM 31 | ||
| 339 | #define MAXSWINUM 31 | ||
| 340 | |||
| 341 | /* | ||
| 342 | * Application Flash | ||
| 343 | * | ||
| 344 | */ | ||
| 345 | #define FLASH_BASE REALVIEW_FLASH_BASE | ||
| 346 | #define FLASH_SIZE REALVIEW_FLASH_SIZE | ||
| 347 | #define FLASH_END (FLASH_BASE + FLASH_SIZE - 1) | ||
| 348 | #define FLASH_BLOCK_SIZE SZ_128K | ||
| 349 | |||
| 350 | /* | ||
| 351 | * Boot Flash | ||
| 352 | * | ||
| 353 | */ | ||
| 354 | #define EPROM_BASE REALVIEW_BOOT_ROM_HI | ||
| 355 | #define EPROM_SIZE REALVIEW_BOOT_ROM_SIZE | ||
| 356 | #define EPROM_END (EPROM_BASE + EPROM_SIZE - 1) | ||
| 357 | |||
| 358 | /* | ||
| 359 | * Clean base - dummy | ||
| 360 | * | ||
| 361 | */ | ||
| 362 | #define CLEAN_BASE EPROM_BASE | ||
| 363 | |||
| 364 | /* | ||
| 365 | * System controller bit assignment | ||
| 366 | */ | ||
| 367 | #define REALVIEW_REFCLK 0 | ||
| 368 | #define REALVIEW_TIMCLK 1 | ||
| 369 | |||
| 370 | #define REALVIEW_TIMER1_EnSel 15 | ||
| 371 | #define REALVIEW_TIMER2_EnSel 17 | ||
| 372 | #define REALVIEW_TIMER3_EnSel 19 | ||
| 373 | #define REALVIEW_TIMER4_EnSel 21 | ||
| 374 | |||
| 375 | |||
| 376 | #define MAX_TIMER 2 | ||
| 377 | #define MAX_PERIOD 699050 | ||
| 378 | #define TICKS_PER_uSEC 1 | ||
| 379 | |||
| 380 | /* | ||
| 381 | * These are useconds NOT ticks. | ||
| 382 | * | ||
| 383 | */ | ||
| 384 | #define mSEC_1 1000 | ||
| 385 | #define mSEC_5 (mSEC_1 * 5) | ||
| 386 | #define mSEC_10 (mSEC_1 * 10) | ||
| 387 | #define mSEC_25 (mSEC_1 * 25) | ||
| 388 | #define SEC_1 (mSEC_1 * 1000) | ||
| 389 | |||
| 390 | #define REALVIEW_CSR_BASE 0x10000000 | ||
| 391 | #define REALVIEW_CSR_SIZE 0x10000000 | ||
| 392 | |||
| 393 | #endif | ||
| 394 | |||
| 395 | /* END */ | ||
diff --git a/include/asm-arm/arch-realview/system.h b/include/asm-arm/arch-realview/system.h new file mode 100644 index 000000000000..9f8fcbca0869 --- /dev/null +++ b/include/asm-arm/arch-realview/system.h | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/system.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2003 ARM Limited | ||
| 5 | * Copyright (C) 2000 Deep Blue Solutions Ltd | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | #ifndef __ASM_ARCH_SYSTEM_H | ||
| 22 | #define __ASM_ARCH_SYSTEM_H | ||
| 23 | |||
| 24 | #include <asm/hardware.h> | ||
| 25 | #include <asm/io.h> | ||
| 26 | #include <asm/arch/platform.h> | ||
| 27 | |||
| 28 | static inline void arch_idle(void) | ||
| 29 | { | ||
| 30 | /* | ||
| 31 | * This should do all the clock switching | ||
| 32 | * and wait for interrupt tricks | ||
| 33 | */ | ||
| 34 | cpu_do_idle(); | ||
| 35 | } | ||
| 36 | |||
| 37 | static inline void arch_reset(char mode) | ||
| 38 | { | ||
| 39 | unsigned int hdr_ctrl = (IO_ADDRESS(REALVIEW_SYS_BASE) + REALVIEW_SYS_RESETCTL_OFFSET); | ||
| 40 | unsigned int val; | ||
| 41 | |||
| 42 | /* | ||
| 43 | * To reset, we hit the on-board reset register | ||
| 44 | * in the system FPGA | ||
| 45 | */ | ||
| 46 | val = __raw_readl(hdr_ctrl); | ||
| 47 | val |= REALVIEW_SYS_CTRL_RESET_CONFIGCLR; | ||
| 48 | __raw_writel(val, hdr_ctrl); | ||
| 49 | } | ||
| 50 | |||
| 51 | #endif | ||
diff --git a/include/asm-arm/arch-realview/timex.h b/include/asm-arm/arch-realview/timex.h new file mode 100644 index 000000000000..5b9d82d0a5e0 --- /dev/null +++ b/include/asm-arm/arch-realview/timex.h | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/timex.h | ||
| 3 | * | ||
| 4 | * RealView architecture timex specifications | ||
| 5 | * | ||
| 6 | * Copyright (C) 2003 ARM Limited | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | #define CLOCK_TICK_RATE (50000000 / 16) | ||
diff --git a/include/asm-arm/arch-realview/uncompress.h b/include/asm-arm/arch-realview/uncompress.h new file mode 100644 index 000000000000..b5e4d360665b --- /dev/null +++ b/include/asm-arm/arch-realview/uncompress.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/uncompress.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2003 ARM Limited | ||
| 5 | * | ||
| 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 | ||
| 8 | * the Free Software Foundation; either version 2 of the License, or | ||
| 9 | * (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 19 | */ | ||
| 20 | #include <asm/hardware.h> | ||
| 21 | |||
| 22 | #define AMBA_UART_DR (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x00)) | ||
| 23 | #define AMBA_UART_LCRH (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x2c)) | ||
| 24 | #define AMBA_UART_CR (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x30)) | ||
| 25 | #define AMBA_UART_FR (*(volatile unsigned char *) (REALVIEW_UART0_BASE + 0x18)) | ||
| 26 | |||
| 27 | /* | ||
| 28 | * This does not append a newline | ||
| 29 | */ | ||
| 30 | static void putstr(const char *s) | ||
| 31 | { | ||
| 32 | while (*s) { | ||
| 33 | while (AMBA_UART_FR & (1 << 5)) | ||
| 34 | barrier(); | ||
| 35 | |||
| 36 | AMBA_UART_DR = *s; | ||
| 37 | |||
| 38 | if (*s == '\n') { | ||
| 39 | while (AMBA_UART_FR & (1 << 5)) | ||
| 40 | barrier(); | ||
| 41 | |||
| 42 | AMBA_UART_DR = '\r'; | ||
| 43 | } | ||
| 44 | s++; | ||
| 45 | } | ||
| 46 | while (AMBA_UART_FR & (1 << 3)) | ||
| 47 | barrier(); | ||
| 48 | } | ||
| 49 | |||
| 50 | /* | ||
| 51 | * nothing to do | ||
| 52 | */ | ||
| 53 | #define arch_decomp_setup() | ||
| 54 | #define arch_decomp_wdog() | ||
diff --git a/include/asm-arm/arch-realview/vmalloc.h b/include/asm-arm/arch-realview/vmalloc.h new file mode 100644 index 000000000000..0ad49af186af --- /dev/null +++ b/include/asm-arm/arch-realview/vmalloc.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* | ||
| 2 | * linux/include/asm-arm/arch-realview/vmalloc.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2003 ARM Limited | ||
| 5 | * Copyright (C) 2000 Russell King. | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License as published by | ||
| 9 | * the Free Software Foundation; either version 2 of the License, or | ||
| 10 | * (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | #define VMALLOC_END (PAGE_OFFSET + 0x18000000) | ||
diff --git a/include/asm-arm/arch-s3c2410/regs-iis.h b/include/asm-arm/arch-s3c2410/regs-iis.h index fdd62e8cd6cb..7fdde9b91cb4 100644 --- a/include/asm-arm/arch-s3c2410/regs-iis.h +++ b/include/asm-arm/arch-s3c2410/regs-iis.h | |||
| @@ -55,6 +55,7 @@ | |||
| 55 | #define S3C2410_IISMOD_16FS (0<<0) | 55 | #define S3C2410_IISMOD_16FS (0<<0) |
| 56 | #define S3C2410_IISMOD_32FS (1<<0) | 56 | #define S3C2410_IISMOD_32FS (1<<0) |
| 57 | #define S3C2410_IISMOD_48FS (2<<0) | 57 | #define S3C2410_IISMOD_48FS (2<<0) |
| 58 | #define S3C2410_IISMOD_FS_MASK (3<<0) | ||
| 58 | 59 | ||
| 59 | #define S3C2410_IISPSR (0x08) | 60 | #define S3C2410_IISPSR (0x08) |
| 60 | #define S3C2410_IISPSR_INTMASK (31<<5) | 61 | #define S3C2410_IISPSR_INTMASK (31<<5) |
diff --git a/include/asm-arm/hardware/amba_clcd.h b/include/asm-arm/hardware/amba_clcd.h index ce4cf5c1c05d..6b8d73dc1ab0 100644 --- a/include/asm-arm/hardware/amba_clcd.h +++ b/include/asm-arm/hardware/amba_clcd.h | |||
| @@ -22,7 +22,7 @@ | |||
| 22 | #define CLCD_UBAS 0x00000010 | 22 | #define CLCD_UBAS 0x00000010 |
| 23 | #define CLCD_LBAS 0x00000014 | 23 | #define CLCD_LBAS 0x00000014 |
| 24 | 24 | ||
| 25 | #ifndef CONFIG_ARCH_VERSATILE | 25 | #if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW) |
| 26 | #define CLCD_IENB 0x00000018 | 26 | #define CLCD_IENB 0x00000018 |
| 27 | #define CLCD_CNTL 0x0000001c | 27 | #define CLCD_CNTL 0x0000001c |
| 28 | #else | 28 | #else |
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h index a515e2aed829..8c454aa58ac6 100644 --- a/include/asm-i386/apic.h +++ b/include/asm-i386/apic.h | |||
| @@ -118,8 +118,7 @@ extern void release_lapic_nmi(void); | |||
| 118 | extern void disable_timer_nmi_watchdog(void); | 118 | extern void disable_timer_nmi_watchdog(void); |
| 119 | extern void enable_timer_nmi_watchdog(void); | 119 | extern void enable_timer_nmi_watchdog(void); |
| 120 | extern void nmi_watchdog_tick (struct pt_regs * regs); | 120 | extern void nmi_watchdog_tick (struct pt_regs * regs); |
| 121 | extern int APIC_init(void); | 121 | extern int APIC_init_uniprocessor (void); |
| 122 | extern void APIC_late_time_init(void); | ||
| 123 | extern void disable_APIC_timer(void); | 122 | extern void disable_APIC_timer(void); |
| 124 | extern void enable_APIC_timer(void); | 123 | extern void enable_APIC_timer(void); |
| 125 | 124 | ||
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h index 9139b89497a1..622815bf3243 100644 --- a/include/asm-i386/hw_irq.h +++ b/include/asm-i386/hw_irq.h | |||
| @@ -55,7 +55,6 @@ void init_8259A(int aeoi); | |||
| 55 | void FASTCALL(send_IPI_self(int vector)); | 55 | void FASTCALL(send_IPI_self(int vector)); |
| 56 | void init_VISWS_APIC_irqs(void); | 56 | void init_VISWS_APIC_irqs(void); |
| 57 | void setup_IO_APIC(void); | 57 | void setup_IO_APIC(void); |
| 58 | void IO_APIC_late_time_init(void); | ||
| 59 | void disable_IO_APIC(void); | 58 | void disable_IO_APIC(void); |
| 60 | void print_IO_APIC(void); | 59 | void print_IO_APIC(void); |
| 61 | int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); | 60 | int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn); |
diff --git a/include/asm-i386/mach-default/smpboot_hooks.h b/include/asm-i386/mach-default/smpboot_hooks.h index d7c70c144f9f..7f45f6311059 100644 --- a/include/asm-i386/mach-default/smpboot_hooks.h +++ b/include/asm-i386/mach-default/smpboot_hooks.h | |||
| @@ -1,6 +1,11 @@ | |||
| 1 | /* two abstractions specific to kernel/smpboot.c, mainly to cater to visws | 1 | /* two abstractions specific to kernel/smpboot.c, mainly to cater to visws |
| 2 | * which needs to alter them. */ | 2 | * which needs to alter them. */ |
| 3 | 3 | ||
| 4 | static inline void smpboot_clear_io_apic_irqs(void) | ||
| 5 | { | ||
| 6 | io_apic_irqs = 0; | ||
| 7 | } | ||
| 8 | |||
| 4 | static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) | 9 | static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) |
| 5 | { | 10 | { |
| 6 | CMOS_WRITE(0xa, 0xf); | 11 | CMOS_WRITE(0xa, 0xf); |
| @@ -27,3 +32,13 @@ static inline void smpboot_restore_warm_reset_vector(void) | |||
| 27 | 32 | ||
| 28 | *((volatile long *) phys_to_virt(0x467)) = 0; | 33 | *((volatile long *) phys_to_virt(0x467)) = 0; |
| 29 | } | 34 | } |
| 35 | |||
| 36 | static inline void smpboot_setup_io_apic(void) | ||
| 37 | { | ||
| 38 | /* | ||
| 39 | * Here we can be sure that there is an IO-APIC in the system. Let's | ||
| 40 | * go and set it up: | ||
| 41 | */ | ||
| 42 | if (!skip_ioapic_setup && nr_ioapics) | ||
| 43 | setup_IO_APIC(); | ||
| 44 | } | ||
diff --git a/include/asm-i386/mach-visws/smpboot_hooks.h b/include/asm-i386/mach-visws/smpboot_hooks.h index 14d8e0375f7a..d926471fa359 100644 --- a/include/asm-i386/mach-visws/smpboot_hooks.h +++ b/include/asm-i386/mach-visws/smpboot_hooks.h | |||
| @@ -11,7 +11,14 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) | |||
| 11 | 11 | ||
| 12 | /* for visws do nothing for any of these */ | 12 | /* for visws do nothing for any of these */ |
| 13 | 13 | ||
| 14 | static inline void smpboot_clear_io_apic_irqs(void) | ||
| 15 | { | ||
| 16 | } | ||
| 17 | |||
| 14 | static inline void smpboot_restore_warm_reset_vector(void) | 18 | static inline void smpboot_restore_warm_reset_vector(void) |
| 15 | { | 19 | { |
| 16 | } | 20 | } |
| 17 | 21 | ||
| 22 | static inline void smpboot_setup_io_apic(void) | ||
| 23 | { | ||
| 24 | } | ||
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 2b0401b93f2b..9d2579230689 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h | |||
| @@ -39,8 +39,7 @@ | |||
| 39 | #define PORT_RSA 13 | 39 | #define PORT_RSA 13 |
| 40 | #define PORT_NS16550A 14 | 40 | #define PORT_NS16550A 14 |
| 41 | #define PORT_XSCALE 15 | 41 | #define PORT_XSCALE 15 |
| 42 | #define PORT_IP3106 16 | 42 | #define PORT_MAX_8250 15 /* max port ID */ |
| 43 | #define PORT_MAX_8250 16 /* max port ID */ | ||
| 44 | 43 | ||
| 45 | /* | 44 | /* |
| 46 | * ARM specific type numbers. These are not currently guaranteed | 45 | * ARM specific type numbers. These are not currently guaranteed |
| @@ -118,7 +117,9 @@ | |||
| 118 | #define PORT_M32R_SIO 68 | 117 | #define PORT_M32R_SIO 68 |
| 119 | 118 | ||
| 120 | /*Digi jsm */ | 119 | /*Digi jsm */ |
| 121 | #define PORT_JSM 65 | 120 | #define PORT_JSM 69 |
| 121 | |||
| 122 | #define PORT_IP3106 70 | ||
| 122 | 123 | ||
| 123 | #ifdef __KERNEL__ | 124 | #ifdef __KERNEL__ |
| 124 | 125 | ||
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 14cb2718cb77..46e3c0bf3c94 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h | |||
| @@ -1055,6 +1055,7 @@ typedef struct { | |||
| 1055 | unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ | 1055 | unsigned char emu10k2_chip; /* Audigy 1 or Audigy 2. */ |
| 1056 | unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ | 1056 | unsigned char ca0102_chip; /* Audigy 1 or Audigy 2. Not SB Audigy 2 Value. */ |
| 1057 | unsigned char ca0108_chip; /* Audigy 2 Value */ | 1057 | unsigned char ca0108_chip; /* Audigy 2 Value */ |
| 1058 | unsigned char ca_cardbus_chip; /* Audigy 2 ZS Notebook */ | ||
| 1058 | unsigned char ca0151_chip; /* P16V */ | 1059 | unsigned char ca0151_chip; /* P16V */ |
| 1059 | unsigned char spk71; /* Has 7.1 speakers */ | 1060 | unsigned char spk71; /* Has 7.1 speakers */ |
| 1060 | unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */ | 1061 | unsigned char sblive51; /* SBLive! 5.1 - extout 0x11 -> center, 0x12 -> lfe */ |
diff --git a/init/main.c b/init/main.c index 4075d97e94b1..f142d4035341 100644 --- a/init/main.c +++ b/init/main.c | |||
| @@ -64,6 +64,10 @@ | |||
| 64 | #endif | 64 | #endif |
| 65 | #endif | 65 | #endif |
| 66 | 66 | ||
| 67 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 68 | #include <asm/smp.h> | ||
| 69 | #endif | ||
| 70 | |||
| 67 | /* | 71 | /* |
| 68 | * Versions of gcc older than that listed below may actually compile | 72 | * Versions of gcc older than that listed below may actually compile |
| 69 | * and link okay, but the end product can have subtle run time bugs. | 73 | * and link okay, but the end product can have subtle run time bugs. |
| @@ -310,7 +314,14 @@ extern void setup_arch(char **); | |||
| 310 | 314 | ||
| 311 | #ifndef CONFIG_SMP | 315 | #ifndef CONFIG_SMP |
| 312 | 316 | ||
| 317 | #ifdef CONFIG_X86_LOCAL_APIC | ||
| 318 | static void __init smp_init(void) | ||
| 319 | { | ||
| 320 | APIC_init_uniprocessor(); | ||
| 321 | } | ||
| 322 | #else | ||
| 313 | #define smp_init() do { } while (0) | 323 | #define smp_init() do { } while (0) |
| 324 | #endif | ||
| 314 | 325 | ||
| 315 | static inline void setup_per_cpu_areas(void) { } | 326 | static inline void setup_per_cpu_areas(void) { } |
| 316 | static inline void smp_prepare_cpus(unsigned int maxcpus) { } | 327 | static inline void smp_prepare_cpus(unsigned int maxcpus) { } |
| @@ -259,6 +259,8 @@ void __pagevec_release(struct pagevec *pvec) | |||
| 259 | pagevec_reinit(pvec); | 259 | pagevec_reinit(pvec); |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | EXPORT_SYMBOL(__pagevec_release); | ||
| 263 | |||
| 262 | /* | 264 | /* |
| 263 | * pagevec_release() for pages which are known to not be on the LRU | 265 | * pagevec_release() for pages which are known to not be on the LRU |
| 264 | * | 266 | * |
| @@ -387,6 +389,7 @@ unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping, | |||
| 387 | return pagevec_count(pvec); | 389 | return pagevec_count(pvec); |
| 388 | } | 390 | } |
| 389 | 391 | ||
| 392 | EXPORT_SYMBOL(pagevec_lookup_tag); | ||
| 390 | 393 | ||
| 391 | #ifdef CONFIG_SMP | 394 | #ifdef CONFIG_SMP |
| 392 | /* | 395 | /* |
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index e9cd8e054f25..53aeff0b783a 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
| @@ -579,6 +579,30 @@ static int __devinit snd_emu10k1_ecard_init(emu10k1_t * emu) | |||
| 579 | return 0; | 579 | return 0; |
| 580 | } | 580 | } |
| 581 | 581 | ||
| 582 | static int __devinit snd_emu10k1_cardbus_init(emu10k1_t * emu) | ||
| 583 | { | ||
| 584 | unsigned long special_port; | ||
| 585 | unsigned int value; | ||
| 586 | |||
| 587 | /* Special initialisation routine | ||
| 588 | * before the rest of the IO-Ports become active. | ||
| 589 | */ | ||
| 590 | special_port = emu->port + 0x38; | ||
| 591 | value = inl(special_port); | ||
| 592 | outl(0x00d00000, special_port); | ||
| 593 | value = inl(special_port); | ||
| 594 | outl(0x00d00001, special_port); | ||
| 595 | value = inl(special_port); | ||
| 596 | outl(0x00d0005f, special_port); | ||
| 597 | value = inl(special_port); | ||
| 598 | outl(0x00d0007f, special_port); | ||
| 599 | value = inl(special_port); | ||
| 600 | outl(0x0090007f, special_port); | ||
| 601 | value = inl(special_port); | ||
| 602 | |||
| 603 | return 0; | ||
| 604 | } | ||
| 605 | |||
| 582 | /* | 606 | /* |
| 583 | * Create the EMU10K1 instance | 607 | * Create the EMU10K1 instance |
| 584 | */ | 608 | */ |
| @@ -624,6 +648,16 @@ static emu_chip_details_t emu_chip_details[] = { | |||
| 624 | .ca0108_chip = 1, | 648 | .ca0108_chip = 1, |
| 625 | .spk71 = 1, | 649 | .spk71 = 1, |
| 626 | .ac97_chip = 1} , | 650 | .ac97_chip = 1} , |
| 651 | /* Audigy 2 ZS Notebook Cardbus card.*/ | ||
| 652 | /* Tested by James@superbug.co.uk 30th October 2005 */ | ||
| 653 | /* Not working yet, but progressing. */ | ||
| 654 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, | ||
| 655 | .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", | ||
| 656 | .id = "Audigy2", | ||
| 657 | .emu10k2_chip = 1, | ||
| 658 | .ca0108_chip = 1, | ||
| 659 | .ca_cardbus_chip = 1, | ||
| 660 | .spk71 = 1} , | ||
| 627 | {.vendor = 0x1102, .device = 0x0008, | 661 | {.vendor = 0x1102, .device = 0x0008, |
| 628 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", | 662 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", |
| 629 | .id = "Audigy2", | 663 | .id = "Audigy2", |
| @@ -1011,6 +1045,11 @@ int __devinit snd_emu10k1_create(snd_card_t * card, | |||
| 1011 | snd_emu10k1_free(emu); | 1045 | snd_emu10k1_free(emu); |
| 1012 | return err; | 1046 | return err; |
| 1013 | } | 1047 | } |
| 1048 | } else if (emu->card_capabilities->ca_cardbus_chip) { | ||
| 1049 | if ((err = snd_emu10k1_cardbus_init(emu)) < 0) { | ||
| 1050 | snd_emu10k1_free(emu); | ||
| 1051 | return err; | ||
| 1052 | } | ||
| 1014 | } else { | 1053 | } else { |
| 1015 | /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version | 1054 | /* 5.1: Enable the additional AC97 Slots. If the emu10k1 version |
| 1016 | does not support this, it shouldn't do any harm */ | 1055 | does not support this, it shouldn't do any harm */ |
