diff --git a/[refs] b/[refs] index b030c661d1a8..c12462e338ef 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 5375871d432ae9fc581014ac117b96aaee3cd0c7 +refs/heads/master: 1a5a9906d4e8d1976b701f889d8f35d54b928f25 diff --git a/trunk/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt b/trunk/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt deleted file mode 100644 index bc8ded641ab6..000000000000 --- a/trunk/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt +++ /dev/null @@ -1,63 +0,0 @@ -* FSL MPIC Message Registers - -This binding specifies what properties must be available in the device tree -representation of the message register blocks found in some FSL MPIC -implementations. - -Required properties: - - - compatible: Specifies the compatibility list for the message register - block. The type shall be and the value shall be of the form - "fsl,mpic-v-msgr", where is the version number of - the MPIC containing the message registers. - - - reg: Specifies the base physical address(s) and size(s) of the - message register block's addressable register space. The type shall be - . - - - interrupts: Specifies a list of interrupt-specifiers which are available - for receiving interrupts. Interrupt-specifier consists of two cells: first - cell is interrupt-number and second cell is level-sense. The type shall be - . - -Optional properties: - - - mpic-msgr-receive-mask: Specifies what registers in the containing block - are allowed to receive interrupts. The value is a bit mask where a set - bit at bit 'n' indicates that message register 'n' can receive interrupts. - Note that "bit 'n'" is numbered from LSB for PPC hardware. The type shall - be . If not present, then all of the message registers in the block - are available. - -Aliases: - - An alias should be created for every message register block. They are not - required, though. However, a particular implementation of this binding - may require aliases to be present. Aliases are of the form - 'mpic-msgr-block', where is an integer specifying the block's number. - Numbers shall start at 0. - -Example: - - aliases { - mpic-msgr-block0 = &mpic_msgr_block0; - mpic-msgr-block1 = &mpic_msgr_block1; - }; - - mpic_msgr_block0: mpic-msgr-block@41400 { - compatible = "fsl,mpic-v3.1-msgr"; - reg = <0x41400 0x200>; - // Message registers 0 and 2 in this block can receive interrupts on - // sources 0xb0 and 0xb2, respectively. - interrupts = <0xb0 2 0xb2 2>; - mpic-msgr-receive-mask = <0x5>; - }; - - mpic_msgr_block1: mpic-msgr-block@42400 { - compatible = "fsl,mpic-v3.1-msgr"; - reg = <0x42400 0x200>; - // Message registers 0 and 2 in this block can receive interrupts on - // sources 0xb4 and 0xb6, respectively. - interrupts = <0xb4 2 0xb6 2>; - mpic-msgr-receive-mask = <0x5>; - }; diff --git a/trunk/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/trunk/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt index dc5744636a57..2cf38bd841fd 100644 --- a/trunk/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt +++ b/trunk/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt @@ -56,27 +56,7 @@ PROPERTIES to the client. The presence of this property also mandates that any initialization related to interrupt sources shall be limited to sources explicitly referenced in the device tree. - - - big-endian - Usage: optional - Value type: - If present the MPIC will be assumed to be big-endian. Some - device-trees omit this property on MPIC nodes even when the MPIC is - in fact big-endian, so certain boards override this property. - - - single-cpu-affinity - Usage: optional - Value type: - If present the MPIC will be assumed to only be able to route - non-IPI interrupts to a single CPU at a time (EG: Freescale MPIC). - - - last-interrupt-source - Usage: optional - Value type: - Some MPICs do not correctly report the number of hardware sources - in the global feature registers. If specified, this field will - override the value read from MPIC_GREG_FEATURE_LAST_SRC. - + INTERRUPT SPECIFIER DEFINITION Interrupt specifiers consists of 4 cells encoded as diff --git a/trunk/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt b/trunk/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt index 5693877ab377..5d586e1ccaf5 100644 --- a/trunk/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt +++ b/trunk/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt @@ -6,10 +6,8 @@ Required properties: etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on the parent type. -- reg : It may contain one or two regions. The first region should contain - the address and the length of the shared message interrupt register set. - The second region should contain the address of aliased MSIIR register for - platforms that have such an alias. +- reg : should contain the address and the length of the shared message + interrupt register set. - msi-available-ranges: use style section to define which msi interrupt can be used in the 256 msi interrupts. This property is diff --git a/trunk/Documentation/filesystems/debugfs.txt b/trunk/Documentation/filesystems/debugfs.txt index 7a34f827989c..4e2575873187 100644 --- a/trunk/Documentation/filesystems/debugfs.txt +++ b/trunk/Documentation/filesystems/debugfs.txt @@ -136,7 +136,7 @@ file. void __iomem *base; }; - struct dentry *debugfs_create_regset32(const char *name, umode_t mode, + struct dentry *debugfs_create_regset32(const char *name, mode_t mode, struct dentry *parent, struct debugfs_regset32 *regset); diff --git a/trunk/Documentation/filesystems/porting b/trunk/Documentation/filesystems/porting index 74acd9618819..b4a3d765ff9a 100644 --- a/trunk/Documentation/filesystems/porting +++ b/trunk/Documentation/filesystems/porting @@ -429,9 +429,3 @@ filemap_write_and_wait_range() so that all dirty pages are synced out properly. You must also keep in mind that ->fsync() is not called with i_mutex held anymore, so if you require i_mutex locking you must make sure to take it and release it yourself. - --- -[mandatory] - d_alloc_root() is gone, along with a lot of bugs caused by code -misusing it. Replacement: d_make_root(inode). The difference is, -d_make_root() drops the reference to inode if dentry allocation fails. diff --git a/trunk/Documentation/filesystems/qnx6.txt b/trunk/Documentation/filesystems/qnx6.txt deleted file mode 100644 index 050223ea03c7..000000000000 --- a/trunk/Documentation/filesystems/qnx6.txt +++ /dev/null @@ -1,174 +0,0 @@ -The QNX6 Filesystem -=================== - -The qnx6fs is used by newer QNX operating system versions. (e.g. Neutrino) -It got introduced in QNX 6.4.0 and is used default since 6.4.1. - -Option -====== - -mmi_fs Mount filesystem as used for example by Audi MMI 3G system - -Specification -============= - -qnx6fs shares many properties with traditional Unix filesystems. It has the -concepts of blocks, inodes and directories. -On QNX it is possible to create little endian and big endian qnx6 filesystems. -This feature makes it possible to create and use a different endianness fs -for the target (QNX is used on quite a range of embedded systems) plattform -running on a different endianess. -The Linux driver handles endianness transparently. (LE and BE) - -Blocks ------- - -The space in the device or file is split up into blocks. These are a fixed -size of 512, 1024, 2048 or 4096, which is decided when the filesystem is -created. -Blockpointers are 32bit, so the maximum space that can be adressed is -2^32 * 4096 bytes or 16TB - -The superblocks ---------------- - -The superblock contains all global information about the filesystem. -Each qnx6fs got two superblocks, each one having a 64bit serial number. -That serial number is used to identify the "active" superblock. -In write mode with reach new snapshot (after each synchronous write), the -serial of the new master superblock is increased (old superblock serial + 1) - -So basically the snapshot functionality is realized by an atomic final -update of the serial number. Before updating that serial, all modifications -are done by copying all modified blocks during that specific write request -(or period) and building up a new (stable) filesystem structure under the -inactive superblock. - -Each superblock holds a set of root inodes for the different filesystem -parts. (Inode, Bitmap and Longfilenames) -Each of these root nodes holds information like total size of the stored -data and the adressing levels in that specific tree. -If the level value is 0, up to 16 direct blocks can be adressed by each -node. -Level 1 adds an additional indirect adressing level where each indirect -adressing block holds up to blocksize / 4 bytes pointers to data blocks. -Level 2 adds an additional indirect adressig block level (so, already up -to 16 * 256 * 256 = 1048576 blocks that can be adressed by such a tree)a - -Unused block pointers are always set to ~0 - regardless of root node, -indirect adressing blocks or inodes. -Data leaves are always on the lowest level. So no data is stored on upper -tree levels. - -The first Superblock is located at 0x2000. (0x2000 is the bootblock size) -The Audi MMI 3G first superblock directly starts at byte 0. -Second superblock position can either be calculated from the superblock -information (total number of filesystem blocks) or by taking the highest -device address, zeroing the last 3 bytes and then substracting 0x1000 from -that address. - -0x1000 is the size reserved for each superblock - regardless of the -blocksize of the filesystem. - -Inodes ------- - -Each object in the filesystem is represented by an inode. (index node) -The inode structure contains pointers to the filesystem blocks which contain -the data held in the object and all of the metadata about an object except -its longname. (filenames longer than 27 characters) -The metadata about an object includes the permissions, owner, group, flags, -size, number of blocks used, access time, change time and modification time. - -Object mode field is POSIX format. (which makes things easier) - -There are also pointers to the first 16 blocks, if the object data can be -adressed with 16 direct blocks. -For more than 16 blocks an indirect adressing in form of another tree is -used. (scheme is the same as the one used for the superblock root nodes) - -The filesize is stored 64bit. Inode counting starts with 1. (whilst long -filename inodes start with 0) - -Directories ------------ - -A directory is a filesystem object and has an inode just like a file. -It is a specially formatted file containing records which associate each -name with an inode number. -'.' inode number points to the directory inode -'..' inode number points to the parent directory inode -Eeach filename record additionally got a filename length field. - -One special case are long filenames or subdirectory names. -These got set a filename length field of 0xff in the corresponding directory -record plus the longfile inode number also stored in that record. -With that longfilename inode number, the longfilename tree can be walked -starting with the superblock longfilename root node pointers. - -Special files -------------- - -Symbolic links are also filesystem objects with inodes. They got a specific -bit in the inode mode field identifying them as symbolic link. -The directory entry file inode pointer points to the target file inode. - -Hard links got an inode, a directory entry, but a specific mode bit set, -no block pointers and the directory file record pointing to the target file -inode. - -Character and block special devices do not exist in QNX as those files -are handled by the QNX kernel/drivers and created in /dev independant of the -underlaying filesystem. - -Long filenames --------------- - -Long filenames are stored in a seperate adressing tree. The staring point -is the longfilename root node in the active superblock. -Each data block (tree leaves) holds one long filename. That filename is -limited to 510 bytes. The first two starting bytes are used as length field -for the actual filename. -If that structure shall fit for all allowed blocksizes, it is clear why there -is a limit of 510 bytes for the actual filename stored. - -Bitmap ------- - -The qnx6fs filesystem allocation bitmap is stored in a tree under bitmap -root node in the superblock and each bit in the bitmap represents one -filesystem block. -The first block is block 0, which starts 0x1000 after superblock start. -So for a normal qnx6fs 0x3000 (bootblock + superblock) is the physical -address at which block 0 is located. - -Bits at the end of the last bitmap block are set to 1, if the device is -smaller than addressing space in the bitmap. - -Bitmap system area ------------------- - -The bitmap itself is devided into three parts. -First the system area, that is split into two halfs. -Then userspace. - -The requirement for a static, fixed preallocated system area comes from how -qnx6fs deals with writes. -Each superblock got it's own half of the system area. So superblock #1 -always uses blocks from the lower half whilst superblock #2 just writes to -blocks represented by the upper half bitmap system area bits. - -Bitmap blocks, Inode blocks and indirect addressing blocks for those two -tree structures are treated as system blocks. - -The rational behind that is that a write request can work on a new snapshot -(system area of the inactive - resp. lower serial numbered superblock) while -at the same time there is still a complete stable filesystem structer in the -other half of the system area. - -When finished with writing (a sync write is completed, the maximum sync leap -time or a filesystem sync is requested), serial of the previously inactive -superblock atomically is increased and the fs switches over to that - then -stable declared - superblock. - -For all data outside the system area, blocks are just copied while writing. diff --git a/trunk/Documentation/ioctl/ioctl-number.txt b/trunk/Documentation/ioctl/ioctl-number.txt index 3b7488fc3373..68fbfb6529eb 100644 --- a/trunk/Documentation/ioctl/ioctl-number.txt +++ b/trunk/Documentation/ioctl/ioctl-number.txt @@ -218,7 +218,6 @@ Code Seq#(hex) Include File Comments 'h' 00-7F conflict! Charon filesystem 'h' 00-1F linux/hpet.h conflict! -'h' 80-8F fs/hfsplus/ioctl.c 'i' 00-3F linux/i2o-dev.h conflict! 'i' 0B-1F linux/ipmi.h conflict! 'i' 80-8F linux/i8k.h diff --git a/trunk/Documentation/networking/dns_resolver.txt b/trunk/Documentation/networking/dns_resolver.txt index d86adcdae420..7f531ad83285 100644 --- a/trunk/Documentation/networking/dns_resolver.txt +++ b/trunk/Documentation/networking/dns_resolver.txt @@ -102,10 +102,6 @@ implemented in the module can be called after doing: If _expiry is non-NULL, the expiry time (TTL) of the result will be returned also. -The kernel maintains an internal keyring in which it caches looked up keys. -This can be cleared by any process that has the CAP_SYS_ADMIN capability by -the use of KEYCTL_KEYRING_CLEAR on the keyring ID. - =============================== READING DNS KEYS FROM USERSPACE diff --git a/trunk/Documentation/powerpc/firmware-assisted-dump.txt b/trunk/Documentation/powerpc/firmware-assisted-dump.txt deleted file mode 100644 index 3007bc98af28..000000000000 --- a/trunk/Documentation/powerpc/firmware-assisted-dump.txt +++ /dev/null @@ -1,270 +0,0 @@ - - Firmware-Assisted Dump - ------------------------ - July 2011 - -The goal of firmware-assisted dump is to enable the dump of -a crashed system, and to do so from a fully-reset system, and -to minimize the total elapsed time until the system is back -in production use. - -- Firmware assisted dump (fadump) infrastructure is intended to replace - the existing phyp assisted dump. -- Fadump uses the same firmware interfaces and memory reservation model - as phyp assisted dump. -- Unlike phyp dump, fadump exports the memory dump through /proc/vmcore - in the ELF format in the same way as kdump. This helps us reuse the - kdump infrastructure for dump capture and filtering. -- Unlike phyp dump, userspace tool does not need to refer any sysfs - interface while reading /proc/vmcore. -- Unlike phyp dump, fadump allows user to release all the memory reserved - for dump, with a single operation of echo 1 > /sys/kernel/fadump_release_mem. -- Once enabled through kernel boot parameter, fadump can be - started/stopped through /sys/kernel/fadump_registered interface (see - sysfs files section below) and can be easily integrated with kdump - service start/stop init scripts. - -Comparing with kdump or other strategies, firmware-assisted -dump offers several strong, practical advantages: - --- Unlike kdump, the system has been reset, and loaded - with a fresh copy of the kernel. In particular, - PCI and I/O devices have been reinitialized and are - in a clean, consistent state. --- Once the dump is copied out, the memory that held the dump - is immediately available to the running kernel. And therefore, - unlike kdump, fadump doesn't need a 2nd reboot to get back - the system to the production configuration. - -The above can only be accomplished by coordination with, -and assistance from the Power firmware. The procedure is -as follows: - --- The first kernel registers the sections of memory with the - Power firmware for dump preservation during OS initialization. - These registered sections of memory are reserved by the first - kernel during early boot. - --- When a system crashes, the Power firmware will save - the low memory (boot memory of size larger of 5% of system RAM - or 256MB) of RAM to the previous registered region. It will - also save system registers, and hardware PTE's. - - NOTE: The term 'boot memory' means size of the low memory chunk - that is required for a kernel to boot successfully when - booted with restricted memory. By default, the boot memory - size will be the larger of 5% of system RAM or 256MB. - Alternatively, user can also specify boot memory size - through boot parameter 'fadump_reserve_mem=' which will - override the default calculated size. Use this option - if default boot memory size is not sufficient for second - kernel to boot successfully. - --- After the low memory (boot memory) area has been saved, the - firmware will reset PCI and other hardware state. It will - *not* clear the RAM. It will then launch the bootloader, as - normal. - --- The freshly booted kernel will notice that there is a new - node (ibm,dump-kernel) in the device tree, indicating that - there is crash data available from a previous boot. During - the early boot OS will reserve rest of the memory above - boot memory size effectively booting with restricted memory - size. This will make sure that the second kernel will not - touch any of the dump memory area. - --- User-space tools will read /proc/vmcore to obtain the contents - of memory, which holds the previous crashed kernel dump in ELF - format. The userspace tools may copy this info to disk, or - network, nas, san, iscsi, etc. as desired. - --- Once the userspace tool is done saving dump, it will echo - '1' to /sys/kernel/fadump_release_mem to release the reserved - memory back to general use, except the memory required for - next firmware-assisted dump registration. - - e.g. - # echo 1 > /sys/kernel/fadump_release_mem - -Please note that the firmware-assisted dump feature -is only available on Power6 and above systems with recent -firmware versions. - -Implementation details: ----------------------- - -During boot, a check is made to see if firmware supports -this feature on that particular machine. If it does, then -we check to see if an active dump is waiting for us. If yes -then everything but boot memory size of RAM is reserved during -early boot (See Fig. 2). This area is released once we finish -collecting the dump from user land scripts (e.g. kdump scripts) -that are run. If there is dump data, then the -/sys/kernel/fadump_release_mem file is created, and the reserved -memory is held. - -If there is no waiting dump data, then only the memory required -to hold CPU state, HPTE region, boot memory dump and elfcore -header, is reserved at the top of memory (see Fig. 1). This area -is *not* released: this region will be kept permanently reserved, -so that it can act as a receptacle for a copy of the boot memory -content in addition to CPU state and HPTE region, in the case a -crash does occur. - - o Memory Reservation during first kernel - - Low memory Top of memory - 0 boot memory size | - | | |<--Reserved dump area -->| - V V | Permanent Reservation V - +-----------+----------/ /----------+---+----+-----------+----+ - | | |CPU|HPTE| DUMP |ELF | - +-----------+----------/ /----------+---+----+-----------+----+ - | ^ - | | - \ / - ------------------------------------------- - Boot memory content gets transferred to - reserved area by firmware at the time of - crash - Fig. 1 - - o Memory Reservation during second kernel after crash - - Low memory Top of memory - 0 boot memory size | - | |<------------- Reserved dump area ----------- -->| - V V V - +-----------+----------/ /----------+---+----+-----------+----+ - | | |CPU|HPTE| DUMP |ELF | - +-----------+----------/ /----------+---+----+-----------+----+ - | | - V V - Used by second /proc/vmcore - kernel to boot - Fig. 2 - -Currently the dump will be copied from /proc/vmcore to a -a new file upon user intervention. The dump data available through -/proc/vmcore will be in ELF format. Hence the existing kdump -infrastructure (kdump scripts) to save the dump works fine with -minor modifications. - -The tools to examine the dump will be same as the ones -used for kdump. - -How to enable firmware-assisted dump (fadump): -------------------------------------- - -1. Set config option CONFIG_FA_DUMP=y and build kernel. -2. Boot into linux kernel with 'fadump=on' kernel cmdline option. -3. Optionally, user can also set 'fadump_reserve_mem=' kernel cmdline - to specify size of the memory to reserve for boot memory dump - preservation. - -NOTE: If firmware-assisted dump fails to reserve memory then it will - fallback to existing kdump mechanism if 'crashkernel=' option - is set at kernel cmdline. - -Sysfs/debugfs files: ------------- - -Firmware-assisted dump feature uses sysfs file system to hold -the control files and debugfs file to display memory reserved region. - -Here is the list of files under kernel sysfs: - - /sys/kernel/fadump_enabled - - This is used to display the fadump status. - 0 = fadump is disabled - 1 = fadump is enabled - - This interface can be used by kdump init scripts to identify if - fadump is enabled in the kernel and act accordingly. - - /sys/kernel/fadump_registered - - This is used to display the fadump registration status as well - as to control (start/stop) the fadump registration. - 0 = fadump is not registered. - 1 = fadump is registered and ready to handle system crash. - - To register fadump echo 1 > /sys/kernel/fadump_registered and - echo 0 > /sys/kernel/fadump_registered for un-register and stop the - fadump. Once the fadump is un-registered, the system crash will not - be handled and vmcore will not be captured. This interface can be - easily integrated with kdump service start/stop. - - /sys/kernel/fadump_release_mem - - This file is available only when fadump is active during - second kernel. This is used to release the reserved memory - region that are held for saving crash dump. To release the - reserved memory echo 1 to it: - - echo 1 > /sys/kernel/fadump_release_mem - - After echo 1, the content of the /sys/kernel/debug/powerpc/fadump_region - file will change to reflect the new memory reservations. - - The existing userspace tools (kdump infrastructure) can be easily - enhanced to use this interface to release the memory reserved for - dump and continue without 2nd reboot. - -Here is the list of files under powerpc debugfs: -(Assuming debugfs is mounted on /sys/kernel/debug directory.) - - /sys/kernel/debug/powerpc/fadump_region - - This file shows the reserved memory regions if fadump is - enabled otherwise this file is empty. The output format - is: - : [-] bytes, Dumped: - - e.g. - Contents when fadump is registered during first kernel - - # cat /sys/kernel/debug/powerpc/fadump_region - CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x0 - HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x0 - DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x0 - - Contents when fadump is active during second kernel - - # cat /sys/kernel/debug/powerpc/fadump_region - CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x40020 - HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x1000 - DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x10000000 - : [0x00000010000000-0x0000006ffaffff] 0x5ffb0000 bytes, Dumped: 0x5ffb0000 - -NOTE: Please refer to Documentation/filesystems/debugfs.txt on - how to mount the debugfs filesystem. - - -TODO: ------ - o Need to come up with the better approach to find out more - accurate boot memory size that is required for a kernel to - boot successfully when booted with restricted memory. - o The fadump implementation introduces a fadump crash info structure - in the scratch area before the ELF core header. The idea of introducing - this structure is to pass some important crash info data to the second - kernel which will help second kernel to populate ELF core header with - correct data before it gets exported through /proc/vmcore. The current - design implementation does not address a possibility of introducing - additional fields (in future) to this structure without affecting - compatibility. Need to come up with the better approach to address this. - The possible approaches are: - 1. Introduce version field for version tracking, bump up the version - whenever a new field is added to the structure in future. The version - field can be used to find out what fields are valid for the current - version of the structure. - 2. Reserve the area of predefined size (say PAGE_SIZE) for this - structure and have unused area as reserved (initialized to zero) - for future field additions. - The advantage of approach 1 over 2 is we don't need to reserve extra space. ---- -Author: Mahesh Salgaonkar -This document is based on the original documentation written for phyp -assisted dump by Linas Vepstas and Manish Ahuja. diff --git a/trunk/Documentation/powerpc/mpc52xx.txt b/trunk/Documentation/powerpc/mpc52xx.txt index 0d540a31ea1a..10dd4ab93b85 100644 --- a/trunk/Documentation/powerpc/mpc52xx.txt +++ b/trunk/Documentation/powerpc/mpc52xx.txt @@ -2,7 +2,7 @@ Linux 2.6.x on MPC52xx family ----------------------------- For the latest info, go to http://www.246tNt.com/mpc52xx/ - + To compile/use : - U-Boot: @@ -10,23 +10,23 @@ To compile/use : if you wish to ). # make lite5200_defconfig # make uImage - + then, on U-boot: => tftpboot 200000 uImage => tftpboot 400000 pRamdisk => bootm 200000 400000 - + - DBug: # dn -i zImage.initrd.lite5200 - + Some remarks : - The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100 diff --git a/trunk/Documentation/powerpc/phyp-assisted-dump.txt b/trunk/Documentation/powerpc/phyp-assisted-dump.txt new file mode 100644 index 000000000000..ad340205d96a --- /dev/null +++ b/trunk/Documentation/powerpc/phyp-assisted-dump.txt @@ -0,0 +1,127 @@ + + Hypervisor-Assisted Dump + ------------------------ + November 2007 + +The goal of hypervisor-assisted dump is to enable the dump of +a crashed system, and to do so from a fully-reset system, and +to minimize the total elapsed time until the system is back +in production use. + +As compared to kdump or other strategies, hypervisor-assisted +dump offers several strong, practical advantages: + +-- Unlike kdump, the system has been reset, and loaded + with a fresh copy of the kernel. In particular, + PCI and I/O devices have been reinitialized and are + in a clean, consistent state. +-- As the dump is performed, the dumped memory becomes + immediately available to the system for normal use. +-- After the dump is completed, no further reboots are + required; the system will be fully usable, and running + in its normal, production mode on its normal kernel. + +The above can only be accomplished by coordination with, +and assistance from the hypervisor. The procedure is +as follows: + +-- When a system crashes, the hypervisor will save + the low 256MB of RAM to a previously registered + save region. It will also save system state, system + registers, and hardware PTE's. + +-- After the low 256MB area has been saved, the + hypervisor will reset PCI and other hardware state. + It will *not* clear RAM. It will then launch the + bootloader, as normal. + +-- The freshly booted kernel will notice that there + is a new node (ibm,dump-kernel) in the device tree, + indicating that there is crash data available from + a previous boot. It will boot into only 256MB of RAM, + reserving the rest of system memory. + +-- Userspace tools will parse /sys/kernel/release_region + and read /proc/vmcore to obtain the contents of memory, + which holds the previous crashed kernel. The userspace + tools may copy this info to disk, or network, nas, san, + iscsi, etc. as desired. + + For Example: the values in /sys/kernel/release-region + would look something like this (address-range pairs). + CPU:0x177fee000-0x10000: HPTE:0x177ffe020-0x1000: / + DUMP:0x177fff020-0x10000000, 0x10000000-0x16F1D370A + +-- As the userspace tools complete saving a portion of + dump, they echo an offset and size to + /sys/kernel/release_region to release the reserved + memory back to general use. + + An example of this is: + "echo 0x40000000 0x10000000 > /sys/kernel/release_region" + which will release 256MB at the 1GB boundary. + +Please note that the hypervisor-assisted dump feature +is only available on Power6-based systems with recent +firmware versions. + +Implementation details: +---------------------- + +During boot, a check is made to see if firmware supports +this feature on this particular machine. If it does, then +we check to see if a active dump is waiting for us. If yes +then everything but 256 MB of RAM is reserved during early +boot. This area is released once we collect a dump from user +land scripts that are run. If there is dump data, then +the /sys/kernel/release_region file is created, and +the reserved memory is held. + +If there is no waiting dump data, then only the highest +256MB of the ram is reserved as a scratch area. This area +is *not* released: this region will be kept permanently +reserved, so that it can act as a receptacle for a copy +of the low 256MB in the case a crash does occur. See, +however, "open issues" below, as to whether +such a reserved region is really needed. + +Currently the dump will be copied from /proc/vmcore to a +a new file upon user intervention. The starting address +to be read and the range for each data point in provided +in /sys/kernel/release_region. + +The tools to examine the dump will be same as the ones +used for kdump. + +General notes: +-------------- +Security: please note that there are potential security issues +with any sort of dump mechanism. In particular, plaintext +(unencrypted) data, and possibly passwords, may be present in +the dump data. Userspace tools must take adequate precautions to +preserve security. + +Open issues/ToDo: +------------ + o The various code paths that tell the hypervisor that a crash + occurred, vs. it simply being a normal reboot, should be + reviewed, and possibly clarified/fixed. + + o Instead of using /sys/kernel, should there be a /sys/dump + instead? There is a dump_subsys being created by the s390 code, + perhaps the pseries code should use a similar layout as well. + + o Is reserving a 256MB region really required? The goal of + reserving a 256MB scratch area is to make sure that no + important crash data is clobbered when the hypervisor + save low mem to the scratch area. But, if one could assure + that nothing important is located in some 256MB area, then + it would not need to be reserved. Something that can be + improved in subsequent versions. + + o Still working the kdump team to integrate this with kdump, + some work remains but this would not affect the current + patches. + + o Still need to write a shell script, to copy the dump away. + Currently I am parsing it manually. diff --git a/trunk/Documentation/security/00-INDEX b/trunk/Documentation/security/00-INDEX index eeed1de546d4..99b85d39751c 100644 --- a/trunk/Documentation/security/00-INDEX +++ b/trunk/Documentation/security/00-INDEX @@ -6,8 +6,6 @@ SELinux.txt - how to get started with the SELinux security enhancement. Smack.txt - documentation on the Smack Linux Security Module. -Yama.txt - - documentation on the Yama Linux Security Module. apparmor.txt - documentation on the AppArmor security extension. credentials.txt diff --git a/trunk/Documentation/security/Yama.txt b/trunk/Documentation/security/Yama.txt deleted file mode 100644 index a9511f179069..000000000000 --- a/trunk/Documentation/security/Yama.txt +++ /dev/null @@ -1,65 +0,0 @@ -Yama is a Linux Security Module that collects a number of system-wide DAC -security protections that are not handled by the core kernel itself. To -select it at boot time, specify "security=yama" (though this will disable -any other LSM). - -Yama is controlled through sysctl in /proc/sys/kernel/yama: - -- ptrace_scope - -============================================================== - -ptrace_scope: - -As Linux grows in popularity, it will become a larger target for -malware. One particularly troubling weakness of the Linux process -interfaces is that a single user is able to examine the memory and -running state of any of their processes. For example, if one application -(e.g. Pidgin) was compromised, it would be possible for an attacker to -attach to other running processes (e.g. Firefox, SSH sessions, GPG agent, -etc) to extract additional credentials and continue to expand the scope -of their attack without resorting to user-assisted phishing. - -This is not a theoretical problem. SSH session hijacking -(http://www.storm.net.nz/projects/7) and arbitrary code injection -(http://c-skills.blogspot.com/2007/05/injectso.html) attacks already -exist and remain possible if ptrace is allowed to operate as before. -Since ptrace is not commonly used by non-developers and non-admins, system -builders should be allowed the option to disable this debugging system. - -For a solution, some applications use prctl(PR_SET_DUMPABLE, ...) to -specifically disallow such ptrace attachment (e.g. ssh-agent), but many -do not. A more general solution is to only allow ptrace directly from a -parent to a child process (i.e. direct "gdb EXE" and "strace EXE" still -work), or with CAP_SYS_PTRACE (i.e. "gdb --pid=PID", and "strace -p PID" -still work as root). - -For software that has defined application-specific relationships -between a debugging process and its inferior (crash handlers, etc), -prctl(PR_SET_PTRACER, pid, ...) can be used. An inferior can declare which -other process (and its descendents) are allowed to call PTRACE_ATTACH -against it. Only one such declared debugging process can exists for -each inferior at a time. For example, this is used by KDE, Chromium, and -Firefox's crash handlers, and by Wine for allowing only Wine processes -to ptrace each other. If a process wishes to entirely disable these ptrace -restrictions, it can call prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, ...) -so that any otherwise allowed process (even those in external pid namespaces) -may attach. - -The sysctl settings are: - -0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other - process running under the same uid, as long as it is dumpable (i.e. - did not transition uids, start privileged, or have called - prctl(PR_SET_DUMPABLE...) already). - -1 - restricted ptrace: a process must have a predefined relationship - with the inferior it wants to call PTRACE_ATTACH on. By default, - this relationship is that of only its descendants when the above - classic criteria is also met. To change the relationship, an - inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare - an allowed debugger PID to call PTRACE_ATTACH on the inferior. - -The original children-only logic was based on the restrictions in grsecurity. - -============================================================== diff --git a/trunk/Documentation/security/keys.txt b/trunk/Documentation/security/keys.txt index 787717091421..fcbe7a703405 100644 --- a/trunk/Documentation/security/keys.txt +++ b/trunk/Documentation/security/keys.txt @@ -554,10 +554,6 @@ The keyctl syscall functions are: process must have write permission on the keyring, and it must be a keyring (or else error ENOTDIR will result). - This function can also be used to clear special kernel keyrings if they - are appropriately marked if the user has CAP_SYS_ADMIN capability. The - DNS resolver cache keyring is an example of this. - (*) Link a key into a keyring: diff --git a/trunk/MAINTAINERS b/trunk/MAINTAINERS index 58f60356f071..92f9924c4335 100644 --- a/trunk/MAINTAINERS +++ b/trunk/MAINTAINERS @@ -4071,7 +4071,7 @@ M: Josh Boyer M: Matt Porter W: http://www.penguinppc.org/ L: linuxppc-dev@lists.ozlabs.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git +T: git git://git.infradead.org/users/jwboyer/powerpc-4xx.git S: Maintained F: arch/powerpc/platforms/40x/ F: arch/powerpc/platforms/44x/ diff --git a/trunk/arch/alpha/kernel/binfmt_loader.c b/trunk/arch/alpha/kernel/binfmt_loader.c index d1f474d1d44d..3fcfad410130 100644 --- a/trunk/arch/alpha/kernel/binfmt_loader.c +++ b/trunk/arch/alpha/kernel/binfmt_loader.c @@ -46,7 +46,6 @@ static struct linux_binfmt loader_format = { static int __init init_loader_binfmt(void) { - insert_binfmt(&loader_format); - return 0; + return insert_binfmt(&loader_format); } arch_initcall(init_loader_binfmt); diff --git a/trunk/arch/arm/mach-tegra/fuse.c b/trunk/arch/arm/mach-tegra/fuse.c index ea49bd93c6b9..1fa26d9a1a68 100644 --- a/trunk/arch/arm/mach-tegra/fuse.c +++ b/trunk/arch/arm/mach-tegra/fuse.c @@ -19,7 +19,6 @@ #include #include -#include #include @@ -59,7 +58,6 @@ unsigned long long tegra_chip_uid(void) hi = fuse_readl(FUSE_UID_HIGH); return (hi << 32ull) | lo; } -EXPORT_SYMBOL(tegra_chip_uid); int tegra_sku_id(void) { diff --git a/trunk/arch/m68k/Kconfig b/trunk/arch/m68k/Kconfig index d318c606c888..ae413d4a8bb7 100644 --- a/trunk/arch/m68k/Kconfig +++ b/trunk/arch/m68k/Kconfig @@ -7,7 +7,6 @@ config M68K select GENERIC_IRQ_SHOW select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS select GENERIC_CPU_DEVICES - select FPU if MMU config RWSEM_GENERIC_SPINLOCK bool @@ -25,6 +24,9 @@ config ARCH_HAS_ILOG2_U64 config GENERIC_CLOCKEVENTS bool +config GENERIC_CMOS_UPDATE + def_bool !MMU + config GENERIC_GPIO bool @@ -65,9 +67,6 @@ config CPU_HAS_NO_MULDIV64 config CPU_HAS_ADDRESS_SPACES bool -config FPU - bool - config HZ int default 1000 if CLEOPATRA diff --git a/trunk/arch/m68k/include/asm/m5206sim.h b/trunk/arch/m68k/include/asm/m5206sim.h index 69722366b084..9015eadd5c00 100644 --- a/trunk/arch/m68k/include/asm/m5206sim.h +++ b/trunk/arch/m68k/include/asm/m5206sim.h @@ -100,11 +100,11 @@ #define MCFDMA_BASE1 (MCF_MBAR + 0x240) /* Base address DMA 1 */ #if defined(CONFIG_NETtel) -#define MCFUART_BASE0 (MCF_MBAR + 0x180) /* Base address UART0 */ -#define MCFUART_BASE1 (MCF_MBAR + 0x140) /* Base address UART1 */ +#define MCFUART_BASE1 0x180 /* Base address of UART1 */ +#define MCFUART_BASE2 0x140 /* Base address of UART2 */ #else -#define MCFUART_BASE0 (MCF_MBAR + 0x140) /* Base address UART0 */ -#define MCFUART_BASE1 (MCF_MBAR + 0x180) /* Base address UART1 */ +#define MCFUART_BASE1 0x140 /* Base address of UART1 */ +#define MCFUART_BASE2 0x180 /* Base address of UART2 */ #endif /* @@ -112,8 +112,6 @@ */ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ -#define MCF_IRQ_UART0 73 /* UART0 */ -#define MCF_IRQ_UART1 74 /* UART1 */ /* * Generic GPIO diff --git a/trunk/arch/m68k/include/asm/m520xsim.h b/trunk/arch/m68k/include/asm/m520xsim.h index 17f2aab9cf97..eda62de7e607 100644 --- a/trunk/arch/m68k/include/asm/m520xsim.h +++ b/trunk/arch/m68k/include/asm/m520xsim.h @@ -48,21 +48,8 @@ #define MCFINT_UART1 27 /* Interrupt number for UART1 */ #define MCFINT_UART2 28 /* Interrupt number for UART2 */ #define MCFINT_QSPI 31 /* Interrupt number for QSPI */ -#define MCFINT_FECRX0 36 /* Interrupt number for FEC RX */ -#define MCFINT_FECTX0 40 /* Interrupt number for FEC RX */ -#define MCFINT_FECENTC0 42 /* Interrupt number for FEC RX */ #define MCFINT_PIT1 4 /* Interrupt number for PIT1 (PIT0 in processor) */ -#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) -#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) -#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) - -#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) -#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) -#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) - -#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) - /* * SDRAM configuration registers. */ @@ -157,25 +144,15 @@ /* * UART module. */ -#define MCFUART_BASE0 0xFC060000 /* Base address of UART0 */ -#define MCFUART_BASE1 0xFC064000 /* Base address of UART1 */ -#define MCFUART_BASE2 0xFC068000 /* Base address of UART2 */ +#define MCFUART_BASE1 0xFC060000 /* Base address of UART1 */ +#define MCFUART_BASE2 0xFC064000 /* Base address of UART2 */ +#define MCFUART_BASE3 0xFC068000 /* Base address of UART2 */ /* * FEC module. */ -#define MCFFEC_BASE0 0xFC030000 /* Base of FEC ethernet */ -#define MCFFEC_SIZE0 0x800 /* Register set size */ - -/* - * QSPI module. - */ -#define MCFQSPI_BASE 0xFC05C000 /* Base of QSPI module */ -#define MCFQSPI_SIZE 0x40 /* Register set size */ - -#define MCFQSPI_CS0 46 -#define MCFQSPI_CS1 47 -#define MCFQSPI_CS2 27 +#define MCFFEC_BASE 0xFC030000 /* Base of FEC ethernet */ +#define MCFFEC_SIZE 0x800 /* Register set size */ /* * Reset Control Unit. diff --git a/trunk/arch/m68k/include/asm/m523xsim.h b/trunk/arch/m68k/include/asm/m523xsim.h index 075062d4eecd..6235921eca4e 100644 --- a/trunk/arch/m68k/include/asm/m523xsim.h +++ b/trunk/arch/m68k/include/asm/m523xsim.h @@ -35,23 +35,8 @@ #define MCFINT_VECBASE 64 /* Vector base number */ #define MCFINT_UART0 13 /* Interrupt number for UART0 */ -#define MCFINT_UART1 14 /* Interrupt number for UART1 */ -#define MCFINT_UART2 15 /* Interrupt number for UART2 */ -#define MCFINT_QSPI 18 /* Interrupt number for QSPI */ -#define MCFINT_FECRX0 23 /* Interrupt number for FEC */ -#define MCFINT_FECTX0 27 /* Interrupt number for FEC */ -#define MCFINT_FECENTC0 29 /* Interrupt number for FEC */ #define MCFINT_PIT1 36 /* Interrupt number for PIT1 */ - -#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) -#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) -#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) - -#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) -#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) -#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) - -#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) +#define MCFINT_QSPI 18 /* Interrupt number for QSPI */ /* * SDRAM configuration registers. @@ -65,8 +50,8 @@ /* * Reset Control Unit (relative to IPSBAR). */ -#define MCF_RCR (MCF_IPSBAR + 0x110000) -#define MCF_RSR (MCF_IPSBAR + 0x110001) +#define MCF_RCR 0x110000 +#define MCF_RSR 0x110001 #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ @@ -74,26 +59,15 @@ /* * UART module. */ -#define MCFUART_BASE0 (MCF_IPSBAR + 0x200) -#define MCFUART_BASE1 (MCF_IPSBAR + 0x240) -#define MCFUART_BASE2 (MCF_IPSBAR + 0x280) +#define MCFUART_BASE1 (MCF_IPSBAR + 0x200) +#define MCFUART_BASE2 (MCF_IPSBAR + 0x240) +#define MCFUART_BASE3 (MCF_IPSBAR + 0x280) /* * FEC ethernet module. */ -#define MCFFEC_BASE0 (MCF_IPSBAR + 0x1000) -#define MCFFEC_SIZE0 0x800 - -/* - * QSPI module. - */ -#define MCFQSPI_BASE (MCF_IPSBAR + 0x340) -#define MCFQSPI_SIZE 0x40 - -#define MCFQSPI_CS0 91 -#define MCFQSPI_CS1 92 -#define MCFQSPI_CS2 103 -#define MCFQSPI_CS3 99 +#define MCFFEC_BASE (MCF_IPSBAR + 0x1000) +#define MCFFEC_SIZE 0x800 /* * GPIO module. diff --git a/trunk/arch/m68k/include/asm/m5249sim.h b/trunk/arch/m68k/include/asm/m5249sim.h index 7f0c2c3660fd..805714ca8d7d 100644 --- a/trunk/arch/m68k/include/asm/m5249sim.h +++ b/trunk/arch/m68k/include/asm/m5249sim.h @@ -76,19 +76,8 @@ /* * UART module. */ -#define MCFUART_BASE0 (MCF_MBAR + 0x1c0) /* Base address UART0 */ -#define MCFUART_BASE1 (MCF_MBAR + 0x200) /* Base address UART1 */ - -/* - * QSPI module. - */ -#define MCFQSPI_BASE (MCF_MBAR + 0x300) /* Base address QSPI */ -#define MCFQSPI_SIZE 0x40 /* Register set size */ - -#define MCFQSPI_CS0 29 -#define MCFQSPI_CS1 24 -#define MCFQSPI_CS2 21 -#define MCFQSPI_CS3 22 +#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ +#define MCFUART_BASE2 0x200 /* Base address of UART2 */ /* * DMA unit base addresses. @@ -119,9 +108,6 @@ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ -#define MCF_IRQ_UART0 73 /* UART0 */ -#define MCF_IRQ_UART1 74 /* UART1 */ - /* * General purpose IO registers (in MBAR2). */ diff --git a/trunk/arch/m68k/include/asm/m5272sim.h b/trunk/arch/m68k/include/asm/m5272sim.h index a58f1760d858..759c2b07a994 100644 --- a/trunk/arch/m68k/include/asm/m5272sim.h +++ b/trunk/arch/m68k/include/asm/m5272sim.h @@ -68,8 +68,8 @@ #define MCFSIM_DCMR1 0x5c /* DRAM 1 Mask reg (r/w) */ #define MCFSIM_DCCR1 0x63 /* DRAM 1 Control reg (r/w) */ -#define MCFUART_BASE0 (MCF_MBAR + 0x100) /* Base address UART0 */ -#define MCFUART_BASE1 (MCF_MBAR + 0x140) /* Base address UART1 */ +#define MCFUART_BASE1 0x100 /* Base address of UART1 */ +#define MCFUART_BASE2 0x140 /* Base address of UART2 */ #define MCFSIM_PACNT (MCF_MBAR + 0x80) /* Port A Control (r/w) */ #define MCFSIM_PADDR (MCF_MBAR + 0x84) /* Port A Direction (r/w) */ @@ -88,9 +88,6 @@ #define MCFTIMER_BASE3 (MCF_MBAR + 0x240) /* Base address TIMER4 */ #define MCFTIMER_BASE4 (MCF_MBAR + 0x260) /* Base address TIMER3 */ -#define MCFFEC_BASE0 (MCF_MBAR + 0x840) /* Base FEC ethernet */ -#define MCFFEC_SIZE0 0x1d0 - /* * Define system peripheral IRQ usage. */ @@ -104,8 +101,8 @@ #define MCF_IRQ_TIMER2 70 /* Timer 2 */ #define MCF_IRQ_TIMER3 71 /* Timer 3 */ #define MCF_IRQ_TIMER4 72 /* Timer 4 */ -#define MCF_IRQ_UART0 73 /* UART 0 */ -#define MCF_IRQ_UART1 74 /* UART 1 */ +#define MCF_IRQ_UART1 73 /* UART 1 */ +#define MCF_IRQ_UART2 74 /* UART 2 */ #define MCF_IRQ_PLIP 75 /* PLIC 2Khz Periodic */ #define MCF_IRQ_PLIA 76 /* PLIC Asynchronous */ #define MCF_IRQ_USB0 77 /* USB Endpoint 0 */ @@ -117,9 +114,9 @@ #define MCF_IRQ_USB6 83 /* USB Endpoint 6 */ #define MCF_IRQ_USB7 84 /* USB Endpoint 7 */ #define MCF_IRQ_DMA 85 /* DMA Controller */ -#define MCF_IRQ_FECRX0 86 /* Ethernet Receiver */ -#define MCF_IRQ_FECTX0 87 /* Ethernet Transmitter */ -#define MCF_IRQ_FECENTC0 88 /* Ethernet Non-Time Critical */ +#define MCF_IRQ_ERX 86 /* Ethernet Receiver */ +#define MCF_IRQ_ETX 87 /* Ethernet Transmitter */ +#define MCF_IRQ_ENTC 88 /* Ethernet Non-Time Critical */ #define MCF_IRQ_QSPI 89 /* Queued Serial Interface */ #define MCF_IRQ_EINT5 90 /* External Interrupt 5 */ #define MCF_IRQ_EINT6 91 /* External Interrupt 6 */ diff --git a/trunk/arch/m68k/include/asm/m527xsim.h b/trunk/arch/m68k/include/asm/m527xsim.h index 83db8106f50a..758810ef91ec 100644 --- a/trunk/arch/m68k/include/asm/m527xsim.h +++ b/trunk/arch/m68k/include/asm/m527xsim.h @@ -38,29 +38,8 @@ #define MCFINT_UART1 14 /* Interrupt number for UART1 */ #define MCFINT_UART2 15 /* Interrupt number for UART2 */ #define MCFINT_QSPI 18 /* Interrupt number for QSPI */ -#define MCFINT_FECRX0 23 /* Interrupt number for FEC0 */ -#define MCFINT_FECTX0 27 /* Interrupt number for FEC0 */ -#define MCFINT_FECENTC0 29 /* Interrupt number for FEC0 */ #define MCFINT_PIT1 36 /* Interrupt number for PIT1 */ -#define MCFINT2_VECBASE 128 /* Vector base number 2 */ -#define MCFINT2_FECRX1 23 /* Interrupt number for FEC1 */ -#define MCFINT2_FECTX1 27 /* Interrupt number for FEC1 */ -#define MCFINT2_FECENTC1 29 /* Interrupt number for FEC1 */ - -#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) -#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) -#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) - -#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) -#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) -#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) -#define MCF_IRQ_FECRX1 (MCFINT2_VECBASE + MCFINT2_FECRX1) -#define MCF_IRQ_FECTX1 (MCFINT2_VECBASE + MCFINT2_FECTX1) -#define MCF_IRQ_FECENTC1 (MCFINT2_VECBASE + MCFINT2_FECENTC1) - -#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) - /* * SDRAM configuration registers. */ @@ -93,9 +72,9 @@ /* * UART module. */ -#define MCFUART_BASE0 (MCF_IPSBAR + 0x200) -#define MCFUART_BASE1 (MCF_IPSBAR + 0x240) -#define MCFUART_BASE2 (MCF_IPSBAR + 0x280) +#define MCFUART_BASE1 (MCF_IPSBAR + 0x200) +#define MCFUART_BASE2 (MCF_IPSBAR + 0x240) +#define MCFUART_BASE3 (MCF_IPSBAR + 0x280) /* * FEC ethernet module. @@ -105,28 +84,6 @@ #define MCFFEC_BASE1 (MCF_IPSBAR + 0x1800) #define MCFFEC_SIZE1 0x800 -/* - * QSPI module. - */ -#define MCFQSPI_BASE (MCF_IPSBAR + 0x340) -#define MCFQSPI_SIZE 0x40 - -#ifdef CONFIG_M5271 -#define MCFQSPI_CS0 91 -#define MCFQSPI_CS1 92 -#define MCFQSPI_CS2 99 -#define MCFQSPI_CS3 103 -#endif -#ifdef CONFIG_M5275 -#define MCFQSPI_CS0 59 -#define MCFQSPI_CS1 60 -#define MCFQSPI_CS2 61 -#define MCFQSPI_CS3 62 -#endif - -/* - * GPIO module. - */ #ifdef CONFIG_M5271 #define MCFGPIO_PODR_ADDR (MCF_IPSBAR + 0x100000) #define MCFGPIO_PODR_DATAH (MCF_IPSBAR + 0x100001) @@ -328,8 +285,8 @@ /* * Reset Control Unit (relative to IPSBAR). */ -#define MCF_RCR (MCF_IPSBAR + 0x110000) -#define MCF_RSR (MCF_IPSBAR + 0x110001) +#define MCF_RCR 0x110000 +#define MCF_RSR 0x110001 #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ diff --git a/trunk/arch/m68k/include/asm/m528xsim.h b/trunk/arch/m68k/include/asm/m528xsim.h index 569476fba18c..d798bd5df56c 100644 --- a/trunk/arch/m68k/include/asm/m528xsim.h +++ b/trunk/arch/m68k/include/asm/m528xsim.h @@ -35,24 +35,9 @@ #define MCFINT_VECBASE 64 /* Vector base number */ #define MCFINT_UART0 13 /* Interrupt number for UART0 */ -#define MCFINT_UART1 14 /* Interrupt number for UART1 */ -#define MCFINT_UART2 15 /* Interrupt number for UART2 */ #define MCFINT_QSPI 18 /* Interrupt number for QSPI */ -#define MCFINT_FECRX0 23 /* Interrupt number for FEC */ -#define MCFINT_FECTX0 27 /* Interrupt number for FEC */ -#define MCFINT_FECENTC0 29 /* Interrupt number for FEC */ #define MCFINT_PIT1 55 /* Interrupt number for PIT1 */ -#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) -#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) -#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) - -#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) -#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) -#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) - -#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) - /* * SDRAM configuration registers. */ @@ -73,26 +58,15 @@ /* * UART module. */ -#define MCFUART_BASE0 (MCF_IPSBAR + 0x00000200) -#define MCFUART_BASE1 (MCF_IPSBAR + 0x00000240) -#define MCFUART_BASE2 (MCF_IPSBAR + 0x00000280) +#define MCFUART_BASE1 (MCF_IPSBAR + 0x00000200) +#define MCFUART_BASE2 (MCF_IPSBAR + 0x00000240) +#define MCFUART_BASE3 (MCF_IPSBAR + 0x00000280) /* * FEC ethernet module. */ -#define MCFFEC_BASE0 (MCF_IPSBAR + 0x00001000) -#define MCFFEC_SIZE0 0x800 - -/* - * QSPI module. - */ -#define MCFQSPI_IOBASE (MCF_IPSBAR + 0x340) -#define MCFQSPI_SIZE 0x40 - -#define MCFQSPI_CS0 147 -#define MCFQSPI_CS1 148 -#define MCFQSPI_CS2 149 -#define MCFQSPI_CS3 150 +#define MCFFEC_BASE (MCF_IPSBAR + 0x00001000) +#define MCFFEC_SIZE 0x800 /* * GPIO registers @@ -272,8 +246,8 @@ /* * Reset Control Unit (relative to IPSBAR). */ -#define MCF_RCR (MCF_IPSBAR + 0x110000) -#define MCF_RSR (MCF_IPSBAR + 0x110001) +#define MCF_RCR 0x110000 +#define MCF_RSR 0x110001 #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ diff --git a/trunk/arch/m68k/include/asm/m5307sim.h b/trunk/arch/m68k/include/asm/m5307sim.h index 3bc3adaa7ee0..8f8609fcc9b8 100644 --- a/trunk/arch/m68k/include/asm/m5307sim.h +++ b/trunk/arch/m68k/include/asm/m5307sim.h @@ -117,11 +117,11 @@ * UART module. */ #if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3) -#define MCFUART_BASE0 (MCF_MBAR + 0x200) /* Base address UART0 */ -#define MCFUART_BASE1 (MCF_MBAR + 0x1c0) /* Base address UART1 */ +#define MCFUART_BASE1 0x200 /* Base address of UART1 */ +#define MCFUART_BASE2 0x1c0 /* Base address of UART2 */ #else -#define MCFUART_BASE0 (MCF_MBAR + 0x1c0) /* Base address UART0 */ -#define MCFUART_BASE1 (MCF_MBAR + 0x200) /* Base address UART1 */ +#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ +#define MCFUART_BASE2 0x200 /* Base address of UART2 */ #endif /* @@ -176,8 +176,6 @@ */ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ -#define MCF_IRQ_UART0 73 /* UART0 */ -#define MCF_IRQ_UART1 74 /* UART1 */ /****************************************************************************/ #endif /* m5307sim_h */ diff --git a/trunk/arch/m68k/include/asm/m532xsim.h b/trunk/arch/m68k/include/asm/m532xsim.h index 29b66e21413a..ba4cc784f574 100644 --- a/trunk/arch/m68k/include/asm/m532xsim.h +++ b/trunk/arch/m68k/include/asm/m532xsim.h @@ -24,19 +24,6 @@ #define MCFINT_UART1 27 /* Interrupt number for UART1 */ #define MCFINT_UART2 28 /* Interrupt number for UART2 */ #define MCFINT_QSPI 31 /* Interrupt number for QSPI */ -#define MCFINT_FECRX0 36 /* Interrupt number for FEC */ -#define MCFINT_FECTX0 40 /* Interrupt number for FEC */ -#define MCFINT_FECENTC0 42 /* Interrupt number for FEC */ - -#define MCF_IRQ_UART0 (MCFINT_VECBASE + MCFINT_UART0) -#define MCF_IRQ_UART1 (MCFINT_VECBASE + MCFINT_UART1) -#define MCF_IRQ_UART2 (MCFINT_VECBASE + MCFINT_UART2) - -#define MCF_IRQ_FECRX0 (MCFINT_VECBASE + MCFINT_FECRX0) -#define MCF_IRQ_FECTX0 (MCFINT_VECBASE + MCFINT_FECTX0) -#define MCF_IRQ_FECENTC0 (MCFINT_VECBASE + MCFINT_FECENTC0) - -#define MCF_IRQ_QSPI (MCFINT_VECBASE + MCFINT_QSPI) #define MCF_WTM_WCR MCF_REG16(0xFC098000) @@ -95,25 +82,9 @@ /* * UART module. */ -#define MCFUART_BASE0 0xFC060000 /* Base address of UART1 */ -#define MCFUART_BASE1 0xFC064000 /* Base address of UART2 */ -#define MCFUART_BASE2 0xFC068000 /* Base address of UART3 */ - -/* - * FEC module. - */ -#define MCFFEC_BASE0 0xFC030000 /* Base address of FEC0 */ -#define MCFFEC_SIZE0 0x800 /* Size of FEC0 region */ - -/* - * QSPI module. - */ -#define MCFQSPI_BASE 0xFC058000 /* Base address of QSPI */ -#define MCFQSPI_SIZE 0x40 /* Size of QSPI region */ - -#define MCFQSPI_CS0 84 -#define MCFQSPI_CS1 85 -#define MCFQSPI_CS2 86 +#define MCFUART_BASE1 0xFC060000 /* Base address of UART1 */ +#define MCFUART_BASE2 0xFC064000 /* Base address of UART2 */ +#define MCFUART_BASE3 0xFC068000 /* Base address of UART3 */ /* * Timer module. diff --git a/trunk/arch/m68k/include/asm/m5407sim.h b/trunk/arch/m68k/include/asm/m5407sim.h index 79f58dd6a83d..51e00b00b8a6 100644 --- a/trunk/arch/m68k/include/asm/m5407sim.h +++ b/trunk/arch/m68k/include/asm/m5407sim.h @@ -85,8 +85,8 @@ #define MCFTIMER_BASE1 (MCF_MBAR + 0x140) /* Base of TIMER1 */ #define MCFTIMER_BASE2 (MCF_MBAR + 0x180) /* Base of TIMER2 */ -#define MCFUART_BASE0 (MCF_MBAR + 0x1c0) /* Base address UART0 */ -#define MCFUART_BASE1 (MCF_MBAR + 0x200) /* Base address UART1 */ +#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ +#define MCFUART_BASE2 0x200 /* Base address of UART2 */ #define MCFSIM_PADDR (MCF_MBAR + 0x244) #define MCFSIM_PADAT (MCF_MBAR + 0x248) @@ -139,8 +139,6 @@ */ #define MCF_IRQ_TIMER 30 /* Timer0, Level 6 */ #define MCF_IRQ_PROFILER 31 /* Timer1, Level 7 */ -#define MCF_IRQ_UART0 73 /* UART0 */ -#define MCF_IRQ_UART1 74 /* UART1 */ /****************************************************************************/ #endif /* m5407sim_h */ diff --git a/trunk/arch/m68k/include/asm/m54xxsim.h b/trunk/arch/m68k/include/asm/m54xxsim.h index ae56b8848a9d..1ed8bfb02772 100644 --- a/trunk/arch/m68k/include/asm/m54xxsim.h +++ b/trunk/arch/m68k/include/asm/m54xxsim.h @@ -31,20 +31,16 @@ /* * UART module. */ -#define MCFUART_BASE0 (MCF_MBAR + 0x8600) /* Base address UART0 */ -#define MCFUART_BASE1 (MCF_MBAR + 0x8700) /* Base address UART1 */ -#define MCFUART_BASE2 (MCF_MBAR + 0x8800) /* Base address UART2 */ -#define MCFUART_BASE3 (MCF_MBAR + 0x8900) /* Base address UART3 */ +#define MCFUART_BASE1 0x8600 /* Base address of UART1 */ +#define MCFUART_BASE2 0x8700 /* Base address of UART2 */ +#define MCFUART_BASE3 0x8800 /* Base address of UART3 */ +#define MCFUART_BASE4 0x8900 /* Base address of UART4 */ /* * Define system peripheral IRQ usage. */ -#define MCF_IRQ_TIMER (MCFINT_VECBASE + 54) /* Slice Timer 0 */ -#define MCF_IRQ_PROFILER (MCFINT_VECBASE + 53) /* Slice Timer 1 */ -#define MCF_IRQ_UART0 (MCFINT_VECBASE + 35) -#define MCF_IRQ_UART1 (MCFINT_VECBASE + 34) -#define MCF_IRQ_UART2 (MCFINT_VECBASE + 33) -#define MCF_IRQ_UART3 (MCFINT_VECBASE + 32) +#define MCF_IRQ_TIMER (64 + 54) /* Slice Timer 0 */ +#define MCF_IRQ_PROFILER (64 + 53) /* Slice Timer 1 */ /* * Generic GPIO support diff --git a/trunk/arch/m68k/include/asm/machdep.h b/trunk/arch/m68k/include/asm/machdep.h index 825c1c813196..789f3b2de0e9 100644 --- a/trunk/arch/m68k/include/asm/machdep.h +++ b/trunk/arch/m68k/include/asm/machdep.h @@ -22,6 +22,8 @@ extern unsigned int (*mach_get_ss)(void); extern int (*mach_get_rtc_pll)(struct rtc_pll_info *); extern int (*mach_set_rtc_pll)(struct rtc_pll_info *); extern int (*mach_set_clock_mmss)(unsigned long); +extern void (*mach_gettod)(int *year, int *mon, int *day, int *hour, + int *min, int *sec); extern void (*mach_reset)( void ); extern void (*mach_halt)( void ); extern void (*mach_power_off)( void ); @@ -33,8 +35,9 @@ extern void (*mach_l2_flush) (int); extern void (*mach_beep) (unsigned int, unsigned int); /* Hardware clock functions */ -extern void hw_timer_init(irq_handler_t handler); +extern void hw_timer_init(void); extern unsigned long hw_timer_offset(void); +extern irqreturn_t arch_timer_interrupt(int irq, void *dummy); extern void config_BSP(char *command, int len); diff --git a/trunk/arch/m68k/include/asm/mcfqspi.h b/trunk/arch/m68k/include/asm/mcfqspi.h index 7b51416ccae2..7fe631972f1f 100644 --- a/trunk/arch/m68k/include/asm/mcfqspi.h +++ b/trunk/arch/m68k/include/asm/mcfqspi.h @@ -21,6 +21,17 @@ #ifndef mcfqspi_h #define mcfqspi_h +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) +#define MCFQSPI_IOBASE (MCF_IPSBAR + 0x340) +#elif defined(CONFIG_M5249) +#define MCFQSPI_IOBASE (MCF_MBAR + 0x300) +#elif defined(CONFIG_M520x) +#define MCFQSPI_IOBASE 0xFC05C000 +#elif defined(CONFIG_M532x) +#define MCFQSPI_IOBASE 0xFC058000 +#endif +#define MCFQSPI_IOSIZE 0x40 + /** * struct mcfqspi_cs_control - chip select control for the coldfire qspi driver * @setup: setup the control; allocate gpio's, etc. May be NULL. diff --git a/trunk/arch/m68k/include/asm/mcfuart.h b/trunk/arch/m68k/include/asm/mcfuart.h index 2d3bc774b3c5..2abedff0a694 100644 --- a/trunk/arch/m68k/include/asm/mcfuart.h +++ b/trunk/arch/m68k/include/asm/mcfuart.h @@ -41,10 +41,7 @@ struct mcf_platform_uart { #define MCFUART_UTF 0x28 /* Transmitter FIFO (r/w) */ #define MCFUART_URF 0x2c /* Receiver FIFO (r/w) */ #define MCFUART_UFPD 0x30 /* Frac Prec. Divider (r/w) */ -#endif -#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \ - defined(CONFIG_M5249) || defined(CONFIG_M5307) || \ - defined(CONFIG_M5407) +#else #define MCFUART_UIVR 0x30 /* Interrupt Vector (r/w) */ #endif #define MCFUART_UIPR 0x34 /* Input Port (r) */ diff --git a/trunk/arch/m68k/kernel/process.c b/trunk/arch/m68k/kernel/process.c index c54ef927e483..6cf4bd6e34f8 100644 --- a/trunk/arch/m68k/kernel/process.c +++ b/trunk/arch/m68k/kernel/process.c @@ -1,378 +1,5 @@ -/* - * linux/arch/m68k/kernel/process.c - * - * Copyright (C) 1995 Hamish Macdonald - * - * 68060 fixes by Jesper Skov - */ - -/* - * This file handles the architecture-dependent parts of process handling.. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -asmlinkage void ret_from_fork(void); - - -/* - * Return saved PC from a blocked thread - */ -unsigned long thread_saved_pc(struct task_struct *tsk) -{ - struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; - /* Check whether the thread is blocked in resume() */ - if (in_sched_functions(sw->retpc)) - return ((unsigned long *)sw->a6)[1]; - else - return sw->retpc; -} - -/* - * The idle loop on an m68k.. - */ -static void default_idle(void) -{ - if (!need_resched()) -#if defined(MACH_ATARI_ONLY) - /* block out HSYNC on the atari (falcon) */ - __asm__("stop #0x2200" : : : "cc"); -#else - __asm__("stop #0x2000" : : : "cc"); -#endif -} - -void (*idle)(void) = default_idle; - -/* - * The idle thread. There's no useful work to be - * done, so just try to conserve power and have a - * low exit latency (ie sit in a loop waiting for - * somebody to say that they'd like to reschedule) - */ -void cpu_idle(void) -{ - /* endless idle loop with no priority at all */ - while (1) { - while (!need_resched()) - idle(); - schedule_preempt_disabled(); - } -} - -void machine_restart(char * __unused) -{ - if (mach_reset) - mach_reset(); - for (;;); -} - -void machine_halt(void) -{ - if (mach_halt) - mach_halt(); - for (;;); -} - -void machine_power_off(void) -{ - if (mach_power_off) - mach_power_off(); - for (;;); -} - -void (*pm_power_off)(void) = machine_power_off; -EXPORT_SYMBOL(pm_power_off); - -void show_regs(struct pt_regs * regs) -{ - printk("\n"); - printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", - regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); - printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", - regs->orig_d0, regs->d0, regs->a2, regs->a1); - printk("A0: %08lx D5: %08lx D4: %08lx\n", - regs->a0, regs->d5, regs->d4); - printk("D3: %08lx D2: %08lx D1: %08lx\n", - regs->d3, regs->d2, regs->d1); - if (!(regs->sr & PS_S)) - printk("USP: %08lx\n", rdusp()); -} - -/* - * Create a kernel thread - */ -int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - int pid; - mm_segment_t fs; - - fs = get_fs(); - set_fs (KERNEL_DS); - - { - register long retval __asm__ ("d0"); - register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; - - retval = __NR_clone; - __asm__ __volatile__ - ("clrl %%d2\n\t" - "trap #0\n\t" /* Linux/m68k system call */ - "tstl %0\n\t" /* child or parent */ - "jne 1f\n\t" /* parent - jump */ -#ifdef CONFIG_MMU - "lea %%sp@(%c7),%6\n\t" /* reload current */ - "movel %6@,%6\n\t" -#endif - "movel %3,%%sp@-\n\t" /* push argument */ - "jsr %4@\n\t" /* call fn */ - "movel %0,%%d1\n\t" /* pass exit value */ - "movel %2,%%d0\n\t" /* exit */ - "trap #0\n" - "1:" - : "+d" (retval) - : "i" (__NR_clone), "i" (__NR_exit), - "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), - "i" (-THREAD_SIZE) - : "d2"); - - pid = retval; - } - - set_fs (fs); - return pid; -} -EXPORT_SYMBOL(kernel_thread); - -void flush_thread(void) -{ - current->thread.fs = __USER_DS; -#ifdef CONFIG_FPU - if (!FPU_IS_EMU) { - unsigned long zero = 0; - asm volatile("frestore %0": :"m" (zero)); - } -#endif -} - -/* - * "m68k_fork()".. By the time we get here, the - * non-volatile registers have also been saved on the - * stack. We do some ugly pointer stuff here.. (see - * also copy_thread) - */ - -asmlinkage int m68k_fork(struct pt_regs *regs) -{ #ifdef CONFIG_MMU - return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); +#include "process_mm.c" #else - return -EINVAL; +#include "process_no.c" #endif -} - -asmlinkage int m68k_vfork(struct pt_regs *regs) -{ - return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, - NULL, NULL); -} - -asmlinkage int m68k_clone(struct pt_regs *regs) -{ - unsigned long clone_flags; - unsigned long newsp; - int __user *parent_tidptr, *child_tidptr; - - /* syscall2 puts clone_flags in d1 and usp in d2 */ - clone_flags = regs->d1; - newsp = regs->d2; - parent_tidptr = (int __user *)regs->d3; - child_tidptr = (int __user *)regs->d4; - if (!newsp) - newsp = rdusp(); - return do_fork(clone_flags, newsp, regs, 0, - parent_tidptr, child_tidptr); -} - -int copy_thread(unsigned long clone_flags, unsigned long usp, - unsigned long unused, - struct task_struct * p, struct pt_regs * regs) -{ - struct pt_regs * childregs; - struct switch_stack * childstack, *stack; - unsigned long *retp; - - childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; - - *childregs = *regs; - childregs->d0 = 0; - - retp = ((unsigned long *) regs); - stack = ((struct switch_stack *) retp) - 1; - - childstack = ((struct switch_stack *) childregs) - 1; - *childstack = *stack; - childstack->retpc = (unsigned long)ret_from_fork; - - p->thread.usp = usp; - p->thread.ksp = (unsigned long)childstack; - - if (clone_flags & CLONE_SETTLS) - task_thread_info(p)->tp_value = regs->d5; - - /* - * Must save the current SFC/DFC value, NOT the value when - * the parent was last descheduled - RGH 10-08-96 - */ - p->thread.fs = get_fs().seg; - -#ifdef CONFIG_FPU - if (!FPU_IS_EMU) { - /* Copy the current fpu state */ - asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); - - if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) { - if (CPU_IS_COLDFIRE) { - asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t" - "fmovel %/fpiar,%1\n\t" - "fmovel %/fpcr,%2\n\t" - "fmovel %/fpsr,%3" - : - : "m" (p->thread.fp[0]), - "m" (p->thread.fpcntl[0]), - "m" (p->thread.fpcntl[1]), - "m" (p->thread.fpcntl[2]) - : "memory"); - } else { - asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" - "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" - : - : "m" (p->thread.fp[0]), - "m" (p->thread.fpcntl[0]) - : "memory"); - } - } - - /* Restore the state in case the fpu was busy */ - asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); - } -#endif /* CONFIG_FPU */ - - return 0; -} - -/* Fill in the fpu structure for a core dump. */ -#ifdef CONFIG_FPU -int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) -{ - char fpustate[216]; - - if (FPU_IS_EMU) { - int i; - - memcpy(fpu->fpcntl, current->thread.fpcntl, 12); - memcpy(fpu->fpregs, current->thread.fp, 96); - /* Convert internal fpu reg representation - * into long double format - */ - for (i = 0; i < 24; i += 3) - fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | - ((fpu->fpregs[i] & 0x0000ffff) << 16); - return 1; - } - - /* First dump the fpu context to avoid protocol violation. */ - asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); - if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) - return 0; - - if (CPU_IS_COLDFIRE) { - asm volatile ("fmovel %/fpiar,%0\n\t" - "fmovel %/fpcr,%1\n\t" - "fmovel %/fpsr,%2\n\t" - "fmovemd %/fp0-%/fp7,%3" - : - : "m" (fpu->fpcntl[0]), - "m" (fpu->fpcntl[1]), - "m" (fpu->fpcntl[2]), - "m" (fpu->fpregs[0]) - : "memory"); - } else { - asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" - : - : "m" (fpu->fpcntl[0]) - : "memory"); - asm volatile ("fmovemx %/fp0-%/fp7,%0" - : - : "m" (fpu->fpregs[0]) - : "memory"); - } - - return 1; -} -EXPORT_SYMBOL(dump_fpu); -#endif /* CONFIG_FPU */ - -/* - * sys_execve() executes a new program. - */ -asmlinkage int sys_execve(const char __user *name, - const char __user *const __user *argv, - const char __user *const __user *envp) -{ - int error; - char * filename; - struct pt_regs *regs = (struct pt_regs *) &name; - - filename = getname(name); - error = PTR_ERR(filename); - if (IS_ERR(filename)) - return error; - error = do_execve(filename, argv, envp, regs); - putname(filename); - return error; -} - -unsigned long get_wchan(struct task_struct *p) -{ - unsigned long fp, pc; - unsigned long stack_page; - int count = 0; - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - stack_page = (unsigned long)task_stack_page(p); - fp = ((struct switch_stack *)p->thread.ksp)->a6; - do { - if (fp < stack_page+sizeof(struct thread_info) || - fp >= 8184+stack_page) - return 0; - pc = ((unsigned long *)fp)[1]; - if (!in_sched_functions(pc)) - return pc; - fp = *(unsigned long *) fp; - } while (count++ < 16); - return 0; -} diff --git a/trunk/arch/m68k/kernel/process_mm.c b/trunk/arch/m68k/kernel/process_mm.c new file mode 100644 index 000000000000..fe4186b5fc32 --- /dev/null +++ b/trunk/arch/m68k/kernel/process_mm.c @@ -0,0 +1,367 @@ +/* + * linux/arch/m68k/kernel/process.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * 68060 fixes by Jesper Skov + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +asmlinkage void ret_from_fork(void); + + +/* + * Return saved PC from a blocked thread + */ +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; + /* Check whether the thread is blocked in resume() */ + if (in_sched_functions(sw->retpc)) + return ((unsigned long *)sw->a6)[1]; + else + return sw->retpc; +} + +/* + * The idle loop on an m68k.. + */ +static void default_idle(void) +{ + if (!need_resched()) +#if defined(MACH_ATARI_ONLY) + /* block out HSYNC on the atari (falcon) */ + __asm__("stop #0x2200" : : : "cc"); +#else + __asm__("stop #0x2000" : : : "cc"); +#endif +} + +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + while (1) { + while (!need_resched()) + idle(); + schedule_preempt_disabled(); + } +} + +void machine_restart(char * __unused) +{ + if (mach_reset) + mach_reset(); + for (;;); +} + +void machine_halt(void) +{ + if (mach_halt) + mach_halt(); + for (;;); +} + +void machine_power_off(void) +{ + if (mach_power_off) + mach_power_off(); + for (;;); +} + +void (*pm_power_off)(void) = machine_power_off; +EXPORT_SYMBOL(pm_power_off); + +void show_regs(struct pt_regs * regs) +{ + printk("\n"); + printk("Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", + regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); + printk("ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", + regs->orig_d0, regs->d0, regs->a2, regs->a1); + printk("A0: %08lx D5: %08lx D4: %08lx\n", + regs->a0, regs->d5, regs->d4); + printk("D3: %08lx D2: %08lx D1: %08lx\n", + regs->d3, regs->d2, regs->d1); + if (!(regs->sr & PS_S)) + printk("USP: %08lx\n", rdusp()); +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + int pid; + mm_segment_t fs; + + fs = get_fs(); + set_fs (KERNEL_DS); + + { + register long retval __asm__ ("d0"); + register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; + + retval = __NR_clone; + __asm__ __volatile__ + ("clrl %%d2\n\t" + "trap #0\n\t" /* Linux/m68k system call */ + "tstl %0\n\t" /* child or parent */ + "jne 1f\n\t" /* parent - jump */ + "lea %%sp@(%c7),%6\n\t" /* reload current */ + "movel %6@,%6\n\t" + "movel %3,%%sp@-\n\t" /* push argument */ + "jsr %4@\n\t" /* call fn */ + "movel %0,%%d1\n\t" /* pass exit value */ + "movel %2,%%d0\n\t" /* exit */ + "trap #0\n" + "1:" + : "+d" (retval) + : "i" (__NR_clone), "i" (__NR_exit), + "r" (arg), "a" (fn), "d" (clone_arg), "r" (current), + "i" (-THREAD_SIZE) + : "d2"); + + pid = retval; + } + + set_fs (fs); + return pid; +} +EXPORT_SYMBOL(kernel_thread); + +void flush_thread(void) +{ + unsigned long zero = 0; + + current->thread.fs = __USER_DS; + if (!FPU_IS_EMU) + asm volatile("frestore %0": :"m" (zero)); +} + +/* + * "m68k_fork()".. By the time we get here, the + * non-volatile registers have also been saved on the + * stack. We do some ugly pointer stuff here.. (see + * also copy_thread) + */ + +asmlinkage int m68k_fork(struct pt_regs *regs) +{ + return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); +} + +asmlinkage int m68k_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, + NULL, NULL); +} + +asmlinkage int m68k_clone(struct pt_regs *regs) +{ + unsigned long clone_flags; + unsigned long newsp; + int __user *parent_tidptr, *child_tidptr; + + /* syscall2 puts clone_flags in d1 and usp in d2 */ + clone_flags = regs->d1; + newsp = regs->d2; + parent_tidptr = (int __user *)regs->d3; + child_tidptr = (int __user *)regs->d4; + if (!newsp) + newsp = rdusp(); + return do_fork(clone_flags, newsp, regs, 0, + parent_tidptr, child_tidptr); +} + +int copy_thread(unsigned long clone_flags, unsigned long usp, + unsigned long unused, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + struct switch_stack * childstack, *stack; + unsigned long *retp; + + childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; + + *childregs = *regs; + childregs->d0 = 0; + + retp = ((unsigned long *) regs); + stack = ((struct switch_stack *) retp) - 1; + + childstack = ((struct switch_stack *) childregs) - 1; + *childstack = *stack; + childstack->retpc = (unsigned long)ret_from_fork; + + p->thread.usp = usp; + p->thread.ksp = (unsigned long)childstack; + + if (clone_flags & CLONE_SETTLS) + task_thread_info(p)->tp_value = regs->d5; + + /* + * Must save the current SFC/DFC value, NOT the value when + * the parent was last descheduled - RGH 10-08-96 + */ + p->thread.fs = get_fs().seg; + + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); + + if (!CPU_IS_060 ? p->thread.fpstate[0] : p->thread.fpstate[2]) { + if (CPU_IS_COLDFIRE) { + asm volatile ("fmovemd %/fp0-%/fp7,%0\n\t" + "fmovel %/fpiar,%1\n\t" + "fmovel %/fpcr,%2\n\t" + "fmovel %/fpsr,%3" + : + : "m" (p->thread.fp[0]), + "m" (p->thread.fpcntl[0]), + "m" (p->thread.fpcntl[1]), + "m" (p->thread.fpcntl[2]) + : "memory"); + } else { + asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" + : + : "m" (p->thread.fp[0]), + "m" (p->thread.fpcntl[0]) + : "memory"); + } + } + + /* Restore the state in case the fpu was busy */ + asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); + } + + return 0; +} + +/* Fill in the fpu structure for a core dump. */ + +int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu) +{ + char fpustate[216]; + + if (FPU_IS_EMU) { + int i; + + memcpy(fpu->fpcntl, current->thread.fpcntl, 12); + memcpy(fpu->fpregs, current->thread.fp, 96); + /* Convert internal fpu reg representation + * into long double format + */ + for (i = 0; i < 24; i += 3) + fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | + ((fpu->fpregs[i] & 0x0000ffff) << 16); + return 1; + } + + /* First dump the fpu context to avoid protocol violation. */ + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!CPU_IS_060 ? !fpustate[0] : !fpustate[2]) + return 0; + + if (CPU_IS_COLDFIRE) { + asm volatile ("fmovel %/fpiar,%0\n\t" + "fmovel %/fpcr,%1\n\t" + "fmovel %/fpsr,%2\n\t" + "fmovemd %/fp0-%/fp7,%3" + : + : "m" (fpu->fpcntl[0]), + "m" (fpu->fpcntl[1]), + "m" (fpu->fpcntl[2]), + "m" (fpu->fpregs[0]) + : "memory"); + } else { + asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" + : + : "m" (fpu->fpcntl[0]) + : "memory"); + asm volatile ("fmovemx %/fp0-%/fp7,%0" + : + : "m" (fpu->fpregs[0]) + : "memory"); + } + + return 1; +} +EXPORT_SYMBOL(dump_fpu); + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(const char __user *name, + const char __user *const __user *argv, + const char __user *const __user *envp) +{ + int error; + char * filename; + struct pt_regs *regs = (struct pt_regs *) &name; + + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + return error; + error = do_execve(filename, argv, envp, regs); + putname(filename); + return error; +} + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)task_stack_page(p); + fp = ((struct switch_stack *)p->thread.ksp)->a6; + do { + if (fp < stack_page+sizeof(struct thread_info) || + fp >= 8184+stack_page) + return 0; + pc = ((unsigned long *)fp)[1]; + if (!in_sched_functions(pc)) + return pc; + fp = *(unsigned long *) fp; + } while (count++ < 16); + return 0; +} diff --git a/trunk/arch/m68k/kernel/process_no.c b/trunk/arch/m68k/kernel/process_no.c new file mode 100644 index 000000000000..f7fe6c348595 --- /dev/null +++ b/trunk/arch/m68k/kernel/process_no.c @@ -0,0 +1,404 @@ +/* + * linux/arch/m68knommu/kernel/process.c + * + * Copyright (C) 1995 Hamish Macdonald + * + * 68060 fixes by Jesper Skov + * + * uClinux changes + * Copyright (C) 2000-2002, David McCullough + */ + +/* + * This file handles the architecture-dependent parts of process handling.. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +asmlinkage void ret_from_fork(void); + +/* + * The following aren't currently used. + */ +void (*pm_idle)(void); +EXPORT_SYMBOL(pm_idle); + +void (*pm_power_off)(void); +EXPORT_SYMBOL(pm_power_off); + +/* + * The idle loop on an m68knommu.. + */ +static void default_idle(void) +{ + local_irq_disable(); + while (!need_resched()) { + /* This stop will re-enable interrupts */ + __asm__("stop #0x2000" : : : "cc"); + local_irq_disable(); + } + local_irq_enable(); +} + +void (*idle)(void) = default_idle; + +/* + * The idle thread. There's no useful work to be + * done, so just try to conserve power and have a + * low exit latency (ie sit in a loop waiting for + * somebody to say that they'd like to reschedule) + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + while (1) { + idle(); + schedule_preempt_disabled(); + } +} + +void machine_restart(char * __unused) +{ + if (mach_reset) + mach_reset(); + for (;;); +} + +void machine_halt(void) +{ + if (mach_halt) + mach_halt(); + for (;;); +} + +void machine_power_off(void) +{ + if (mach_power_off) + mach_power_off(); + for (;;); +} + +void show_regs(struct pt_regs * regs) +{ + printk(KERN_NOTICE "\n"); + printk(KERN_NOTICE "Format %02x Vector: %04x PC: %08lx Status: %04x %s\n", + regs->format, regs->vector, regs->pc, regs->sr, print_tainted()); + printk(KERN_NOTICE "ORIG_D0: %08lx D0: %08lx A2: %08lx A1: %08lx\n", + regs->orig_d0, regs->d0, regs->a2, regs->a1); + printk(KERN_NOTICE "A0: %08lx D5: %08lx D4: %08lx\n", + regs->a0, regs->d5, regs->d4); + printk(KERN_NOTICE "D3: %08lx D2: %08lx D1: %08lx\n", + regs->d3, regs->d2, regs->d1); + if (!(regs->sr & PS_S)) + printk(KERN_NOTICE "USP: %08lx\n", rdusp()); +} + +/* + * Create a kernel thread + */ +int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + int retval; + long clone_arg = flags | CLONE_VM; + mm_segment_t fs; + + fs = get_fs(); + set_fs(KERNEL_DS); + + __asm__ __volatile__ ( + "movel %%sp, %%d2\n\t" + "movel %5, %%d1\n\t" + "movel %1, %%d0\n\t" + "trap #0\n\t" + "cmpl %%sp, %%d2\n\t" + "jeq 1f\n\t" + "movel %3, %%sp@-\n\t" + "jsr %4@\n\t" + "movel %2, %%d0\n\t" + "trap #0\n" + "1:\n\t" + "movel %%d0, %0\n" + : "=d" (retval) + : "i" (__NR_clone), + "i" (__NR_exit), + "a" (arg), + "a" (fn), + "a" (clone_arg) + : "cc", "%d0", "%d1", "%d2"); + + set_fs(fs); + return retval; +} +EXPORT_SYMBOL(kernel_thread); + +void flush_thread(void) +{ +#ifdef CONFIG_FPU + unsigned long zero = 0; +#endif + + current->thread.fs = __USER_DS; +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) + asm volatile (".chip 68k/68881\n\t" + "frestore %0\n\t" + ".chip 68k" : : "m" (zero)); +#endif +} + +/* + * "m68k_fork()".. By the time we get here, the + * non-volatile registers have also been saved on the + * stack. We do some ugly pointer stuff here.. (see + * also copy_thread) + */ + +asmlinkage int m68k_fork(struct pt_regs *regs) +{ + /* fork almost works, enough to trick you into looking elsewhere :-( */ + return(-EINVAL); +} + +asmlinkage int m68k_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); +} + +asmlinkage int m68k_clone(struct pt_regs *regs) +{ + unsigned long clone_flags; + unsigned long newsp; + + /* syscall2 puts clone_flags in d1 and usp in d2 */ + clone_flags = regs->d1; + newsp = regs->d2; + if (!newsp) + newsp = rdusp(); + return do_fork(clone_flags, newsp, regs, 0, NULL, NULL); +} + +int copy_thread(unsigned long clone_flags, + unsigned long usp, unsigned long topstk, + struct task_struct * p, struct pt_regs * regs) +{ + struct pt_regs * childregs; + struct switch_stack * childstack, *stack; + unsigned long *retp; + + childregs = (struct pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1; + + *childregs = *regs; + childregs->d0 = 0; + + retp = ((unsigned long *) regs); + stack = ((struct switch_stack *) retp) - 1; + + childstack = ((struct switch_stack *) childregs) - 1; + *childstack = *stack; + childstack->retpc = (unsigned long)ret_from_fork; + + p->thread.usp = usp; + p->thread.ksp = (unsigned long)childstack; + + if (clone_flags & CLONE_SETTLS) + task_thread_info(p)->tp_value = regs->d5; + + /* + * Must save the current SFC/DFC value, NOT the value when + * the parent was last descheduled - RGH 10-08-96 + */ + p->thread.fs = get_fs().seg; + +#ifdef CONFIG_FPU + if (!FPU_IS_EMU) { + /* Copy the current fpu state */ + asm volatile ("fsave %0" : : "m" (p->thread.fpstate[0]) : "memory"); + + if (p->thread.fpstate[0]) + asm volatile ("fmovemx %/fp0-%/fp7,%0\n\t" + "fmoveml %/fpiar/%/fpcr/%/fpsr,%1" + : : "m" (p->thread.fp[0]), "m" (p->thread.fpcntl[0]) + : "memory"); + /* Restore the state in case the fpu was busy */ + asm volatile ("frestore %0" : : "m" (p->thread.fpstate[0])); + } +#endif + + return 0; +} + +/* Fill in the fpu structure for a core dump. */ + +int dump_fpu(struct pt_regs *regs, struct user_m68kfp_struct *fpu) +{ +#ifdef CONFIG_FPU + char fpustate[216]; + + if (FPU_IS_EMU) { + int i; + + memcpy(fpu->fpcntl, current->thread.fpcntl, 12); + memcpy(fpu->fpregs, current->thread.fp, 96); + /* Convert internal fpu reg representation + * into long double format + */ + for (i = 0; i < 24; i += 3) + fpu->fpregs[i] = ((fpu->fpregs[i] & 0xffff0000) << 15) | + ((fpu->fpregs[i] & 0x0000ffff) << 16); + return 1; + } + + /* First dump the fpu context to avoid protocol violation. */ + asm volatile ("fsave %0" :: "m" (fpustate[0]) : "memory"); + if (!fpustate[0]) + return 0; + + asm volatile ("fmovem %/fpiar/%/fpcr/%/fpsr,%0" + :: "m" (fpu->fpcntl[0]) + : "memory"); + asm volatile ("fmovemx %/fp0-%/fp7,%0" + :: "m" (fpu->fpregs[0]) + : "memory"); +#endif + return 1; +} +EXPORT_SYMBOL(dump_fpu); + +/* + * Generic dumping code. Used for panic and debug. + */ +void dump(struct pt_regs *fp) +{ + unsigned long *sp; + unsigned char *tp; + int i; + + printk(KERN_EMERG "\nCURRENT PROCESS:\n\n"); + printk(KERN_EMERG "COMM=%s PID=%d\n", current->comm, current->pid); + + if (current->mm) { + printk(KERN_EMERG "TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n", + (int) current->mm->start_code, + (int) current->mm->end_code, + (int) current->mm->start_data, + (int) current->mm->end_data, + (int) current->mm->end_data, + (int) current->mm->brk); + printk(KERN_EMERG "USER-STACK=%08x KERNEL-STACK=%08x\n\n", + (int) current->mm->start_stack, + (int)(((unsigned long) current) + THREAD_SIZE)); + } + + printk(KERN_EMERG "PC: %08lx\n", fp->pc); + printk(KERN_EMERG "SR: %08lx SP: %08lx\n", (long) fp->sr, (long) fp); + printk(KERN_EMERG "d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", + fp->d0, fp->d1, fp->d2, fp->d3); + printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", + fp->d4, fp->d5, fp->a0, fp->a1); + printk(KERN_EMERG "\nUSP: %08x TRAPFRAME: %p\n", + (unsigned int) rdusp(), fp); + + printk(KERN_EMERG "\nCODE:"); + tp = ((unsigned char *) fp->pc) - 0x20; + for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) { + if ((i % 0x10) == 0) + printk(KERN_EMERG "%p: ", tp + i); + printk("%08x ", (int) *sp++); + } + printk(KERN_EMERG "\n"); + + printk(KERN_EMERG "KERNEL STACK:"); + tp = ((unsigned char *) fp) - 0x40; + for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) { + if ((i % 0x10) == 0) + printk(KERN_EMERG "%p: ", tp + i); + printk("%08x ", (int) *sp++); + } + printk(KERN_EMERG "\n"); + + printk(KERN_EMERG "USER STACK:"); + tp = (unsigned char *) (rdusp() - 0x10); + for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) { + if ((i % 0x10) == 0) + printk(KERN_EMERG "%p: ", tp + i); + printk("%08x ", (int) *sp++); + } + printk(KERN_EMERG "\n"); +} + +/* + * sys_execve() executes a new program. + */ +asmlinkage int sys_execve(const char *name, + const char *const *argv, + const char *const *envp) +{ + int error; + char * filename; + struct pt_regs *regs = (struct pt_regs *) &name; + + filename = getname(name); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + return error; + error = do_execve(filename, argv, envp, regs); + putname(filename); + return error; +} + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, pc; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = (unsigned long)p; + fp = ((struct switch_stack *)p->thread.ksp)->a6; + do { + if (fp < stack_page+sizeof(struct thread_info) || + fp >= THREAD_SIZE-8+stack_page) + return 0; + pc = ((unsigned long *)fp)[1]; + if (!in_sched_functions(pc)) + return pc; + fp = *(unsigned long *) fp; + } while (count++ < 16); + return 0; +} + +/* + * Return saved PC of a blocked thread. + */ +unsigned long thread_saved_pc(struct task_struct *tsk) +{ + struct switch_stack *sw = (struct switch_stack *)tsk->thread.ksp; + + /* Check whether the thread is blocked in resume() */ + if (in_sched_functions(sw->retpc)) + return ((unsigned long *)sw->a6)[1]; + else + return sw->retpc; +} + diff --git a/trunk/arch/m68k/kernel/ptrace.c b/trunk/arch/m68k/kernel/ptrace.c index 149a05f8b9ee..07a417550e94 100644 --- a/trunk/arch/m68k/kernel/ptrace.c +++ b/trunk/arch/m68k/kernel/ptrace.c @@ -1,305 +1,5 @@ -/* - * linux/arch/m68k/kernel/ptrace.c - * - * Copyright (C) 1994 by Hamish Macdonald - * Taken from linux/kernel/ptrace.c and modified for M680x0. - * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds - * - * This file is subject to the terms and conditions of the GNU General - * Public License. See the file COPYING in the main directory of - * this archive for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * does not yet catch signals sent when the child dies. - * in exit.c or in signal.c. - */ - -/* determines which bits in the SR the user has access to. */ -/* 1 = access 0 = no access */ -#define SR_MASK 0x001f - -/* sets the trace bits. */ -#define TRACE_BITS 0xC000 -#define T1_BIT 0x8000 -#define T0_BIT 0x4000 - -/* Find the stack offset for a register, relative to thread.esp0. */ -#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) -#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ - - sizeof(struct switch_stack)) -/* Mapping from PT_xxx to the stack offset at which the register is - saved. Notice that usp has no stack-slot and needs to be treated - specially (see get_reg/put_reg below). */ -static const int regoff[] = { - [0] = PT_REG(d1), - [1] = PT_REG(d2), - [2] = PT_REG(d3), - [3] = PT_REG(d4), - [4] = PT_REG(d5), - [5] = SW_REG(d6), - [6] = SW_REG(d7), - [7] = PT_REG(a0), - [8] = PT_REG(a1), - [9] = PT_REG(a2), - [10] = SW_REG(a3), - [11] = SW_REG(a4), - [12] = SW_REG(a5), - [13] = SW_REG(a6), - [14] = PT_REG(d0), - [15] = -1, - [16] = PT_REG(orig_d0), - [17] = PT_REG(sr), - [18] = PT_REG(pc), -}; - -/* - * Get contents of register REGNO in task TASK. - */ -static inline long get_reg(struct task_struct *task, int regno) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); - else - return 0; - /* Need to take stkadj into account. */ - if (regno == PT_SR || regno == PT_PC) { - long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); - addr = (unsigned long *) ((unsigned long)addr + stkadj); - /* The sr is actually a 16 bit register. */ - if (regno == PT_SR) - return *(unsigned short *)addr; - } - return *addr; -} - -/* - * Write contents of register REGNO in task TASK. - */ -static inline int put_reg(struct task_struct *task, int regno, - unsigned long data) -{ - unsigned long *addr; - - if (regno == PT_USP) - addr = &task->thread.usp; - else if (regno < ARRAY_SIZE(regoff)) - addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); - else - return -1; - /* Need to take stkadj into account. */ - if (regno == PT_SR || regno == PT_PC) { - long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); - addr = (unsigned long *) ((unsigned long)addr + stkadj); - /* The sr is actually a 16 bit register. */ - if (regno == PT_SR) { - *(unsigned short *)addr = data; - return 0; - } - } - *addr = data; - return 0; -} - -/* - * Make sure the single step bit is not set. - */ -static inline void singlestep_disable(struct task_struct *child) -{ - unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; - put_reg(child, PT_SR, tmp); - clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); -} - -/* - * Called by kernel/ptrace.c when detaching.. - */ -void ptrace_disable(struct task_struct *child) -{ - singlestep_disable(child); -} - -void user_enable_single_step(struct task_struct *child) -{ - unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; - put_reg(child, PT_SR, tmp | T1_BIT); - set_tsk_thread_flag(child, TIF_DELAYED_TRACE); -} - #ifdef CONFIG_MMU -void user_enable_block_step(struct task_struct *child) -{ - unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; - put_reg(child, PT_SR, tmp | T0_BIT); -} +#include "ptrace_mm.c" +#else +#include "ptrace_no.c" #endif - -void user_disable_single_step(struct task_struct *child) -{ - singlestep_disable(child); -} - -long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data) -{ - unsigned long tmp; - int i, ret = 0; - int regno = addr >> 2; /* temporary hack. */ - unsigned long __user *datap = (unsigned long __user *) data; - - switch (request) { - /* read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: - if (addr & 3) - goto out_eio; - - if (regno >= 0 && regno < 19) { - tmp = get_reg(child, regno); - } else if (regno >= 21 && regno < 49) { - tmp = child->thread.fp[regno - 21]; - /* Convert internal fpu reg representation - * into long double format - */ - if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) - tmp = ((tmp & 0xffff0000) << 15) | - ((tmp & 0x0000ffff) << 16); -#ifndef CONFIG_MMU - } else if (regno == 49) { - tmp = child->mm->start_code; - } else if (regno == 50) { - tmp = child->mm->start_data; - } else if (regno == 51) { - tmp = child->mm->end_code; -#endif - } else - goto out_eio; - ret = put_user(tmp, datap); - break; - - case PTRACE_POKEUSR: - /* write the word at location addr in the USER area */ - if (addr & 3) - goto out_eio; - - if (regno == PT_SR) { - data &= SR_MASK; - data |= get_reg(child, PT_SR) & ~SR_MASK; - } - if (regno >= 0 && regno < 19) { - if (put_reg(child, regno, data)) - goto out_eio; - } else if (regno >= 21 && regno < 48) { - /* Convert long double format - * into internal fpu reg representation - */ - if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) { - data <<= 15; - data = (data & 0xffff0000) | - ((data & 0x0000ffff) >> 1); - } - child->thread.fp[regno - 21] = data; - } else - goto out_eio; - break; - - case PTRACE_GETREGS: /* Get all gp regs from the child. */ - for (i = 0; i < 19; i++) { - tmp = get_reg(child, i); - ret = put_user(tmp, datap); - if (ret) - break; - datap++; - } - break; - - case PTRACE_SETREGS: /* Set all gp regs in the child. */ - for (i = 0; i < 19; i++) { - ret = get_user(tmp, datap); - if (ret) - break; - if (i == PT_SR) { - tmp &= SR_MASK; - tmp |= get_reg(child, PT_SR) & ~SR_MASK; - } - put_reg(child, i, tmp); - datap++; - } - break; - - case PTRACE_GETFPREGS: /* Get the child FPU state. */ - if (copy_to_user(datap, &child->thread.fp, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - - case PTRACE_SETFPREGS: /* Set the child FPU state. */ - if (copy_from_user(&child->thread.fp, datap, - sizeof(struct user_m68kfp_struct))) - ret = -EFAULT; - break; - - case PTRACE_GET_THREAD_AREA: - ret = put_user(task_thread_info(child)->tp_value, datap); - break; - - default: - ret = ptrace_request(child, request, addr, data); - break; - } - - return ret; -out_eio: - return -EIO; -} - -asmlinkage void syscall_trace(void) -{ - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } -} - -#ifdef CONFIG_COLDFIRE -asmlinkage int syscall_trace_enter(void) -{ - int ret = 0; - - if (test_thread_flag(TIF_SYSCALL_TRACE)) - ret = tracehook_report_syscall_entry(task_pt_regs(current)); - return ret; -} - -asmlinkage void syscall_trace_leave(void) -{ - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(task_pt_regs(current), 0); -} -#endif /* CONFIG_COLDFIRE */ diff --git a/trunk/arch/m68k/kernel/ptrace_mm.c b/trunk/arch/m68k/kernel/ptrace_mm.c new file mode 100644 index 000000000000..7bc999b73529 --- /dev/null +++ b/trunk/arch/m68k/kernel/ptrace_mm.c @@ -0,0 +1,295 @@ +/* + * linux/arch/m68k/kernel/ptrace.c + * + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of + * this archive for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which bits in the SR the user has access to. */ +/* 1 = access 0 = no access */ +#define SR_MASK 0x001f + +/* sets the trace bits. */ +#define TRACE_BITS 0xC000 +#define T1_BIT 0x8000 +#define T0_BIT 0x4000 + +/* Find the stack offset for a register, relative to thread.esp0. */ +#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) +#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ + - sizeof(struct switch_stack)) +/* Mapping from PT_xxx to the stack offset at which the register is + saved. Notice that usp has no stack-slot and needs to be treated + specially (see get_reg/put_reg below). */ +static const int regoff[] = { + [0] = PT_REG(d1), + [1] = PT_REG(d2), + [2] = PT_REG(d3), + [3] = PT_REG(d4), + [4] = PT_REG(d5), + [5] = SW_REG(d6), + [6] = SW_REG(d7), + [7] = PT_REG(a0), + [8] = PT_REG(a1), + [9] = PT_REG(a2), + [10] = SW_REG(a3), + [11] = SW_REG(a4), + [12] = SW_REG(a5), + [13] = SW_REG(a6), + [14] = PT_REG(d0), + [15] = -1, + [16] = PT_REG(orig_d0), + [17] = PT_REG(sr), + [18] = PT_REG(pc), +}; + +/* + * Get contents of register REGNO in task TASK. + */ +static inline long get_reg(struct task_struct *task, int regno) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < ARRAY_SIZE(regoff)) + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); + else + return 0; + /* Need to take stkadj into account. */ + if (regno == PT_SR || regno == PT_PC) { + long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); + addr = (unsigned long *) ((unsigned long)addr + stkadj); + /* The sr is actually a 16 bit register. */ + if (regno == PT_SR) + return *(unsigned short *)addr; + } + return *addr; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < ARRAY_SIZE(regoff)) + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); + else + return -1; + /* Need to take stkadj into account. */ + if (regno == PT_SR || regno == PT_PC) { + long stkadj = *(long *)(task->thread.esp0 + PT_REG(stkadj)); + addr = (unsigned long *) ((unsigned long)addr + stkadj); + /* The sr is actually a 16 bit register. */ + if (regno == PT_SR) { + *(unsigned short *)addr = data; + return 0; + } + } + *addr = data; + return 0; +} + +/* + * Make sure the single step bit is not set. + */ +static inline void singlestep_disable(struct task_struct *child) +{ + unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; + put_reg(child, PT_SR, tmp); + clear_tsk_thread_flag(child, TIF_DELAYED_TRACE); +} + +/* + * Called by kernel/ptrace.c when detaching.. + */ +void ptrace_disable(struct task_struct *child) +{ + singlestep_disable(child); +} + +void user_enable_single_step(struct task_struct *child) +{ + unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; + put_reg(child, PT_SR, tmp | T1_BIT); + set_tsk_thread_flag(child, TIF_DELAYED_TRACE); +} + +void user_enable_block_step(struct task_struct *child) +{ + unsigned long tmp = get_reg(child, PT_SR) & ~TRACE_BITS; + put_reg(child, PT_SR, tmp | T0_BIT); +} + +void user_disable_single_step(struct task_struct *child) +{ + singlestep_disable(child); +} + +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) +{ + unsigned long tmp; + int i, ret = 0; + int regno = addr >> 2; /* temporary hack. */ + unsigned long __user *datap = (unsigned long __user *) data; + + switch (request) { + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: + if (addr & 3) + goto out_eio; + + if (regno >= 0 && regno < 19) { + tmp = get_reg(child, regno); + } else if (regno >= 21 && regno < 49) { + tmp = child->thread.fp[regno - 21]; + /* Convert internal fpu reg representation + * into long double format + */ + if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) + tmp = ((tmp & 0xffff0000) << 15) | + ((tmp & 0x0000ffff) << 16); + } else + goto out_eio; + ret = put_user(tmp, datap); + break; + + case PTRACE_POKEUSR: + /* write the word at location addr in the USER area */ + if (addr & 3) + goto out_eio; + + if (regno == PT_SR) { + data &= SR_MASK; + data |= get_reg(child, PT_SR) & ~SR_MASK; + } + if (regno >= 0 && regno < 19) { + if (put_reg(child, regno, data)) + goto out_eio; + } else if (regno >= 21 && regno < 48) { + /* Convert long double format + * into internal fpu reg representation + */ + if (FPU_IS_EMU && (regno < 45) && !(regno % 3)) { + data <<= 15; + data = (data & 0xffff0000) | + ((data & 0x0000ffff) >> 1); + } + child->thread.fp[regno - 21] = data; + } else + goto out_eio; + break; + + case PTRACE_GETREGS: /* Get all gp regs from the child. */ + for (i = 0; i < 19; i++) { + tmp = get_reg(child, i); + ret = put_user(tmp, datap); + if (ret) + break; + datap++; + } + break; + + case PTRACE_SETREGS: /* Set all gp regs in the child. */ + for (i = 0; i < 19; i++) { + ret = get_user(tmp, datap); + if (ret) + break; + if (i == PT_SR) { + tmp &= SR_MASK; + tmp |= get_reg(child, PT_SR) & ~SR_MASK; + } + put_reg(child, i, tmp); + datap++; + } + break; + + case PTRACE_GETFPREGS: /* Get the child FPU state. */ + if (copy_to_user(datap, &child->thread.fp, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + + case PTRACE_SETFPREGS: /* Set the child FPU state. */ + if (copy_from_user(&child->thread.fp, datap, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + + case PTRACE_GET_THREAD_AREA: + ret = put_user(task_thread_info(child)->tp_value, datap); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +out_eio: + return -EIO; +} + +asmlinkage void syscall_trace(void) +{ + ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0)); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } +} + +#ifdef CONFIG_COLDFIRE +asmlinkage int syscall_trace_enter(void) +{ + int ret = 0; + + if (test_thread_flag(TIF_SYSCALL_TRACE)) + ret = tracehook_report_syscall_entry(task_pt_regs(current)); + return ret; +} + +asmlinkage void syscall_trace_leave(void) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(task_pt_regs(current), 0); +} +#endif /* CONFIG_COLDFIRE */ diff --git a/trunk/arch/m68k/kernel/ptrace_no.c b/trunk/arch/m68k/kernel/ptrace_no.c new file mode 100644 index 000000000000..6709fb707335 --- /dev/null +++ b/trunk/arch/m68k/kernel/ptrace_no.c @@ -0,0 +1,255 @@ +/* + * linux/arch/m68knommu/kernel/ptrace.c + * + * Copyright (C) 1994 by Hamish Macdonald + * Taken from linux/kernel/ptrace.c and modified for M680x0. + * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of + * this archive for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which bits in the SR the user has access to. */ +/* 1 = access 0 = no access */ +#define SR_MASK 0x001f + +/* sets the trace bits. */ +#define TRACE_BITS 0x8000 + +/* Find the stack offset for a register, relative to thread.esp0. */ +#define PT_REG(reg) ((long)&((struct pt_regs *)0)->reg) +#define SW_REG(reg) ((long)&((struct switch_stack *)0)->reg \ + - sizeof(struct switch_stack)) +/* Mapping from PT_xxx to the stack offset at which the register is + saved. Notice that usp has no stack-slot and needs to be treated + specially (see get_reg/put_reg below). */ +static int regoff[] = { + PT_REG(d1), PT_REG(d2), PT_REG(d3), PT_REG(d4), + PT_REG(d5), SW_REG(d6), SW_REG(d7), PT_REG(a0), + PT_REG(a1), PT_REG(a2), SW_REG(a3), SW_REG(a4), + SW_REG(a5), SW_REG(a6), PT_REG(d0), -1, + PT_REG(orig_d0), PT_REG(sr), PT_REG(pc), +}; + +/* + * Get contents of register REGNO in task TASK. + */ +static inline long get_reg(struct task_struct *task, int regno) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < ARRAY_SIZE(regoff)) + addr = (unsigned long *)(task->thread.esp0 + regoff[regno]); + else + return 0; + return *addr; +} + +/* + * Write contents of register REGNO in task TASK. + */ +static inline int put_reg(struct task_struct *task, int regno, + unsigned long data) +{ + unsigned long *addr; + + if (regno == PT_USP) + addr = &task->thread.usp; + else if (regno < ARRAY_SIZE(regoff)) + addr = (unsigned long *) (task->thread.esp0 + regoff[regno]); + else + return -1; + *addr = data; + return 0; +} + +void user_enable_single_step(struct task_struct *task) +{ + unsigned long srflags; + srflags = get_reg(task, PT_SR) | (TRACE_BITS << 16); + put_reg(task, PT_SR, srflags); +} + +void user_disable_single_step(struct task_struct *task) +{ + unsigned long srflags; + srflags = get_reg(task, PT_SR) & ~(TRACE_BITS << 16); + put_reg(task, PT_SR, srflags); +} + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure the single step bit is not set. + */ +void ptrace_disable(struct task_struct *child) +{ + /* make sure the single step bit is not set. */ + user_disable_single_step(child); +} + +long arch_ptrace(struct task_struct *child, long request, + unsigned long addr, unsigned long data) +{ + int ret; + int regno = addr >> 2; + unsigned long __user *datap = (unsigned long __user *) data; + + switch (request) { + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + + ret = -EIO; + if ((addr & 3) || addr > sizeof(struct user) - 3) + break; + + tmp = 0; /* Default return condition */ + ret = -EIO; + if (regno < 19) { + tmp = get_reg(child, regno); + if (regno == PT_SR) + tmp >>= 16; + } else if (regno >= 21 && regno < 49) { + tmp = child->thread.fp[regno - 21]; + } else if (regno == 49) { + tmp = child->mm->start_code; + } else if (regno == 50) { + tmp = child->mm->start_data; + } else if (regno == 51) { + tmp = child->mm->end_code; + } else + break; + ret = put_user(tmp, datap); + break; + } + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + ret = -EIO; + if ((addr & 3) || addr > sizeof(struct user) - 3) + break; + + if (regno == PT_SR) { + data &= SR_MASK; + data <<= 16; + data |= get_reg(child, PT_SR) & ~(SR_MASK << 16); + } + if (regno < 19) { + if (put_reg(child, regno, data)) + break; + ret = 0; + break; + } + if (regno >= 21 && regno < 48) + { + child->thread.fp[regno - 21] = data; + ret = 0; + } + break; + + case PTRACE_GETREGS: { /* Get all gp regs from the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + tmp = get_reg(child, i); + if (i == PT_SR) + tmp >>= 16; + if (put_user(tmp, datap)) { + ret = -EFAULT; + break; + } + datap++; + } + ret = 0; + break; + } + + case PTRACE_SETREGS: { /* Set all gp regs in the child. */ + int i; + unsigned long tmp; + for (i = 0; i < 19; i++) { + if (get_user(tmp, datap)) { + ret = -EFAULT; + break; + } + if (i == PT_SR) { + tmp &= SR_MASK; + tmp <<= 16; + tmp |= get_reg(child, PT_SR) & ~(SR_MASK << 16); + } + put_reg(child, i, tmp); + datap++; + } + ret = 0; + break; + } + +#ifdef PTRACE_GETFPREGS + case PTRACE_GETFPREGS: { /* Get the child FPU state. */ + ret = 0; + if (copy_to_user(datap, &child->thread.fp, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + } +#endif + +#ifdef PTRACE_SETFPREGS + case PTRACE_SETFPREGS: { /* Set the child FPU state. */ + ret = 0; + if (copy_from_user(&child->thread.fp, datap, + sizeof(struct user_m68kfp_struct))) + ret = -EFAULT; + break; + } +#endif + + case PTRACE_GET_THREAD_AREA: + ret = put_user(task_thread_info(child)->tp_value, datap); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + return ret; +} + +asmlinkage int syscall_trace_enter(void) +{ + int ret = 0; + + if (test_thread_flag(TIF_SYSCALL_TRACE)) + ret = tracehook_report_syscall_entry(task_pt_regs(current)); + return ret; +} + +asmlinkage void syscall_trace_leave(void) +{ + if (test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(task_pt_regs(current), 0); +} diff --git a/trunk/arch/m68k/kernel/setup_no.c b/trunk/arch/m68k/kernel/setup_no.c index 7dc186b7a85f..ca3df0dc7e88 100644 --- a/trunk/arch/m68k/kernel/setup_no.c +++ b/trunk/arch/m68k/kernel/setup_no.c @@ -31,7 +31,6 @@ #include #include #include -#include #include #include @@ -48,9 +47,7 @@ EXPORT_SYMBOL(memory_end); char __initdata command_line[COMMAND_LINE_SIZE]; /* machine dependent timer functions */ -void (*mach_sched_init)(irq_handler_t handler) __initdata = NULL; int (*mach_set_clock_mmss)(unsigned long); -int (*mach_hwclk) (int, struct rtc_time*); /* machine dependent reboot functions */ void (*mach_reset)(void); diff --git a/trunk/arch/m68k/kernel/time.c b/trunk/arch/m68k/kernel/time.c index d7deb7fc7eb5..75ab79b3bdeb 100644 --- a/trunk/arch/m68k/kernel/time.c +++ b/trunk/arch/m68k/kernel/time.c @@ -1,111 +1,5 @@ -/* - * linux/arch/m68k/kernel/time.c - * - * Copyright (C) 1991, 1992, 1995 Linus Torvalds - * - * This file contains the m68k-specific time handling details. - * Most of the stuff is located in the machine specific files. - * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -/* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "xtime_update()" routine every clocktick - */ -static irqreturn_t timer_interrupt(int irq, void *dummy) -{ - xtime_update(1); - update_process_times(user_mode(get_irq_regs())); - profile_tick(CPU_PROFILING); - -#ifdef CONFIG_HEARTBEAT - /* use power LED as a heartbeat instead -- much more useful - for debugging -- based on the version for PReP by Cort */ - /* acts like an actual heart beat -- ie thump-thump-pause... */ - if (mach_heartbeat) { - static unsigned cnt = 0, period = 0, dist = 0; - - if (cnt == 0 || cnt == dist) - mach_heartbeat( 1 ); - else if (cnt == 7 || cnt == dist+7) - mach_heartbeat( 0 ); - - if (++cnt > period) { - cnt = 0; - /* The hyperbolic function below modifies the heartbeat period - * length in dependency of the current (5min) load. It goes - * through the points f(0)=126, f(1)=86, f(5)=51, - * f(inf)->30. */ - period = ((672<tv_sec = 0; - ts->tv_nsec = 0; - - if (mach_hwclk) { - mach_hwclk(0, &time); - - if ((time.tm_year += 1900) < 1970) - time.tm_year += 100; - ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, - time.tm_hour, time.tm_min, time.tm_sec); - } -} - -void __init time_init(void) -{ - mach_sched_init(timer_interrupt); -} - -#ifdef CONFIG_M68KCLASSIC - -u32 arch_gettimeoffset(void) -{ - return mach_gettimeoffset() * 1000; -} - -static int __init rtc_init(void) -{ - struct platform_device *pdev; - - if (!mach_hwclk) - return -ENODEV; - - pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - return 0; -} - -module_init(rtc_init); - -#endif /* CONFIG_M68KCLASSIC */ +#if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE) +#include "time_mm.c" +#else +#include "time_no.c" +#endif diff --git a/trunk/arch/m68k/kernel/time_mm.c b/trunk/arch/m68k/kernel/time_mm.c new file mode 100644 index 000000000000..18b34ee5db3b --- /dev/null +++ b/trunk/arch/m68k/kernel/time_mm.c @@ -0,0 +1,114 @@ +/* + * linux/arch/m68k/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file contains the m68k-specific time handling details. + * Most of the stuff is located in the machine specific files. + * + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +static inline int set_rtc_mmss(unsigned long nowtime) +{ + if (mach_set_clock_mmss) + return mach_set_clock_mmss (nowtime); + return -1; +} + +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "xtime_update()" routine every clocktick + */ +static irqreturn_t timer_interrupt(int irq, void *dummy) +{ + xtime_update(1); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); + +#ifdef CONFIG_HEARTBEAT + /* use power LED as a heartbeat instead -- much more useful + for debugging -- based on the version for PReP by Cort */ + /* acts like an actual heart beat -- ie thump-thump-pause... */ + if (mach_heartbeat) { + static unsigned cnt = 0, period = 0, dist = 0; + + if (cnt == 0 || cnt == dist) + mach_heartbeat( 1 ); + else if (cnt == 7 || cnt == dist+7) + mach_heartbeat( 0 ); + + if (++cnt > period) { + cnt = 0; + /* The hyperbolic function below modifies the heartbeat period + * length in dependency of the current (5min) load. It goes + * through the points f(0)=126, f(1)=86, f(5)=51, + * f(inf)->30. */ + period = ((672<tv_sec = 0; + ts->tv_nsec = 0; + + if (mach_hwclk) { + mach_hwclk(0, &time); + + if ((time.tm_year += 1900) < 1970) + time.tm_year += 100; + ts->tv_sec = mktime(time.tm_year, time.tm_mon, time.tm_mday, + time.tm_hour, time.tm_min, time.tm_sec); + } +} + +void __init time_init(void) +{ + mach_sched_init(timer_interrupt); +} + +u32 arch_gettimeoffset(void) +{ + return mach_gettimeoffset() * 1000; +} + +static int __init rtc_init(void) +{ + struct platform_device *pdev; + + if (!mach_hwclk) + return -ENODEV; + + pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); + if (IS_ERR(pdev)) + return PTR_ERR(pdev); + + return 0; +} + +module_init(rtc_init); diff --git a/trunk/arch/m68k/kernel/time_no.c b/trunk/arch/m68k/kernel/time_no.c new file mode 100644 index 000000000000..3ef0f7768dcd --- /dev/null +++ b/trunk/arch/m68k/kernel/time_no.c @@ -0,0 +1,90 @@ +/* + * linux/arch/m68knommu/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * + * This file contains the m68k-specific time handling details. + * Most of the stuff is located in the machine specific files. + * + * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define TICK_SIZE (tick_nsec / 1000) + +/* machine dependent timer functions */ +void (*mach_gettod)(int*, int*, int*, int*, int*, int*); + +static inline int set_rtc_mmss(unsigned long nowtime) +{ + if (mach_set_clock_mmss) + return mach_set_clock_mmss (nowtime); + return -1; +} + +#ifndef CONFIG_GENERIC_CLOCKEVENTS +/* + * timer_interrupt() needs to keep up the real-time clock, + * as well as call the "xtime_update()" routine every clocktick + */ +irqreturn_t arch_timer_interrupt(int irq, void *dummy) +{ + + if (current->pid) + profile_tick(CPU_PROFILING); + + xtime_update(1); + + update_process_times(user_mode(get_irq_regs())); + + return(IRQ_HANDLED); +} +#endif + +static unsigned long read_rtc_mmss(void) +{ + unsigned int year, mon, day, hour, min, sec; + + if (mach_gettod) { + mach_gettod(&year, &mon, &day, &hour, &min, &sec); + if ((year += 1900) < 1970) + year += 100; + } else { + year = 1970; + mon = day = 1; + hour = min = sec = 0; + } + + + return mktime(year, mon, day, hour, min, sec); +} + +void read_persistent_clock(struct timespec *ts) +{ + ts->tv_sec = read_rtc_mmss(); + ts->tv_nsec = 0; +} + +int update_persistent_clock(struct timespec now) +{ + return set_rtc_mmss(now.tv_sec); +} + +void time_init(void) +{ + hw_timer_init(); +} diff --git a/trunk/arch/m68k/kernel/vmlinux-nommu.lds b/trunk/arch/m68k/kernel/vmlinux-nommu.lds index 40e02d9c38b4..8e66ccb0935e 100644 --- a/trunk/arch/m68k/kernel/vmlinux-nommu.lds +++ b/trunk/arch/m68k/kernel/vmlinux-nommu.lds @@ -1,93 +1,195 @@ /* * vmlinux.lds.S -- master linker script for m68knommu arch * - * (C) Copyright 2002-2012, Greg Ungerer + * (C) Copyright 2002-2006, Greg Ungerer * * This linker script is equipped to build either ROM loaded or RAM * run kernels. */ +#include +#include +#include + #if defined(CONFIG_RAMKERNEL) -#define KTEXT_ADDR CONFIG_KERNELBASE +#define RAM_START CONFIG_KERNELBASE +#define RAM_LENGTH (CONFIG_RAMBASE + CONFIG_RAMSIZE - CONFIG_KERNELBASE) +#define TEXT ram +#define DATA ram +#define INIT ram +#define BSSS ram #endif -#if defined(CONFIG_ROMKERNEL) -#define KTEXT_ADDR CONFIG_ROMSTART -#define KDATA_ADDR CONFIG_KERNELBASE -#define LOAD_OFFSET KDATA_ADDR + (ADDR(.text) + SIZEOF(.text)) +#if defined(CONFIG_ROMKERNEL) || defined(CONFIG_HIMEMKERNEL) +#define RAM_START CONFIG_RAMBASE +#define RAM_LENGTH CONFIG_RAMSIZE +#define ROMVEC_START CONFIG_ROMVEC +#define ROMVEC_LENGTH CONFIG_ROMVECSIZE +#define ROM_START CONFIG_ROMSTART +#define ROM_LENGTH CONFIG_ROMSIZE +#define TEXT rom +#define DATA ram +#define INIT ram +#define BSSS ram +#endif + +#ifndef DATA_ADDR +#define DATA_ADDR #endif -#include -#include -#include OUTPUT_ARCH(m68k) ENTRY(_start) +MEMORY { + ram : ORIGIN = RAM_START, LENGTH = RAM_LENGTH +#ifdef ROM_START + romvec : ORIGIN = ROMVEC_START, LENGTH = ROMVEC_LENGTH + rom : ORIGIN = ROM_START, LENGTH = ROM_LENGTH +#endif +} + jiffies = jiffies_64 + 4; SECTIONS { -#ifdef CONFIG_ROMVEC - . = CONFIG_ROMVEC; +#ifdef ROMVEC_START + . = ROMVEC_START ; .romvec : { - __rom_start = .; + __rom_start = . ; _romvec = .; - *(.romvec) *(.data..initvect) - } + } > romvec #endif - . = KTEXT_ADDR; - - _text = .; - _stext = .; .text : { + _text = .; + _stext = . ; HEAD_TEXT TEXT_TEXT SCHED_TEXT LOCK_TEXT + *(.text..lock) *(.fixup) - . = ALIGN(16); - } - _etext = .; - -#ifdef KDATA_ADDR - . = KDATA_ADDR; -#endif - - _sdata = .; - RO_DATA_SECTION(PAGE_SIZE) - RW_DATA_SECTION(16, PAGE_SIZE, THREAD_SIZE) - _edata = .; - EXCEPTION_TABLE(16) - NOTES + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + + *(.rodata) *(.rodata.*) + *(__vermagic) /* Kernel version magic */ + *(.rodata1) + *(.rodata.str1.1) + + /* Kernel symbol table: Normal symbols */ + . = ALIGN(4); + __start___ksymtab = .; + *(SORT(___ksymtab+*)) + __stop___ksymtab = .; + + /* Kernel symbol table: GPL-only symbols */ + __start___ksymtab_gpl = .; + *(SORT(___ksymtab_gpl+*)) + __stop___ksymtab_gpl = .; + + /* Kernel symbol table: Normal unused symbols */ + __start___ksymtab_unused = .; + *(SORT(___ksymtab_unused+*)) + __stop___ksymtab_unused = .; + + /* Kernel symbol table: GPL-only unused symbols */ + __start___ksymtab_unused_gpl = .; + *(SORT(___ksymtab_unused_gpl+*)) + __stop___ksymtab_unused_gpl = .; + + /* Kernel symbol table: GPL-future symbols */ + __start___ksymtab_gpl_future = .; + *(SORT(___ksymtab_gpl_future+*)) + __stop___ksymtab_gpl_future = .; + + /* Kernel symbol table: Normal symbols */ + __start___kcrctab = .; + *(SORT(___kcrctab+*)) + __stop___kcrctab = .; + + /* Kernel symbol table: GPL-only symbols */ + __start___kcrctab_gpl = .; + *(SORT(___kcrctab_gpl+*)) + __stop___kcrctab_gpl = .; + + /* Kernel symbol table: Normal unused symbols */ + __start___kcrctab_unused = .; + *(SORT(___kcrctab_unused+*)) + __stop___kcrctab_unused = .; + + /* Kernel symbol table: GPL-only unused symbols */ + __start___kcrctab_unused_gpl = .; + *(SORT(___kcrctab_unused_gpl+*)) + __stop___kcrctab_unused_gpl = .; + + /* Kernel symbol table: GPL-future symbols */ + __start___kcrctab_gpl_future = .; + *(SORT(___kcrctab_gpl_future+*)) + __stop___kcrctab_gpl_future = .; + + /* Kernel symbol table: strings */ + *(__ksymtab_strings) + + /* Built-in module parameters */ + . = ALIGN(4) ; + __start___param = .; + *(__param) + __stop___param = .; + + /* Built-in module versions */ + . = ALIGN(4) ; + __start___modver = .; + *(__modver) + __stop___modver = .; + + . = ALIGN(4) ; + _etext = . ; + } > TEXT + + .data DATA_ADDR : { + . = ALIGN(4); + _sdata = . ; + DATA_DATA + CACHELINE_ALIGNED_DATA(32) + PAGE_ALIGNED_DATA(PAGE_SIZE) + *(.data..shared_aligned) + INIT_TASK_DATA(THREAD_SIZE) + _edata = . ; + } > DATA - . = ALIGN(PAGE_SIZE); - __init_begin = .; - INIT_TEXT_SECTION(PAGE_SIZE) - INIT_DATA_SECTION(16) - PERCPU_SECTION(16) .m68k_fixup : { __start_fixup = .; *(.m68k_fixup) __stop_fixup = .; - } + } > DATA + NOTES > DATA + + .init.text : { + . = ALIGN(PAGE_SIZE); + __init_begin = .; + } > INIT + INIT_TEXT_SECTION(PAGE_SIZE) > INIT + INIT_DATA_SECTION(16) > INIT .init.data : { . = ALIGN(PAGE_SIZE); __init_end = .; - } - - _sbss = .; - BSS_SECTION(0, 0, 0) - _ebss = .; - - _end = .; - - STABS_DEBUG - .comment 0 : { *(.comment) } + } > INIT + + .bss : { + . = ALIGN(4); + _sbss = . ; + *(.bss) + *(COMMON) + . = ALIGN(4) ; + _ebss = . ; + _end = . ; + } > BSSS - /* Sections to be discarded */ DISCARDS } diff --git a/trunk/arch/m68k/platform/5206/config.c b/trunk/arch/m68k/platform/5206/config.c index 6bfbeebd231b..6fa3f800277a 100644 --- a/trunk/arch/m68k/platform/5206/config.c +++ b/trunk/arch/m68k/platform/5206/config.c @@ -16,6 +16,83 @@ #include #include #include +#include + +/***************************************************************************/ + +static struct mcf_platform_uart m5206_uart_platform[] = { + { + .mapbase = MCF_MBAR + MCFUART_BASE1, + .irq = 73, + }, + { + .mapbase = MCF_MBAR + MCFUART_BASE2, + .irq = 74, + }, + { }, +}; + +static struct platform_device m5206_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m5206_uart_platform, +}; + +static struct platform_device *m5206_devices[] __initdata = { + &m5206_uart, +}; + +/***************************************************************************/ + +static void __init m5206_uart_init_line(int line, int irq) +{ + if (line == 0) { + writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); + writeb(irq, MCFUART_BASE1 + MCFUART_UIVR); + mcf_mapirq2imr(irq, MCFINTC_UART0); + } else if (line == 1) { + writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); + writeb(irq, MCFUART_BASE2 + MCFUART_UIVR); + mcf_mapirq2imr(irq, MCFINTC_UART1); + } +} + +static void __init m5206_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m5206_uart_platform); + int line; + + for (line = 0; (line < nrlines); line++) + m5206_uart_init_line(line, m5206_uart_platform[line].irq); +} + +/***************************************************************************/ + +static void __init m5206_timers_init(void) +{ + /* Timer1 is always used as system timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER1ICR); + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); + +#ifdef CONFIG_HIGHPROFILE + /* Timer2 is to be used as a high speed profile timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER2ICR); + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); +#endif +} + +/***************************************************************************/ + +void m5206_cpu_reset(void) +{ + local_irq_disable(); + /* Set watchdog to soft reset, and enabled */ + __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); + for (;;) + /* wait for watchdog to timeout */; +} /***************************************************************************/ @@ -27,7 +104,9 @@ void __init config_BSP(char *commandp, int size) commandp[size-1] = 0; #endif /* CONFIG_NETtel */ - mach_sched_init = hw_timer_init; + mach_reset = m5206_cpu_reset; + m5206_timers_init(); + m5206_uarts_init(); /* Only support the external interrupts on their primary level */ mcf_mapirq2imr(25, MCFINTC_EINT1); @@ -36,3 +115,13 @@ void __init config_BSP(char *commandp, int size) } /***************************************************************************/ + +static int __init init_BSP(void) +{ + platform_add_devices(m5206_devices, ARRAY_SIZE(m5206_devices)); + return 0; +} + +arch_initcall(init_BSP); + +/***************************************************************************/ diff --git a/trunk/arch/m68k/platform/520x/config.c b/trunk/arch/m68k/platform/520x/config.c index 235947844f27..8a98683f1b15 100644 --- a/trunk/arch/m68k/platform/520x/config.c +++ b/trunk/arch/m68k/platform/520x/config.c @@ -15,14 +15,194 @@ #include #include #include +#include +#include #include #include #include #include +#include /***************************************************************************/ -#ifdef CONFIG_SPI_COLDFIRE_QSPI +static struct mcf_platform_uart m520x_uart_platform[] = { + { + .mapbase = MCFUART_BASE1, + .irq = MCFINT_VECBASE + MCFINT_UART0, + }, + { + .mapbase = MCFUART_BASE2, + .irq = MCFINT_VECBASE + MCFINT_UART1, + }, + { + .mapbase = MCFUART_BASE3, + .irq = MCFINT_VECBASE + MCFINT_UART2, + }, + { }, +}; + +static struct platform_device m520x_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m520x_uart_platform, +}; + +static struct resource m520x_fec_resources[] = { + { + .start = MCFFEC_BASE, + .end = MCFFEC_BASE + MCFFEC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = 64 + 36, + .end = 64 + 36, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 40, + .end = 64 + 40, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 42, + .end = 64 + 42, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device m520x_fec = { + .name = "fec", + .id = 0, + .num_resources = ARRAY_SIZE(m520x_fec_resources), + .resource = m520x_fec_resources, +}; + +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m520x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#define MCFQSPI_CS0 46 +#define MCFQSPI_CS1 47 +#define MCFQSPI_CS2 27 + +static int m520x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + return 0; + +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m520x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m520x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, cs_high); + break; + } +} + +static void m520x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, !cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, !cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, !cs_high); + break; + } +} + +static struct mcfqspi_cs_control m520x_cs_control = { + .setup = m520x_cs_setup, + .teardown = m520x_cs_teardown, + .select = m520x_cs_select, + .deselect = m520x_cs_deselect, +}; + +static struct mcfqspi_platform_data m520x_qspi_data = { + .bus_num = 0, + .num_chipselect = 3, + .cs_control = &m520x_cs_control, +}; + +static struct platform_device m520x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m520x_qspi_resources), + .resource = m520x_qspi_resources, + .dev.platform_data = &m520x_qspi_data, +}; static void __init m520x_qspi_init(void) { @@ -34,28 +214,54 @@ static void __init m520x_qspi_init(void) par &= 0x00ff; writew(par, MCF_GPIO_PAR_UART); } +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ + -#endif /* CONFIG_SPI_COLDFIRE_QSPI */ +static struct platform_device *m520x_devices[] __initdata = { + &m520x_uart, + &m520x_fec, +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m520x_qspi, +#endif +}; /***************************************************************************/ -static void __init m520x_uarts_init(void) +static void __init m520x_uart_init_line(int line, int irq) { u16 par; u8 par2; - /* UART0 and UART1 GPIO pin setup */ - par = readw(MCF_GPIO_PAR_UART); - par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | MCF_GPIO_PAR_UART_PAR_URXD0; - par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | MCF_GPIO_PAR_UART_PAR_URXD1; - writew(par, MCF_GPIO_PAR_UART); + switch (line) { + case 0: + par = readw(MCF_GPIO_PAR_UART); + par |= MCF_GPIO_PAR_UART_PAR_UTXD0 | + MCF_GPIO_PAR_UART_PAR_URXD0; + writew(par, MCF_GPIO_PAR_UART); + break; + case 1: + par = readw(MCF_GPIO_PAR_UART); + par |= MCF_GPIO_PAR_UART_PAR_UTXD1 | + MCF_GPIO_PAR_UART_PAR_URXD1; + writew(par, MCF_GPIO_PAR_UART); + break; + case 2: + par2 = readb(MCF_GPIO_PAR_FECI2C); + par2 &= ~0x0F; + par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 | + MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; + writeb(par2, MCF_GPIO_PAR_FECI2C); + break; + } +} + +static void __init m520x_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m520x_uart_platform); + int line; - /* UART1 GPIO pin setup */ - par2 = readb(MCF_GPIO_PAR_FECI2C); - par2 &= ~0x0F; - par2 |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2 | - MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2; - writeb(par2, MCF_GPIO_PAR_FECI2C); + for (line = 0; (line < nrlines); line++) + m520x_uart_init_line(line, m520x_uart_platform[line].irq); } /***************************************************************************/ @@ -74,14 +280,32 @@ static void __init m520x_fec_init(void) /***************************************************************************/ +static void m520x_cpu_reset(void) +{ + local_irq_disable(); + __raw_writeb(MCF_RCR_SWRESET, MCF_RCR); +} + +/***************************************************************************/ + void __init config_BSP(char *commandp, int size) { - mach_sched_init = hw_timer_init; + mach_reset = m520x_cpu_reset; m520x_uarts_init(); m520x_fec_init(); -#ifdef CONFIG_SPI_COLDFIRE_QSPI +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) m520x_qspi_init(); #endif } /***************************************************************************/ + +static int __init init_BSP(void) +{ + platform_add_devices(m520x_devices, ARRAY_SIZE(m520x_devices)); + return 0; +} + +arch_initcall(init_BSP); + +/***************************************************************************/ diff --git a/trunk/arch/m68k/platform/523x/config.c b/trunk/arch/m68k/platform/523x/config.c index c8b405d5a961..71f4436ec809 100644 --- a/trunk/arch/m68k/platform/523x/config.c +++ b/trunk/arch/m68k/platform/523x/config.c @@ -16,13 +16,215 @@ #include #include #include +#include +#include #include #include #include +#include +#include /***************************************************************************/ -#ifdef CONFIG_SPI_COLDFIRE_QSPI +static struct mcf_platform_uart m523x_uart_platform[] = { + { + .mapbase = MCFUART_BASE1, + .irq = MCFINT_VECBASE + MCFINT_UART0, + }, + { + .mapbase = MCFUART_BASE2, + .irq = MCFINT_VECBASE + MCFINT_UART0 + 1, + }, + { + .mapbase = MCFUART_BASE3, + .irq = MCFINT_VECBASE + MCFINT_UART0 + 2, + }, + { }, +}; + +static struct platform_device m523x_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m523x_uart_platform, +}; + +static struct resource m523x_fec_resources[] = { + { + .start = MCFFEC_BASE, + .end = MCFFEC_BASE + MCFFEC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = 64 + 23, + .end = 64 + 23, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 27, + .end = 64 + 27, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 29, + .end = 64 + 29, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device m523x_fec = { + .name = "fec", + .id = 0, + .num_resources = ARRAY_SIZE(m523x_fec_resources), + .resource = m523x_fec_resources, +}; + +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m523x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#define MCFQSPI_CS0 91 +#define MCFQSPI_CS1 92 +#define MCFQSPI_CS2 103 +#define MCFQSPI_CS3 99 + +static int m523x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); + goto fail3; + } + status = gpio_direction_output(MCFQSPI_CS3, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); + goto fail4; + } + + return 0; + +fail4: + gpio_free(MCFQSPI_CS3); +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m523x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS3); + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m523x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, cs_high); + break; + } +} + +static void m523x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, !cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, !cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, !cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, !cs_high); + break; + } +} + +static struct mcfqspi_cs_control m523x_cs_control = { + .setup = m523x_cs_setup, + .teardown = m523x_cs_teardown, + .select = m523x_cs_select, + .deselect = m523x_cs_deselect, +}; + +static struct mcfqspi_platform_data m523x_qspi_data = { + .bus_num = 0, + .num_chipselect = 4, + .cs_control = &m523x_cs_control, +}; + +static struct platform_device m523x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m523x_qspi_resources), + .resource = m523x_qspi_resources, + .dev.platform_data = &m523x_qspi_data, +}; static void __init m523x_qspi_init(void) { @@ -35,8 +237,15 @@ static void __init m523x_qspi_init(void) par &= 0x3f3f; writew(par, MCFGPIO_PAR_TIMER); } +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ -#endif /* CONFIG_SPI_COLDFIRE_QSPI */ +static struct platform_device *m523x_devices[] __initdata = { + &m523x_uart, + &m523x_fec, +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m523x_qspi, +#endif +}; /***************************************************************************/ @@ -54,13 +263,31 @@ static void __init m523x_fec_init(void) /***************************************************************************/ +static void m523x_cpu_reset(void) +{ + local_irq_disable(); + __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR); +} + +/***************************************************************************/ + void __init config_BSP(char *commandp, int size) { - mach_sched_init = hw_timer_init; + mach_reset = m523x_cpu_reset; +} + +/***************************************************************************/ + +static int __init init_BSP(void) +{ m523x_fec_init(); -#ifdef CONFIG_SPI_COLDFIRE_QSPI +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) m523x_qspi_init(); #endif + platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices)); + return 0; } +arch_initcall(init_BSP); + /***************************************************************************/ diff --git a/trunk/arch/m68k/platform/5249/config.c b/trunk/arch/m68k/platform/5249/config.c index bbf05135bb98..ceb31e5744a6 100644 --- a/trunk/arch/m68k/platform/5249/config.c +++ b/trunk/arch/m68k/platform/5249/config.c @@ -12,13 +12,34 @@ #include #include #include -#include +#include +#include #include #include #include +#include +#include /***************************************************************************/ +static struct mcf_platform_uart m5249_uart_platform[] = { + { + .mapbase = MCF_MBAR + MCFUART_BASE1, + .irq = 73, + }, + { + .mapbase = MCF_MBAR + MCFUART_BASE2, + .irq = 74, + }, + { }, +}; + +static struct platform_device m5249_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m5249_uart_platform, +}; + #ifdef CONFIG_M5249C3 static struct resource m5249_smc91x_resources[] = { @@ -43,15 +64,153 @@ static struct platform_device m5249_smc91x = { #endif /* CONFIG_M5249C3 */ -static struct platform_device *m5249_devices[] __initdata = { -#ifdef CONFIG_M5249C3 - &m5249_smc91x, -#endif +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m5249_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCF_IRQ_QSPI, + .end = MCF_IRQ_QSPI, + .flags = IORESOURCE_IRQ, + }, }; -/***************************************************************************/ +#define MCFQSPI_CS0 29 +#define MCFQSPI_CS1 24 +#define MCFQSPI_CS2 21 +#define MCFQSPI_CS3 22 + +static int m5249_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); + goto fail3; + } + status = gpio_direction_output(MCFQSPI_CS3, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); + goto fail4; + } + + return 0; + +fail4: + gpio_free(MCFQSPI_CS3); +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m5249_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS3); + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m5249_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, cs_high); + break; + } +} + +static void m5249_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, !cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, !cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, !cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, !cs_high); + break; + } +} + +static struct mcfqspi_cs_control m5249_cs_control = { + .setup = m5249_cs_setup, + .teardown = m5249_cs_teardown, + .select = m5249_cs_select, + .deselect = m5249_cs_deselect, +}; + +static struct mcfqspi_platform_data m5249_qspi_data = { + .bus_num = 0, + .num_chipselect = 4, + .cs_control = &m5249_cs_control, +}; -#ifdef CONFIG_SPI_COLDFIRE_QSPI +static struct platform_device m5249_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m5249_qspi_resources), + .resource = m5249_qspi_resources, + .dev.platform_data = &m5249_qspi_data, +}; static void __init m5249_qspi_init(void) { @@ -60,8 +219,42 @@ static void __init m5249_qspi_init(void) MCF_MBAR + MCFSIM_QSPIICR); mcf_mapirq2imr(MCF_IRQ_QSPI, MCFINTC_QSPI); } +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ -#endif /* CONFIG_SPI_COLDFIRE_QSPI */ + +static struct platform_device *m5249_devices[] __initdata = { + &m5249_uart, +#ifdef CONFIG_M5249C3 + &m5249_smc91x, +#endif +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m5249_qspi, +#endif +}; + +/***************************************************************************/ + +static void __init m5249_uart_init_line(int line, int irq) +{ + if (line == 0) { + writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); + writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR); + mcf_mapirq2imr(irq, MCFINTC_UART0); + } else if (line == 1) { + writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); + writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR); + mcf_mapirq2imr(irq, MCFINTC_UART1); + } +} + +static void __init m5249_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m5249_uart_platform); + int line; + + for (line = 0; (line < nrlines); line++) + m5249_uart_init_line(line, m5249_uart_platform[line].irq); +} /***************************************************************************/ @@ -83,14 +276,43 @@ static void __init m5249_smc91x_init(void) /***************************************************************************/ -void __init config_BSP(char *commandp, int size) +static void __init m5249_timers_init(void) +{ + /* Timer1 is always used as system timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER1ICR); + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); + +#ifdef CONFIG_HIGHPROFILE + /* Timer2 is to be used as a high speed profile timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER2ICR); + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); +#endif +} + +/***************************************************************************/ + +void m5249_cpu_reset(void) { - mach_sched_init = hw_timer_init; + local_irq_disable(); + /* Set watchdog to soft reset, and enabled */ + __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); + for (;;) + /* wait for watchdog to timeout */; +} +/***************************************************************************/ + +void __init config_BSP(char *commandp, int size) +{ + mach_reset = m5249_cpu_reset; + m5249_timers_init(); + m5249_uarts_init(); #ifdef CONFIG_M5249C3 m5249_smc91x_init(); #endif -#ifdef CONFIG_SPI_COLDFIRE_QSPI +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) m5249_qspi_init(); #endif } diff --git a/trunk/arch/m68k/platform/5272/config.c b/trunk/arch/m68k/platform/5272/config.c index e68bc7a148eb..65bb582734e1 100644 --- a/trunk/arch/m68k/platform/5272/config.c +++ b/trunk/arch/m68k/platform/5272/config.c @@ -30,18 +30,84 @@ unsigned char ledbank = 0xff; /***************************************************************************/ -static void __init m5272_uarts_init(void) +static struct mcf_platform_uart m5272_uart_platform[] = { + { + .mapbase = MCF_MBAR + MCFUART_BASE1, + .irq = MCF_IRQ_UART1, + }, + { + .mapbase = MCF_MBAR + MCFUART_BASE2, + .irq = MCF_IRQ_UART2, + }, + { }, +}; + +static struct platform_device m5272_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m5272_uart_platform, +}; + +static struct resource m5272_fec_resources[] = { + { + .start = MCF_MBAR + 0x840, + .end = MCF_MBAR + 0x840 + 0x1cf, + .flags = IORESOURCE_MEM, + }, + { + .start = MCF_IRQ_ERX, + .end = MCF_IRQ_ERX, + .flags = IORESOURCE_IRQ, + }, + { + .start = MCF_IRQ_ETX, + .end = MCF_IRQ_ETX, + .flags = IORESOURCE_IRQ, + }, + { + .start = MCF_IRQ_ENTC, + .end = MCF_IRQ_ENTC, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device m5272_fec = { + .name = "fec", + .id = 0, + .num_resources = ARRAY_SIZE(m5272_fec_resources), + .resource = m5272_fec_resources, +}; + +static struct platform_device *m5272_devices[] __initdata = { + &m5272_uart, + &m5272_fec, +}; + +/***************************************************************************/ + +static void __init m5272_uart_init_line(int line, int irq) { u32 v; - /* Enable the output lines for the serial ports */ - v = readl(MCF_MBAR + MCFSIM_PBCNT); - v = (v & ~0x000000ff) | 0x00000055; - writel(v, MCF_MBAR + MCFSIM_PBCNT); + if ((line >= 0) && (line < 2)) { + /* Enable the output lines for the serial ports */ + v = readl(MCF_MBAR + MCFSIM_PBCNT); + v = (v & ~0x000000ff) | 0x00000055; + writel(v, MCF_MBAR + MCFSIM_PBCNT); + + v = readl(MCF_MBAR + MCFSIM_PDCNT); + v = (v & ~0x000003fc) | 0x000002a8; + writel(v, MCF_MBAR + MCFSIM_PDCNT); + } +} + +static void __init m5272_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m5272_uart_platform); + int line; - v = readl(MCF_MBAR + MCFSIM_PDCNT); - v = (v & ~0x000003fc) | 0x000002a8; - writel(v, MCF_MBAR + MCFSIM_PDCNT); + for (line = 0; (line < nrlines); line++) + m5272_uart_init_line(line, m5272_uart_platform[line].irq); } /***************************************************************************/ @@ -80,7 +146,6 @@ void __init config_BSP(char *commandp, int size) #endif mach_reset = m5272_cpu_reset; - mach_sched_init = hw_timer_init; } /***************************************************************************/ @@ -102,6 +167,7 @@ static int __init init_BSP(void) { m5272_uarts_init(); fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status); + platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices)); return 0; } diff --git a/trunk/arch/m68k/platform/527x/config.c b/trunk/arch/m68k/platform/527x/config.c index 7ed848c3b848..3ebc769cefda 100644 --- a/trunk/arch/m68k/platform/527x/config.c +++ b/trunk/arch/m68k/platform/527x/config.c @@ -16,14 +16,253 @@ #include #include #include +#include +#include #include #include #include #include +#include /***************************************************************************/ -#ifdef CONFIG_SPI_COLDFIRE_QSPI +static struct mcf_platform_uart m527x_uart_platform[] = { + { + .mapbase = MCFUART_BASE1, + .irq = MCFINT_VECBASE + MCFINT_UART0, + }, + { + .mapbase = MCFUART_BASE2, + .irq = MCFINT_VECBASE + MCFINT_UART1, + }, + { + .mapbase = MCFUART_BASE3, + .irq = MCFINT_VECBASE + MCFINT_UART2, + }, + { }, +}; + +static struct platform_device m527x_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m527x_uart_platform, +}; + +static struct resource m527x_fec0_resources[] = { + { + .start = MCFFEC_BASE0, + .end = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = 64 + 23, + .end = 64 + 23, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 27, + .end = 64 + 27, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 29, + .end = 64 + 29, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct resource m527x_fec1_resources[] = { + { + .start = MCFFEC_BASE1, + .end = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = 128 + 23, + .end = 128 + 23, + .flags = IORESOURCE_IRQ, + }, + { + .start = 128 + 27, + .end = 128 + 27, + .flags = IORESOURCE_IRQ, + }, + { + .start = 128 + 29, + .end = 128 + 29, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device m527x_fec[] = { + { + .name = "fec", + .id = 0, + .num_resources = ARRAY_SIZE(m527x_fec0_resources), + .resource = m527x_fec0_resources, + }, + { + .name = "fec", + .id = 1, + .num_resources = ARRAY_SIZE(m527x_fec1_resources), + .resource = m527x_fec1_resources, + }, +}; + +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m527x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#if defined(CONFIG_M5271) +#define MCFQSPI_CS0 91 +#define MCFQSPI_CS1 92 +#define MCFQSPI_CS2 99 +#define MCFQSPI_CS3 103 +#elif defined(CONFIG_M5275) +#define MCFQSPI_CS0 59 +#define MCFQSPI_CS1 60 +#define MCFQSPI_CS2 61 +#define MCFQSPI_CS3 62 +#endif + +static int m527x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); + goto fail3; + } + status = gpio_direction_output(MCFQSPI_CS3, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); + goto fail4; + } + + return 0; + +fail4: + gpio_free(MCFQSPI_CS3); +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m527x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS3); + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m527x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, cs_high); + break; + } +} + +static void m527x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + switch (chip_select) { + case 0: + gpio_set_value(MCFQSPI_CS0, !cs_high); + break; + case 1: + gpio_set_value(MCFQSPI_CS1, !cs_high); + break; + case 2: + gpio_set_value(MCFQSPI_CS2, !cs_high); + break; + case 3: + gpio_set_value(MCFQSPI_CS3, !cs_high); + break; + } +} + +static struct mcfqspi_cs_control m527x_cs_control = { + .setup = m527x_cs_setup, + .teardown = m527x_cs_teardown, + .select = m527x_cs_select, + .deselect = m527x_cs_deselect, +}; + +static struct mcfqspi_platform_data m527x_qspi_data = { + .bus_num = 0, + .num_chipselect = 4, + .cs_control = &m527x_cs_control, +}; + +static struct platform_device m527x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m527x_qspi_resources), + .resource = m527x_qspi_resources, + .dev.platform_data = &m527x_qspi_data, +}; static void __init m527x_qspi_init(void) { @@ -41,23 +280,50 @@ static void __init m527x_qspi_init(void) writew(0x003e, MCFGPIO_PAR_QSPI); #endif } +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ -#endif /* CONFIG_SPI_COLDFIRE_QSPI */ +static struct platform_device *m527x_devices[] __initdata = { + &m527x_uart, + &m527x_fec[0], +#ifdef CONFIG_FEC2 + &m527x_fec[1], +#endif +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m527x_qspi, +#endif +}; /***************************************************************************/ -static void __init m527x_uarts_init(void) +static void __init m527x_uart_init_line(int line, int irq) { u16 sepmask; + if ((line < 0) || (line > 2)) + return; + /* * External Pin Mask Setting & Enable External Pin for Interface */ sepmask = readw(MCF_IPSBAR + MCF_GPIO_PAR_UART); - sepmask |= UART0_ENABLE_MASK | UART1_ENABLE_MASK | UART2_ENABLE_MASK; + if (line == 0) + sepmask |= UART0_ENABLE_MASK; + else if (line == 1) + sepmask |= UART1_ENABLE_MASK; + else if (line == 2) + sepmask |= UART2_ENABLE_MASK; writew(sepmask, MCF_IPSBAR + MCF_GPIO_PAR_UART); } +static void __init m527x_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m527x_uart_platform); + int line; + + for (line = 0; (line < nrlines); line++) + m527x_uart_init_line(line, m527x_uart_platform[line].irq); +} + /***************************************************************************/ static void __init m527x_fec_init(void) @@ -87,14 +353,32 @@ static void __init m527x_fec_init(void) /***************************************************************************/ +static void m527x_cpu_reset(void) +{ + local_irq_disable(); + __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR); +} + +/***************************************************************************/ + void __init config_BSP(char *commandp, int size) { - mach_sched_init = hw_timer_init; + mach_reset = m527x_cpu_reset; m527x_uarts_init(); m527x_fec_init(); -#ifdef CONFIG_SPI_COLDFIRE_QSPI +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) m527x_qspi_init(); #endif } /***************************************************************************/ + +static int __init init_BSP(void) +{ + platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices)); + return 0; +} + +arch_initcall(init_BSP); + +/***************************************************************************/ diff --git a/trunk/arch/m68k/platform/528x/config.c b/trunk/arch/m68k/platform/528x/config.c index d4492926614c..7abe77a2f3e3 100644 --- a/trunk/arch/m68k/platform/528x/config.c +++ b/trunk/arch/m68k/platform/528x/config.c @@ -17,33 +17,229 @@ #include #include #include +#include +#include #include #include #include #include +#include /***************************************************************************/ -#ifdef CONFIG_SPI_COLDFIRE_QSPI +static struct mcf_platform_uart m528x_uart_platform[] = { + { + .mapbase = MCFUART_BASE1, + .irq = MCFINT_VECBASE + MCFINT_UART0, + }, + { + .mapbase = MCFUART_BASE2, + .irq = MCFINT_VECBASE + MCFINT_UART0 + 1, + }, + { + .mapbase = MCFUART_BASE3, + .irq = MCFINT_VECBASE + MCFINT_UART0 + 2, + }, + { }, +}; + +static struct platform_device m528x_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m528x_uart_platform, +}; + +static struct resource m528x_fec_resources[] = { + { + .start = MCFFEC_BASE, + .end = MCFFEC_BASE + MCFFEC_SIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = 64 + 23, + .end = 64 + 23, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 27, + .end = 64 + 27, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 29, + .end = 64 + 29, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device m528x_fec = { + .name = "fec", + .id = 0, + .num_resources = ARRAY_SIZE(m528x_fec_resources), + .resource = m528x_fec_resources, +}; + +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m528x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#define MCFQSPI_CS0 147 +#define MCFQSPI_CS1 148 +#define MCFQSPI_CS2 149 +#define MCFQSPI_CS3 150 + +static int m528x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); + goto fail3; + } + status = gpio_direction_output(MCFQSPI_CS3, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); + goto fail4; + } + + return 0; + +fail4: + gpio_free(MCFQSPI_CS3); +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m528x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS3); + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m528x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high); +} + +static void m528x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high); +} + +static struct mcfqspi_cs_control m528x_cs_control = { + .setup = m528x_cs_setup, + .teardown = m528x_cs_teardown, + .select = m528x_cs_select, + .deselect = m528x_cs_deselect, +}; + +static struct mcfqspi_platform_data m528x_qspi_data = { + .bus_num = 0, + .num_chipselect = 4, + .cs_control = &m528x_cs_control, +}; + +static struct platform_device m528x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m528x_qspi_resources), + .resource = m528x_qspi_resources, + .dev.platform_data = &m528x_qspi_data, +}; static void __init m528x_qspi_init(void) { /* setup Port QS for QSPI with gpio CS control */ __raw_writeb(0x07, MCFGPIO_PQSPAR); } +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ -#endif /* CONFIG_SPI_COLDFIRE_QSPI */ +static struct platform_device *m528x_devices[] __initdata = { + &m528x_uart, + &m528x_fec, +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m528x_qspi, +#endif +}; /***************************************************************************/ -static void __init m528x_uarts_init(void) +static void __init m528x_uart_init_line(int line, int irq) { u8 port; + if ((line < 0) || (line > 2)) + return; + /* make sure PUAPAR is set for UART0 and UART1 */ - port = readb(MCF5282_GPIO_PUAPAR); - port |= 0x03 | (0x03 << 2); - writeb(port, MCF5282_GPIO_PUAPAR); + if (line < 2) { + port = readb(MCF5282_GPIO_PUAPAR); + port |= (0x03 << (line * 2)); + writeb(port, MCF5282_GPIO_PUAPAR); + } +} + +static void __init m528x_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m528x_uart_platform); + int line; + + for (line = 0; (line < nrlines); line++) + m528x_uart_init_line(line, m528x_uart_platform[line].irq); } /***************************************************************************/ @@ -60,6 +256,14 @@ static void __init m528x_fec_init(void) /***************************************************************************/ +static void m528x_cpu_reset(void) +{ + local_irq_disable(); + __raw_writeb(MCF_RCR_SWRESET, MCF_IPSBAR + MCF_RCR); +} + +/***************************************************************************/ + #ifdef CONFIG_WILDFIRE void wildfire_halt(void) { @@ -95,12 +299,22 @@ void __init config_BSP(char *commandp, int size) #ifdef CONFIG_WILDFIREMOD mach_halt = wildfiremod_halt; #endif - mach_sched_init = hw_timer_init; +} + +/***************************************************************************/ + +static int __init init_BSP(void) +{ + mach_reset = m528x_cpu_reset; m528x_uarts_init(); m528x_fec_init(); -#ifdef CONFIG_SPI_COLDFIRE_QSPI +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) m528x_qspi_init(); #endif + platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices)); + return 0; } +arch_initcall(init_BSP); + /***************************************************************************/ diff --git a/trunk/arch/m68k/platform/5307/config.c b/trunk/arch/m68k/platform/5307/config.c index a568d2870d15..00900ac06a9c 100644 --- a/trunk/arch/m68k/platform/5307/config.c +++ b/trunk/arch/m68k/platform/5307/config.c @@ -16,6 +16,7 @@ #include #include #include +#include #include /***************************************************************************/ @@ -28,6 +29,82 @@ unsigned char ledbank = 0xff; /***************************************************************************/ +static struct mcf_platform_uart m5307_uart_platform[] = { + { + .mapbase = MCF_MBAR + MCFUART_BASE1, + .irq = 73, + }, + { + .mapbase = MCF_MBAR + MCFUART_BASE2, + .irq = 74, + }, + { }, +}; + +static struct platform_device m5307_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m5307_uart_platform, +}; + +static struct platform_device *m5307_devices[] __initdata = { + &m5307_uart, +}; + +/***************************************************************************/ + +static void __init m5307_uart_init_line(int line, int irq) +{ + if (line == 0) { + writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); + writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR); + mcf_mapirq2imr(irq, MCFINTC_UART0); + } else if (line == 1) { + writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); + writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR); + mcf_mapirq2imr(irq, MCFINTC_UART1); + } +} + +static void __init m5307_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m5307_uart_platform); + int line; + + for (line = 0; (line < nrlines); line++) + m5307_uart_init_line(line, m5307_uart_platform[line].irq); +} + +/***************************************************************************/ + +static void __init m5307_timers_init(void) +{ + /* Timer1 is always used as system timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER1ICR); + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); + +#ifdef CONFIG_HIGHPROFILE + /* Timer2 is to be used as a high speed profile timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER2ICR); + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); +#endif +} + +/***************************************************************************/ + +void m5307_cpu_reset(void) +{ + local_irq_disable(); + /* Set watchdog to soft reset, and enabled */ + __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); + for (;;) + /* wait for watchdog to timeout */; +} + +/***************************************************************************/ + void __init config_BSP(char *commandp, int size) { #if defined(CONFIG_NETtel) || \ @@ -37,7 +114,9 @@ void __init config_BSP(char *commandp, int size) commandp[size-1] = 0; #endif - mach_sched_init = hw_timer_init; + mach_reset = m5307_cpu_reset; + m5307_timers_init(); + m5307_uarts_init(); /* Only support the external interrupts on their primary level */ mcf_mapirq2imr(25, MCFINTC_EINT1); @@ -56,3 +135,13 @@ void __init config_BSP(char *commandp, int size) } /***************************************************************************/ + +static int __init init_BSP(void) +{ + platform_add_devices(m5307_devices, ARRAY_SIZE(m5307_devices)); + return 0; +} + +arch_initcall(init_BSP); + +/***************************************************************************/ diff --git a/trunk/arch/m68k/platform/532x/config.c b/trunk/arch/m68k/platform/532x/config.c index 2bec3477b739..ca51323f957b 100644 --- a/trunk/arch/m68k/platform/532x/config.c +++ b/trunk/arch/m68k/platform/532x/config.c @@ -21,33 +21,214 @@ #include #include #include +#include +#include #include #include #include #include #include #include +#include /***************************************************************************/ -#ifdef CONFIG_SPI_COLDFIRE_QSPI +static struct mcf_platform_uart m532x_uart_platform[] = { + { + .mapbase = MCFUART_BASE1, + .irq = MCFINT_VECBASE + MCFINT_UART0, + }, + { + .mapbase = MCFUART_BASE2, + .irq = MCFINT_VECBASE + MCFINT_UART1, + }, + { + .mapbase = MCFUART_BASE3, + .irq = MCFINT_VECBASE + MCFINT_UART2, + }, + { }, +}; + +static struct platform_device m532x_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m532x_uart_platform, +}; + +static struct resource m532x_fec_resources[] = { + { + .start = 0xfc030000, + .end = 0xfc0307ff, + .flags = IORESOURCE_MEM, + }, + { + .start = 64 + 36, + .end = 64 + 36, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 40, + .end = 64 + 40, + .flags = IORESOURCE_IRQ, + }, + { + .start = 64 + 42, + .end = 64 + 42, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device m532x_fec = { + .name = "fec", + .id = 0, + .num_resources = ARRAY_SIZE(m532x_fec_resources), + .resource = m532x_fec_resources, +}; + +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +static struct resource m532x_qspi_resources[] = { + { + .start = MCFQSPI_IOBASE, + .end = MCFQSPI_IOBASE + MCFQSPI_IOSIZE - 1, + .flags = IORESOURCE_MEM, + }, + { + .start = MCFINT_VECBASE + MCFINT_QSPI, + .end = MCFINT_VECBASE + MCFINT_QSPI, + .flags = IORESOURCE_IRQ, + }, +}; + +#define MCFQSPI_CS0 84 +#define MCFQSPI_CS1 85 +#define MCFQSPI_CS2 86 + +static int m532x_cs_setup(struct mcfqspi_cs_control *cs_control) +{ + int status; + + status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); + goto fail0; + } + status = gpio_direction_output(MCFQSPI_CS0, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); + goto fail1; + } + + status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); + goto fail1; + } + status = gpio_direction_output(MCFQSPI_CS1, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); + goto fail2; + } + + status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); + if (status) { + pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); + goto fail2; + } + status = gpio_direction_output(MCFQSPI_CS2, 1); + if (status) { + pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); + goto fail3; + } + + return 0; + +fail3: + gpio_free(MCFQSPI_CS2); +fail2: + gpio_free(MCFQSPI_CS1); +fail1: + gpio_free(MCFQSPI_CS0); +fail0: + return status; +} + +static void m532x_cs_teardown(struct mcfqspi_cs_control *cs_control) +{ + gpio_free(MCFQSPI_CS2); + gpio_free(MCFQSPI_CS1); + gpio_free(MCFQSPI_CS0); +} + +static void m532x_cs_select(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + gpio_set_value(MCFQSPI_CS0 + chip_select, cs_high); +} + +static void m532x_cs_deselect(struct mcfqspi_cs_control *cs_control, + u8 chip_select, bool cs_high) +{ + gpio_set_value(MCFQSPI_CS0 + chip_select, !cs_high); +} + +static struct mcfqspi_cs_control m532x_cs_control = { + .setup = m532x_cs_setup, + .teardown = m532x_cs_teardown, + .select = m532x_cs_select, + .deselect = m532x_cs_deselect, +}; + +static struct mcfqspi_platform_data m532x_qspi_data = { + .bus_num = 0, + .num_chipselect = 3, + .cs_control = &m532x_cs_control, +}; + +static struct platform_device m532x_qspi = { + .name = "mcfqspi", + .id = 0, + .num_resources = ARRAY_SIZE(m532x_qspi_resources), + .resource = m532x_qspi_resources, + .dev.platform_data = &m532x_qspi_data, +}; static void __init m532x_qspi_init(void) { /* setup QSPS pins for QSPI with gpio CS control */ writew(0x01f0, MCF_GPIO_PAR_QSPI); } +#endif /* defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) */ -#endif /* CONFIG_SPI_COLDFIRE_QSPI */ + +static struct platform_device *m532x_devices[] __initdata = { + &m532x_uart, + &m532x_fec, +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + &m532x_qspi, +#endif +}; /***************************************************************************/ -static void __init m532x_uarts_init(void) +static void __init m532x_uart_init_line(int line, int irq) { - /* UART GPIO initialization */ - MCF_GPIO_PAR_UART |= 0x0FFF; + if (line == 0) { + /* GPIO initialization */ + MCF_GPIO_PAR_UART |= 0x000F; + } else if (line == 1) { + /* GPIO initialization */ + MCF_GPIO_PAR_UART |= 0x0FF0; + } } +static void __init m532x_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m532x_uart_platform); + int line; + + for (line = 0; (line < nrlines); line++) + m532x_uart_init_line(line, m532x_uart_platform[line].irq); +} /***************************************************************************/ static void __init m532x_fec_init(void) @@ -61,6 +242,14 @@ static void __init m532x_fec_init(void) /***************************************************************************/ +static void m532x_cpu_reset(void) +{ + local_irq_disable(); + __raw_writeb(MCF_RCR_SWRESET, MCF_RCR); +} + +/***************************************************************************/ + void __init config_BSP(char *commandp, int size) { #if !defined(CONFIG_BOOTPARAM) @@ -74,13 +263,6 @@ void __init config_BSP(char *commandp, int size) } #endif - mach_sched_init = hw_timer_init; - m532x_uarts_init(); - m532x_fec_init(); -#ifdef CONFIG_SPI_COLDFIRE_QSPI - m532x_qspi_init(); -#endif - #ifdef CONFIG_BDM_DISABLE /* * Disable the BDM clocking. This also turns off most of the rest of @@ -91,6 +273,21 @@ void __init config_BSP(char *commandp, int size) #endif } +/***************************************************************************/ + +static int __init init_BSP(void) +{ + m532x_uarts_init(); + m532x_fec_init(); +#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) + m532x_qspi_init(); +#endif + platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices)); + return 0; +} + +arch_initcall(init_BSP); + /***************************************************************************/ /* Board initialization */ /***************************************************************************/ diff --git a/trunk/arch/m68k/platform/5407/config.c b/trunk/arch/m68k/platform/5407/config.c index bb6c746ae819..70ea789a400c 100644 --- a/trunk/arch/m68k/platform/5407/config.c +++ b/trunk/arch/m68k/platform/5407/config.c @@ -16,12 +16,91 @@ #include #include #include +#include + +/***************************************************************************/ + +static struct mcf_platform_uart m5407_uart_platform[] = { + { + .mapbase = MCF_MBAR + MCFUART_BASE1, + .irq = 73, + }, + { + .mapbase = MCF_MBAR + MCFUART_BASE2, + .irq = 74, + }, + { }, +}; + +static struct platform_device m5407_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m5407_uart_platform, +}; + +static struct platform_device *m5407_devices[] __initdata = { + &m5407_uart, +}; + +/***************************************************************************/ + +static void __init m5407_uart_init_line(int line, int irq) +{ + if (line == 0) { + writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); + writeb(irq, MCF_MBAR + MCFUART_BASE1 + MCFUART_UIVR); + mcf_mapirq2imr(irq, MCFINTC_UART0); + } else if (line == 1) { + writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); + writeb(irq, MCF_MBAR + MCFUART_BASE2 + MCFUART_UIVR); + mcf_mapirq2imr(irq, MCFINTC_UART1); + } +} + +static void __init m5407_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m5407_uart_platform); + int line; + + for (line = 0; (line < nrlines); line++) + m5407_uart_init_line(line, m5407_uart_platform[line].irq); +} + +/***************************************************************************/ + +static void __init m5407_timers_init(void) +{ + /* Timer1 is always used as system timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER1ICR); + mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); + +#ifdef CONFIG_HIGHPROFILE + /* Timer2 is to be used as a high speed profile timer */ + writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, + MCF_MBAR + MCFSIM_TIMER2ICR); + mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); +#endif +} + +/***************************************************************************/ + +void m5407_cpu_reset(void) +{ + local_irq_disable(); + /* set watchdog to soft reset, and enabled */ + __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); + for (;;) + /* wait for watchdog to timeout */; +} /***************************************************************************/ void __init config_BSP(char *commandp, int size) { - mach_sched_init = hw_timer_init; + mach_reset = m5407_cpu_reset; + m5407_timers_init(); + m5407_uarts_init(); /* Only support the external interrupts on their primary level */ mcf_mapirq2imr(25, MCFINTC_EINT1); @@ -31,3 +110,13 @@ void __init config_BSP(char *commandp, int size) } /***************************************************************************/ + +static int __init init_BSP(void) +{ + platform_add_devices(m5407_devices, ARRAY_SIZE(m5407_devices)); + return 0; +} + +arch_initcall(init_BSP); + +/***************************************************************************/ diff --git a/trunk/arch/m68k/platform/54xx/config.c b/trunk/arch/m68k/platform/54xx/config.c index 2081c6cbb3de..ee043540bfa2 100644 --- a/trunk/arch/m68k/platform/54xx/config.c +++ b/trunk/arch/m68k/platform/54xx/config.c @@ -27,17 +27,64 @@ /***************************************************************************/ -static void __init m54xx_uarts_init(void) +static struct mcf_platform_uart m54xx_uart_platform[] = { + { + .mapbase = MCF_MBAR + MCFUART_BASE1, + .irq = 64 + 35, + }, + { + .mapbase = MCF_MBAR + MCFUART_BASE2, + .irq = 64 + 34, + }, + { + .mapbase = MCF_MBAR + MCFUART_BASE3, + .irq = 64 + 33, + }, + { + .mapbase = MCF_MBAR + MCFUART_BASE4, + .irq = 64 + 32, + }, +}; + +static struct platform_device m54xx_uart = { + .name = "mcfuart", + .id = 0, + .dev.platform_data = m54xx_uart_platform, +}; + +static struct platform_device *m54xx_devices[] __initdata = { + &m54xx_uart, +}; + + +/***************************************************************************/ + +static void __init m54xx_uart_init_line(int line, int irq) { + int rts_cts; + /* enable io pins */ - __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD, - MCF_MBAR + MCF_PAR_PSC(0)); - __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS, - MCF_MBAR + MCF_PAR_PSC(1)); - __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD | MCF_PAR_PSC_RTS_RTS | - MCF_PAR_PSC_CTS_CTS, MCF_MBAR + MCF_PAR_PSC(2)); - __raw_writeb(MCF_PAR_PSC_TXD | MCF_PAR_PSC_RXD, - MCF_MBAR + MCF_PAR_PSC(3)); + switch (line) { + case 0: + rts_cts = 0; break; + case 1: + rts_cts = MCF_PAR_PSC_RTS_RTS; break; + case 2: + rts_cts = MCF_PAR_PSC_RTS_RTS | MCF_PAR_PSC_CTS_CTS; break; + case 3: + rts_cts = 0; break; + } + __raw_writeb(MCF_PAR_PSC_TXD | rts_cts | MCF_PAR_PSC_RXD, + MCF_MBAR + MCF_PAR_PSC(line)); +} + +static void __init m54xx_uarts_init(void) +{ + const int nrlines = ARRAY_SIZE(m54xx_uart_platform); + int line; + + for (line = 0; (line < nrlines); line++) + m54xx_uart_init_line(line, m54xx_uart_platform[line].irq); } /***************************************************************************/ @@ -98,8 +145,18 @@ void __init config_BSP(char *commandp, int size) mmu_context_init(); #endif mach_reset = mcf54xx_reset; - mach_sched_init = hw_timer_init; m54xx_uarts_init(); } /***************************************************************************/ + +static int __init init_BSP(void) +{ + + platform_add_devices(m54xx_devices, ARRAY_SIZE(m54xx_devices)); + return 0; +} + +arch_initcall(init_BSP); + +/***************************************************************************/ diff --git a/trunk/arch/m68k/platform/68328/config.c b/trunk/arch/m68k/platform/68328/config.c index 44b866544314..d70bf2623db1 100644 --- a/trunk/arch/m68k/platform/68328/config.c +++ b/trunk/arch/m68k/platform/68328/config.c @@ -17,7 +17,6 @@ #include #include -#include #include #include #include @@ -27,7 +26,7 @@ /***************************************************************************/ -int m68328_hwclk(int set, struct rtc_time *t); +void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); /***************************************************************************/ @@ -49,7 +48,7 @@ void config_BSP(char *command, int len) printk(KERN_INFO "68328 support Kenneth Albanowski \n"); printk(KERN_INFO "68328/Pilot support Bernhard Kuhn \n"); - mach_hwclk = m68328_hwclk; + mach_gettod = m68328_timer_gettod; mach_reset = m68328_reset; } diff --git a/trunk/arch/m68k/platform/68328/ints.c b/trunk/arch/m68k/platform/68328/ints.c index b3810febb3e3..4bd456531f91 100644 --- a/trunk/arch/m68k/platform/68328/ints.c +++ b/trunk/arch/m68k/platform/68328/ints.c @@ -68,6 +68,8 @@ asmlinkage irqreturn_t inthandler5(void); asmlinkage irqreturn_t inthandler6(void); asmlinkage irqreturn_t inthandler7(void); +extern e_vector *_ramvec; + /* The 68k family did not have a good way to determine the source * of interrupts until later in the family. The EC000 core does * not provide the vector number on the stack, we vector everything diff --git a/trunk/arch/m68k/platform/68328/timers.c b/trunk/arch/m68k/platform/68328/timers.c index b15ddef1ec76..f2678866067b 100644 --- a/trunk/arch/m68k/platform/68328/timers.c +++ b/trunk/arch/m68k/platform/68328/timers.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -120,17 +119,14 @@ void hw_timer_init(void) /***************************************************************************/ -int m68328_hwclk(int set, struct rtc_time *t) +void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec) { - if (!set) { - long now = RTCTIME; - t->tm_year = t->tm_mon = t->tm_mday = 1; - t->tm_hour = (now >> 24) % 24; - t->tm_min = (now >> 16) % 60; - t->tm_sec = now % 60; - } - - return 0; + long now = RTCTIME; + + *year = *mon = *day = 1; + *hour = (now >> 24) % 24; + *min = (now >> 16) % 60; + *sec = now % 60; } /***************************************************************************/ diff --git a/trunk/arch/m68k/platform/68360/config.c b/trunk/arch/m68k/platform/68360/config.c index 599a5949f320..9dd5bca38749 100644 --- a/trunk/arch/m68k/platform/68360/config.c +++ b/trunk/arch/m68k/platform/68360/config.c @@ -103,6 +103,11 @@ void hw_timer_init(void) pquicc->timer_tgcr = tgcr_save; } +void BSP_gettod (int *yearp, int *monp, int *dayp, + int *hourp, int *minp, int *secp) +{ +} + int BSP_set_clock_mmss(unsigned long nowtime) { #if 0 @@ -176,5 +181,6 @@ void config_BSP(char *command, int len) scc1_hwaddr = "\00\01\02\03\04\05"; #endif - mach_reset = BSP_reset; + mach_gettod = BSP_gettod; + mach_reset = BSP_reset; } diff --git a/trunk/arch/m68k/platform/68360/ints.c b/trunk/arch/m68k/platform/68360/ints.c index 8cd42692331b..7b40202d9638 100644 --- a/trunk/arch/m68k/platform/68360/ints.c +++ b/trunk/arch/m68k/platform/68360/ints.c @@ -32,6 +32,8 @@ asmlinkage void trap(void); asmlinkage void bad_interrupt(void); asmlinkage void inthandler(void); +extern void *_ramvec[]; + static void intc_irq_unmask(struct irq_data *d) { pquicc->intr_cimr |= (1 << d->irq); diff --git a/trunk/arch/m68k/platform/68EZ328/config.c b/trunk/arch/m68k/platform/68EZ328/config.c index dd2c53554341..1be1a16f6896 100644 --- a/trunk/arch/m68k/platform/68EZ328/config.c +++ b/trunk/arch/m68k/platform/68EZ328/config.c @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -26,7 +25,7 @@ /***************************************************************************/ -int m68328_hwclk(int set, struct rtc_time *t); +void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); /***************************************************************************/ @@ -70,7 +69,7 @@ void config_BSP(char *command, int len) else command[0] = 0; #endif - mach_hwclk = m68328_hwclk; + mach_gettod = m68328_timer_gettod; mach_reset = m68ez328_reset; } diff --git a/trunk/arch/m68k/platform/68VZ328/config.c b/trunk/arch/m68k/platform/68VZ328/config.c index 25ec673edc25..eabaabe8af36 100644 --- a/trunk/arch/m68k/platform/68VZ328/config.c +++ b/trunk/arch/m68k/platform/68VZ328/config.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -34,7 +33,7 @@ /***************************************************************************/ -int m68328_hwclk(int set, struct rtc_time *t); +void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); /***************************************************************************/ /* Init Drangon Engine hardware */ @@ -182,7 +181,7 @@ void config_BSP(char *command, int size) init_hardware(command, size); - mach_hwclk = m68328_hwclk; + mach_gettod = m68328_timer_gettod; mach_reset = m68vz328_reset; } diff --git a/trunk/arch/m68k/platform/coldfire/Makefile b/trunk/arch/m68k/platform/coldfire/Makefile index a0815c61dec1..a8967baabd72 100644 --- a/trunk/arch/m68k/platform/coldfire/Makefile +++ b/trunk/arch/m68k/platform/coldfire/Makefile @@ -14,18 +14,18 @@ asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 -obj-$(CONFIG_COLDFIRE) += cache.o clk.o device.o dma.o entry.o vectors.o -obj-$(CONFIG_M5206) += timers.o intc.o reset.o -obj-$(CONFIG_M5206e) += timers.o intc.o reset.o -obj-$(CONFIG_M520x) += pit.o intc-simr.o reset.o -obj-$(CONFIG_M523x) += pit.o dma_timer.o intc-2.o reset.o -obj-$(CONFIG_M5249) += timers.o intc.o reset.o -obj-$(CONFIG_M527x) += pit.o intc-2.o reset.o +obj-$(CONFIG_COLDFIRE) += cache.o clk.o dma.o entry.o vectors.o +obj-$(CONFIG_M5206) += timers.o intc.o +obj-$(CONFIG_M5206e) += timers.o intc.o +obj-$(CONFIG_M520x) += pit.o intc-simr.o +obj-$(CONFIG_M523x) += pit.o dma_timer.o intc-2.o +obj-$(CONFIG_M5249) += timers.o intc.o +obj-$(CONFIG_M527x) += pit.o intc-2.o obj-$(CONFIG_M5272) += timers.o -obj-$(CONFIG_M528x) += pit.o intc-2.o reset.o -obj-$(CONFIG_M5307) += timers.o intc.o reset.o -obj-$(CONFIG_M532x) += timers.o intc-simr.o reset.o -obj-$(CONFIG_M5407) += timers.o intc.o reset.o +obj-$(CONFIG_M528x) += pit.o intc-2.o +obj-$(CONFIG_M5307) += timers.o intc.o +obj-$(CONFIG_M532x) += timers.o intc-simr.o +obj-$(CONFIG_M5407) += timers.o intc.o obj-$(CONFIG_M54xx) += sltimers.o intc-2.o obj-y += pinmux.o gpio.o diff --git a/trunk/arch/m68k/platform/coldfire/device.c b/trunk/arch/m68k/platform/coldfire/device.c deleted file mode 100644 index fa50c48292ff..000000000000 --- a/trunk/arch/m68k/platform/coldfire/device.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * device.c -- common ColdFire SoC device support - * - * (C) Copyright 2011, Greg Ungerer - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * All current ColdFire parts contain from 2, 3 or 4 UARTS. - */ -static struct mcf_platform_uart mcf_uart_platform_data[] = { - { - .mapbase = MCFUART_BASE0, - .irq = MCF_IRQ_UART0, - }, - { - .mapbase = MCFUART_BASE1, - .irq = MCF_IRQ_UART1, - }, -#ifdef MCFUART_BASE2 - { - .mapbase = MCFUART_BASE2, - .irq = MCF_IRQ_UART2, - }, -#endif -#ifdef MCFUART_BASE3 - { - .mapbase = MCFUART_BASE3, - .irq = MCF_IRQ_UART3, - }, -#endif - { }, -}; - -static struct platform_device mcf_uart = { - .name = "mcfuart", - .id = 0, - .dev.platform_data = mcf_uart_platform_data, -}; - -#ifdef CONFIG_FEC -/* - * Some ColdFire cores contain the Fast Ethernet Controller (FEC) - * block. It is Freescale's own hardware block. Some ColdFires - * have 2 of these. - */ -static struct resource mcf_fec0_resources[] = { - { - .start = MCFFEC_BASE0, - .end = MCFFEC_BASE0 + MCFFEC_SIZE0 - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MCF_IRQ_FECRX0, - .end = MCF_IRQ_FECRX0, - .flags = IORESOURCE_IRQ, - }, - { - .start = MCF_IRQ_FECTX0, - .end = MCF_IRQ_FECTX0, - .flags = IORESOURCE_IRQ, - }, - { - .start = MCF_IRQ_FECENTC0, - .end = MCF_IRQ_FECENTC0, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device mcf_fec0 = { - .name = "fec", - .id = 0, - .num_resources = ARRAY_SIZE(mcf_fec0_resources), - .resource = mcf_fec0_resources, -}; - -#ifdef MCFFEC_BASE1 -static struct resource mcf_fec1_resources[] = { - { - .start = MCFFEC_BASE1, - .end = MCFFEC_BASE1 + MCFFEC_SIZE1 - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MCF_IRQ_FECRX1, - .end = MCF_IRQ_FECRX1, - .flags = IORESOURCE_IRQ, - }, - { - .start = MCF_IRQ_FECTX1, - .end = MCF_IRQ_FECTX1, - .flags = IORESOURCE_IRQ, - }, - { - .start = MCF_IRQ_FECENTC1, - .end = MCF_IRQ_FECENTC1, - .flags = IORESOURCE_IRQ, - }, -}; - -static struct platform_device mcf_fec1 = { - .name = "fec", - .id = 0, - .num_resources = ARRAY_SIZE(mcf_fec1_resources), - .resource = mcf_fec1_resources, -}; -#endif /* MCFFEC_BASE1 */ -#endif /* CONFIG_FEC */ - -#ifdef CONFIG_SPI_COLDFIRE_QSPI -/* - * The ColdFire QSPI module is an SPI protocol hardware block used - * on a number of different ColdFire CPUs. - */ -static struct resource mcf_qspi_resources[] = { - { - .start = MCFQSPI_BASE, - .end = MCFQSPI_BASE + MCFQSPI_SIZE - 1, - .flags = IORESOURCE_MEM, - }, - { - .start = MCF_IRQ_QSPI, - .end = MCF_IRQ_QSPI, - .flags = IORESOURCE_IRQ, - }, -}; - -static int mcf_cs_setup(struct mcfqspi_cs_control *cs_control) -{ - int status; - - status = gpio_request(MCFQSPI_CS0, "MCFQSPI_CS0"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS0 failed\n"); - goto fail0; - } - status = gpio_direction_output(MCFQSPI_CS0, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS0 failed\n"); - goto fail1; - } - - status = gpio_request(MCFQSPI_CS1, "MCFQSPI_CS1"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS1 failed\n"); - goto fail1; - } - status = gpio_direction_output(MCFQSPI_CS1, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS1 failed\n"); - goto fail2; - } - - status = gpio_request(MCFQSPI_CS2, "MCFQSPI_CS2"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS2 failed\n"); - goto fail2; - } - status = gpio_direction_output(MCFQSPI_CS2, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS2 failed\n"); - goto fail3; - } - -#ifdef MCFQSPI_CS3 - status = gpio_request(MCFQSPI_CS3, "MCFQSPI_CS3"); - if (status) { - pr_debug("gpio_request for MCFQSPI_CS3 failed\n"); - goto fail3; - } - status = gpio_direction_output(MCFQSPI_CS3, 1); - if (status) { - pr_debug("gpio_direction_output for MCFQSPI_CS3 failed\n"); - gpio_free(MCFQSPI_CS3); - goto fail3; - } -#endif - - return 0; - -fail3: - gpio_free(MCFQSPI_CS2); -fail2: - gpio_free(MCFQSPI_CS1); -fail1: - gpio_free(MCFQSPI_CS0); -fail0: - return status; -} - -static void mcf_cs_teardown(struct mcfqspi_cs_control *cs_control) -{ -#ifdef MCFQSPI_CS3 - gpio_free(MCFQSPI_CS3); -#endif - gpio_free(MCFQSPI_CS2); - gpio_free(MCFQSPI_CS1); - gpio_free(MCFQSPI_CS0); -} - -static void mcf_cs_select(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, cs_high); - break; -#ifdef MCFQSPI_CS3 - case 3: - gpio_set_value(MCFQSPI_CS3, cs_high); - break; -#endif - } -} - -static void mcf_cs_deselect(struct mcfqspi_cs_control *cs_control, - u8 chip_select, bool cs_high) -{ - switch (chip_select) { - case 0: - gpio_set_value(MCFQSPI_CS0, !cs_high); - break; - case 1: - gpio_set_value(MCFQSPI_CS1, !cs_high); - break; - case 2: - gpio_set_value(MCFQSPI_CS2, !cs_high); - break; -#ifdef MCFQSPI_CS3 - case 3: - gpio_set_value(MCFQSPI_CS3, !cs_high); - break; -#endif - } -} - -static struct mcfqspi_cs_control mcf_cs_control = { - .setup = mcf_cs_setup, - .teardown = mcf_cs_teardown, - .select = mcf_cs_select, - .deselect = mcf_cs_deselect, -}; - -static struct mcfqspi_platform_data mcf_qspi_data = { - .bus_num = 0, - .num_chipselect = 4, - .cs_control = &mcf_cs_control, -}; - -static struct platform_device mcf_qspi = { - .name = "mcfqspi", - .id = 0, - .num_resources = ARRAY_SIZE(mcf_qspi_resources), - .resource = mcf_qspi_resources, - .dev.platform_data = &mcf_qspi_data, -}; -#endif /* CONFIG_SPI_COLDFIRE_QSPI */ - -static struct platform_device *mcf_devices[] __initdata = { - &mcf_uart, -#ifdef CONFIG_FEC - &mcf_fec0, -#ifdef MCFFEC_BASE1 - &mcf_fec1, -#endif -#endif -#ifdef CONFIG_SPI_COLDFIRE_QSPI - &mcf_qspi, -#endif -}; - -/* - * Some ColdFire UARTs let you set the IRQ line to use. - */ -static void __init mcf_uart_set_irq(void) -{ -#ifdef MCFUART_UIVR - /* UART0 interrupt setup */ - writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR); - writeb(MCF_IRQ_UART0, MCFUART_BASE0 + MCFUART_UIVR); - mcf_mapirq2imr(MCF_IRQ_UART0, MCFINTC_UART0); - - /* UART1 interrupt setup */ - writeb(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI2, MCF_MBAR + MCFSIM_UART2ICR); - writeb(MCF_IRQ_UART1, MCFUART_BASE1 + MCFUART_UIVR); - mcf_mapirq2imr(MCF_IRQ_UART1, MCFINTC_UART1); -#endif -} - -static int __init mcf_init_devices(void) -{ - mcf_uart_set_irq(); - platform_add_devices(mcf_devices, ARRAY_SIZE(mcf_devices)); - return 0; -} - -arch_initcall(mcf_init_devices); - diff --git a/trunk/arch/m68k/platform/coldfire/head.S b/trunk/arch/m68k/platform/coldfire/head.S index c3db70ed33b3..38f04a3f6207 100644 --- a/trunk/arch/m68k/platform/coldfire/head.S +++ b/trunk/arch/m68k/platform/coldfire/head.S @@ -158,10 +158,6 @@ _start: #if defined(CONFIG_UBOOT) movel %sp,_init_sp /* save initial stack pointer */ #endif -#ifdef CONFIG_MBAR - movel #CONFIG_MBAR+1,%d0 /* configured MBAR address */ - movec %d0,%MBAR /* set it */ -#endif /* * Do any platform or board specific setup now. Most boards diff --git a/trunk/arch/m68k/platform/coldfire/pit.c b/trunk/arch/m68k/platform/coldfire/pit.c index e62dbbcb10f6..02663d25822d 100644 --- a/trunk/arch/m68k/platform/coldfire/pit.c +++ b/trunk/arch/m68k/platform/coldfire/pit.c @@ -149,7 +149,7 @@ static struct clocksource pit_clk = { /***************************************************************************/ -void hw_timer_init(irq_handler_t handler) +void hw_timer_init(void) { cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id()); cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32); diff --git a/trunk/arch/m68k/platform/coldfire/reset.c b/trunk/arch/m68k/platform/coldfire/reset.c deleted file mode 100644 index 933e54eacc69..000000000000 --- a/trunk/arch/m68k/platform/coldfire/reset.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * reset.c -- common ColdFire SoC reset support - * - * (C) Copyright 2012, Greg Ungerer - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#include -#include -#include -#include -#include -#include - -/* - * There are 2 common methods amongst the ColdFure parts for reseting - * the CPU. But there are couple of exceptions, the 5272 and the 547x - * have something completely special to them, and we let their specific - * subarch code handle them. - */ - -#ifdef MCFSIM_SYPCR -static void mcf_cpu_reset(void) -{ - local_irq_disable(); - /* Set watchdog to soft reset, and enabled */ - __raw_writeb(0xc0, MCF_MBAR + MCFSIM_SYPCR); - for (;;) - /* wait for watchdog to timeout */; -} -#endif - -#ifdef MCF_RCR -static void mcf_cpu_reset(void) -{ - local_irq_disable(); - __raw_writeb(MCF_RCR_SWRESET, MCF_RCR); -} -#endif - -static int __init mcf_setup_reset(void) -{ - mach_reset = mcf_cpu_reset; - return 0; -} - -arch_initcall(mcf_setup_reset); diff --git a/trunk/arch/m68k/platform/coldfire/sltimers.c b/trunk/arch/m68k/platform/coldfire/sltimers.c index 2027fc20b876..54e1452f853a 100644 --- a/trunk/arch/m68k/platform/coldfire/sltimers.c +++ b/trunk/arch/m68k/platform/coldfire/sltimers.c @@ -81,14 +81,12 @@ void mcfslt_profile_init(void) static u32 mcfslt_cycles_per_jiffy; static u32 mcfslt_cnt; -static irq_handler_t timer_interrupt; - static irqreturn_t mcfslt_tick(int irq, void *dummy) { /* Reset Slice Timer 0 */ __raw_writel(MCFSLT_SSR_BE | MCFSLT_SSR_TE, TA(MCFSLT_SSR)); mcfslt_cnt += mcfslt_cycles_per_jiffy; - return timer_interrupt(irq, dummy); + return arch_timer_interrupt(irq, dummy); } static struct irqaction mcfslt_timer_irq = { @@ -123,7 +121,7 @@ static struct clocksource mcfslt_clk = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -void hw_timer_init(irq_handler_t handler) +void hw_timer_init(void) { mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ; /* @@ -138,7 +136,6 @@ void hw_timer_init(irq_handler_t handler) /* initialize mcfslt_cnt knowing that slice timers count down */ mcfslt_cnt = mcfslt_cycles_per_jiffy; - timer_interrupt = handler; setup_irq(MCF_IRQ_TIMER, &mcfslt_timer_irq); clocksource_register_hz(&mcfslt_clk, MCF_BUSCLK); diff --git a/trunk/arch/m68k/platform/coldfire/timers.c b/trunk/arch/m68k/platform/coldfire/timers.c index ed96ce50d79f..0d90da32fcdb 100644 --- a/trunk/arch/m68k/platform/coldfire/timers.c +++ b/trunk/arch/m68k/platform/coldfire/timers.c @@ -47,27 +47,6 @@ void coldfire_profile_init(void); static u32 mcftmr_cycles_per_jiffy; static u32 mcftmr_cnt; -static irq_handler_t timer_interrupt; - -/***************************************************************************/ - -static void init_timer_irq(void) -{ -#ifdef MCFSIM_ICR_AUTOVEC - /* Timer1 is always used as system timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER1ICR); - mcf_mapirq2imr(MCF_IRQ_TIMER, MCFINTC_TIMER1); - -#ifdef CONFIG_HIGHPROFILE - /* Timer2 is to be used as a high speed profile timer */ - writeb(MCFSIM_ICR_AUTOVEC | MCFSIM_ICR_LEVEL7 | MCFSIM_ICR_PRI3, - MCF_MBAR + MCFSIM_TIMER2ICR); - mcf_mapirq2imr(MCF_IRQ_PROFILER, MCFINTC_TIMER2); -#endif -#endif /* MCFSIM_ICR_AUTOVEC */ -} - /***************************************************************************/ static irqreturn_t mcftmr_tick(int irq, void *dummy) @@ -76,7 +55,7 @@ static irqreturn_t mcftmr_tick(int irq, void *dummy) __raw_writeb(MCFTIMER_TER_CAP | MCFTIMER_TER_REF, TA(MCFTIMER_TER)); mcftmr_cnt += mcftmr_cycles_per_jiffy; - return timer_interrupt(irq, dummy); + return arch_timer_interrupt(irq, dummy); } /***************************************************************************/ @@ -115,7 +94,7 @@ static struct clocksource mcftmr_clk = { /***************************************************************************/ -void hw_timer_init(irq_handler_t handler) +void hw_timer_init(void) { __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); mcftmr_cycles_per_jiffy = FREQ / HZ; @@ -131,8 +110,6 @@ void hw_timer_init(irq_handler_t handler) clocksource_register_hz(&mcftmr_clk, FREQ); - timer_interrupt = handler; - init_timer_irq(); setup_irq(MCF_IRQ_TIMER, &mcftmr_timer_irq); #ifdef CONFIG_HIGHPROFILE diff --git a/trunk/arch/m68k/platform/coldfire/vectors.c b/trunk/arch/m68k/platform/coldfire/vectors.c index a4dbdecbec7a..3a7cc524ecd3 100644 --- a/trunk/arch/m68k/platform/coldfire/vectors.c +++ b/trunk/arch/m68k/platform/coldfire/vectors.c @@ -33,6 +33,8 @@ asmlinkage void dbginterrupt_c(struct frame *fp) /***************************************************************************/ +extern e_vector *_ramvec; + /* Assembler routines */ asmlinkage void buserr(void); asmlinkage void trap(void); diff --git a/trunk/arch/powerpc/Kconfig b/trunk/arch/powerpc/Kconfig index d219ebecabf0..303703d716fe 100644 --- a/trunk/arch/powerpc/Kconfig +++ b/trunk/arch/powerpc/Kconfig @@ -134,7 +134,6 @@ config PPC select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64 select HAVE_GENERIC_HARDIRQS select HAVE_SPARSE_IRQ - select SPARSE_IRQ select IRQ_PER_CPU select IRQ_DOMAIN select GENERIC_IRQ_SHOW @@ -378,16 +377,13 @@ config CRASH_DUMP The same kernel binary can be used as production kernel and dump capture kernel. -config FA_DUMP - bool "Firmware-assisted dump" - depends on PPC64 && PPC_RTAS && CRASH_DUMP +config PHYP_DUMP + bool "Hypervisor-assisted dump (EXPERIMENTAL)" + depends on PPC_PSERIES && EXPERIMENTAL help - A robust mechanism to get reliable kernel crash dump with - assistance from firmware. This approach does not use kexec, - instead firmware assists in booting the kdump kernel - while preserving memory contents. Firmware-assisted dump - is meant to be a kdump replacement offering robustness and - speed not possible without system firmware assistance. + Hypervisor-assisted dump is meant to be a kdump replacement + offering robustness and speed not possible without system + hypervisor assistance. If unsure, say "N" @@ -616,7 +612,7 @@ endmenu config ISA_DMA_API bool - default PCI + default !PPC_ISERIES || PCI menu "Bus options" diff --git a/trunk/arch/powerpc/Kconfig.debug b/trunk/arch/powerpc/Kconfig.debug index 72d55dbc6119..4ccb2a009f74 100644 --- a/trunk/arch/powerpc/Kconfig.debug +++ b/trunk/arch/powerpc/Kconfig.debug @@ -196,6 +196,13 @@ config PPC_EARLY_DEBUG_MAPLE help Select this to enable early debugging for Maple. +config PPC_EARLY_DEBUG_ISERIES + bool "iSeries HV Console" + depends on PPC_ISERIES + help + Select this to enable early debugging for legacy iSeries. You need + to hit "Ctrl-x Ctrl-x" to see the messages on the console. + config PPC_EARLY_DEBUG_PAS_REALMODE bool "PA Semi real mode" depends on PPC_PASEMI diff --git a/trunk/arch/powerpc/Makefile b/trunk/arch/powerpc/Makefile index 6524c6e21896..b8b105c01c64 100644 --- a/trunk/arch/powerpc/Makefile +++ b/trunk/arch/powerpc/Makefile @@ -157,7 +157,6 @@ core-y += arch/powerpc/kernel/ \ arch/powerpc/net/ core-$(CONFIG_XMON) += arch/powerpc/xmon/ core-$(CONFIG_KVM) += arch/powerpc/kvm/ -core-$(CONFIG_PERF_EVENTS) += arch/powerpc/perf/ drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ diff --git a/trunk/arch/powerpc/boot/Makefile b/trunk/arch/powerpc/boot/Makefile index e8461cb18d04..8844a17ce8ed 100644 --- a/trunk/arch/powerpc/boot/Makefile +++ b/trunk/arch/powerpc/boot/Makefile @@ -184,6 +184,7 @@ image-$(CONFIG_PPC_EFIKA) += zImage.chrp image-$(CONFIG_PPC_PMAC) += zImage.pmac image-$(CONFIG_PPC_HOLLY) += dtbImage.holly image-$(CONFIG_PPC_PRPMC2800) += dtbImage.prpmc2800 +image-$(CONFIG_PPC_ISERIES) += zImage.iseries image-$(CONFIG_DEFAULT_UIMAGE) += uImage image-$(CONFIG_EPAPR_BOOT) += zImage.epapr @@ -246,7 +247,7 @@ image-$(CONFIG_ASP834x) += dtbImage.asp834x-redboot image-$(CONFIG_MPC8540_ADS) += cuImage.mpc8540ads image-$(CONFIG_MPC8560_ADS) += cuImage.mpc8560ads image-$(CONFIG_MPC85xx_CDS) += cuImage.mpc8541cds \ - cuImage.mpc8548cds_32b \ + cuImage.mpc8548cds \ cuImage.mpc8555cds image-$(CONFIG_MPC85xx_MDS) += cuImage.mpc8568mds image-$(CONFIG_MPC85xx_DS) += cuImage.mpc8544ds \ @@ -310,6 +311,12 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb $(obj)/vmlinux.strip: vmlinux $(STRIP) -s -R .comment $< -o $@ +# The iseries hypervisor won't take an ET_DYN executable, so this +# changes the type (byte 17) in the file to ET_EXEC (2). +$(obj)/zImage.iseries: vmlinux + $(STRIP) -s -R .comment $< -o $@ + printf "\x02" | dd of=$@ conv=notrunc bs=1 seek=17 + $(obj)/uImage: vmlinux $(wrapperbits) $(call if_changed,wrap,uboot) @@ -357,7 +364,7 @@ install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y)) # anything not in $(targets) clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \ zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \ - zImage.miboot zImage.pmac zImage.pseries \ + zImage.iseries zImage.miboot zImage.pmac zImage.pseries \ zImage.maple simpleImage.* otheros.bld *.dtb # clean up files cached by wrapper diff --git a/trunk/arch/powerpc/boot/dts/a4m072.dts b/trunk/arch/powerpc/boot/dts/a4m072.dts deleted file mode 100644 index fabe7b7d5f13..000000000000 --- a/trunk/arch/powerpc/boot/dts/a4m072.dts +++ /dev/null @@ -1,168 +0,0 @@ -/* - * a4m072 board Device Tree Source - * - * Copyright (C) 2011 DENX Software Engineering GmbH - * Heiko Schocher - * - * Copyright (C) 2007 Semihalf - * Marian Balakowicz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/include/ "mpc5200b.dtsi" - -/ { - model = "anonymous,a4m072"; - compatible = "anonymous,a4m072"; - - soc5200@f0000000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc5200b-immr"; - ranges = <0 0xf0000000 0x0000c000>; - reg = <0xf0000000 0x00000100>; - bus-frequency = <0>; /* From boot loader */ - system-frequency = <0>; /* From boot loader */ - - cdm@200 { - fsl,init-ext-48mhz-en = <0x0>; - fsl,init-fd-enable = <0x01>; - fsl,init-fd-counters = <0x3333>; - }; - - timer@600 { - fsl,has-wdt; - }; - - gpt3: timer@630 { /* General Purpose Timer in GPIO mode */ - compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio"; - gpio-controller; - #gpio-cells = <2>; - }; - - gpt4: timer@640 { /* General Purpose Timer in GPIO mode */ - compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio"; - gpio-controller; - #gpio-cells = <2>; - }; - - gpt5: timer@650 { /* General Purpose Timer in GPIO mode */ - compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio"; - gpio-controller; - #gpio-cells = <2>; - }; - - spi@f00 { - status = "disabled"; - }; - - psc@2000 { - compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; - reg = <0x2000 0x100>; - interrupts = <2 1 0>; - }; - - psc@2200 { - compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; - reg = <0x2200 0x100>; - interrupts = <2 2 0>; - }; - - psc@2400 { - compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; - reg = <0x2400 0x100>; - interrupts = <2 3 0>; - }; - - psc@2600 { - status = "disabled"; - }; - - psc@2800 { - status = "disabled"; - }; - - psc@2c00 { - compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; - reg = <0x2c00 0x100>; - interrupts = <2 4 0>; - }; - - ethernet@3000 { - phy-handle = <&phy0>; - }; - - mdio@3000 { - phy0: ethernet-phy@1f { - reg = <0x1f>; - interrupts = <1 2 0>; /* IRQ 2 active low */ - }; - }; - - i2c@3d00 { - status = "disabled"; - }; - - i2c@3d40 { - hwmon@2e { - compatible = "nsc,lm87"; - reg = <0x2e>; - }; - rtc@51 { - compatible = "nxp,rtc8564"; - reg = <0x51>; - }; - }; - }; - - localbus { - compatible = "fsl,mpc5200b-lpb","simple-bus"; - #address-cells = <2>; - #size-cells = <1>; - ranges = <0 0 0xfe000000 0x02000000 - 1 0 0x62000000 0x00400000 - 2 0 0x64000000 0x00200000 - 3 0 0x66000000 0x01000000 - 6 0 0x68000000 0x01000000 - 7 0 0x6a000000 0x00000004>; - - flash@0,0 { - compatible = "cfi-flash"; - reg = <0 0 0x02000000>; - bank-width = <2>; - #size-cells = <1>; - #address-cells = <1>; - }; - sram0@1,0 { - compatible = "mtd-ram"; - reg = <1 0x00000 0x00400000>; - bank-width = <2>; - }; - }; - - pci@f0000d00 { - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - device_type = "pci"; - compatible = "fsl,mpc5200-pci"; - reg = <0xf0000d00 0x100>; - interrupt-map-mask = <0xf800 0 0 7>; - interrupt-map = < - /* IDSEL 0x16 */ - 0xc000 0 0 1 &mpc5200_pic 1 3 3 - 0xc000 0 0 2 &mpc5200_pic 1 3 3 - 0xc000 0 0 3 &mpc5200_pic 1 3 3 - 0xc000 0 0 4 &mpc5200_pic 1 3 3>; - clock-frequency = <0>; /* From boot loader */ - interrupts = <2 8 0 2 9 0 2 10 0>; - bus-range = <0 0>; - ranges = <0x42000000 0 0x80000000 0x80000000 0 0x10000000 - 0x02000000 0 0x90000000 0x90000000 0 0x10000000 - 0x01000000 0 0x00000000 0xa0000000 0 0x01000000>; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/bluestone.dts b/trunk/arch/powerpc/boot/dts/bluestone.dts index 7bda373f10ef..74876f737407 100644 --- a/trunk/arch/powerpc/boot/dts/bluestone.dts +++ b/trunk/arch/powerpc/boot/dts/bluestone.dts @@ -33,7 +33,7 @@ aliases { ethernet0 = &EMAC0; serial0 = &UART0; - serial1 = &UART1; + //serial1 = &UART1; --gcl missing UART1 label }; cpus { @@ -52,7 +52,7 @@ d-cache-size = <32768>; dcr-controller; dcr-access-method = "native"; - next-level-cache = <&L2C0>; + //next-level-cache = <&L2C0>; --gcl missing L2C0 label }; }; @@ -117,16 +117,6 @@ dcr-reg = <0x00c 0x002>; }; - L2C0: l2c { - compatible = "ibm,l2-cache-apm82181", "ibm,l2-cache"; - dcr-reg = <0x020 0x008 - 0x030 0x008>; - cache-line-size = <32>; - cache-size = <262144>; - interrupt-parent = <&UIC1>; - interrupts = <11 1>; - }; - plb { compatible = "ibm,plb4"; #address-cells = <2>; @@ -192,53 +182,6 @@ reg = <0x001a0000 0x00060000>; }; }; - - ndfc@1,0 { - compatible = "ibm,ndfc"; - reg = <0x00000003 0x00000000 0x00002000>; - ccr = <0x00001000>; - bank-settings = <0x80002222>; - #address-cells = <1>; - #size-cells = <1>; - /* 2Gb Nand Flash */ - nand { - #address-cells = <1>; - #size-cells = <1>; - - partition@0 { - label = "firmware"; - reg = <0x00000000 0x00C00000>; - }; - partition@c00000 { - label = "environment"; - reg = <0x00C00000 0x00B00000>; - }; - partition@1700000 { - label = "kernel"; - reg = <0x01700000 0x00E00000>; - }; - partition@2500000 { - label = "root"; - reg = <0x02500000 0x08200000>; - }; - partition@a700000 { - label = "device-tree"; - reg = <0x0A700000 0x00B00000>; - }; - partition@b200000 { - label = "config"; - reg = <0x0B200000 0x00D00000>; - }; - partition@bf00000 { - label = "diag"; - reg = <0x0BF00000 0x00C00000>; - }; - partition@cb00000 { - label = "vendor"; - reg = <0x0CB00000 0x3500000>; - }; - }; - }; }; UART0: serial@ef600300 { @@ -252,36 +195,11 @@ interrupts = <0x1 0x4>; }; - UART1: serial@ef600400 { - device_type = "serial"; - compatible = "ns16550"; - reg = <0xef600400 0x00000008>; - virtual-reg = <0xef600400>; - clock-frequency = <0>; /* Filled in by U-Boot */ - current-speed = <0>; /* Filled in by U-Boot */ - interrupt-parent = <&UIC0>; - interrupts = <0x1 0x4>; - }; - IIC0: i2c@ef600700 { compatible = "ibm,iic"; reg = <0xef600700 0x00000014>; interrupt-parent = <&UIC0>; interrupts = <0x2 0x4>; - #address-cells = <1>; - #size-cells = <0>; - rtc@68 { - compatible = "stm,m41t80"; - reg = <0x68>; - interrupt-parent = <&UIC0>; - interrupts = <0x9 0x8>; - }; - sttm@4C { - compatible = "adm,adm1032"; - reg = <0x4C>; - interrupt-parent = <&UIC1>; - interrupts = <0x1E 0x8>; /* CPU_THERNAL_L */ - }; }; IIC1: i2c@ef600800 { @@ -332,46 +250,5 @@ }; }; - PCIE0: pciex@d00000000 { - device_type = "pci"; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - compatible = "ibm,plb-pciex-apm821xx", "ibm,plb-pciex"; - primary; - port = <0x0>; /* port number */ - reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */ - 0x0000000c 0x08010000 0x00001000>; /* Registers */ - dcr-reg = <0x100 0x020>; - sdr-base = <0x300>; - - /* Outbound ranges, one memory and one IO, - * later cannot be changed - */ - ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 - 0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000 - 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; - - /* Inbound 2GB range starting at 0 */ - dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; - - /* This drives busses 40 to 0x7f */ - bus-range = <0x40 0x7f>; - - /* Legacy interrupts (note the weird polarity, the bridge seems - * to invert PCIe legacy interrupts). - * We are de-swizzling here because the numbers are actually for - * port of the root complex virtual P2P bridge. But I want - * to avoid putting a node for it in the tree, so the numbers - * below are basically de-swizzled numbers. - * The real slot is on idsel 0, so the swizzling is 1:1 - */ - interrupt-map-mask = <0x0 0x0 0x0 0x7>; - interrupt-map = < - 0x0 0x0 0x0 0x1 &UIC3 0xc 0x4 /* swizzled int A */ - 0x0 0x0 0x0 0x2 &UIC3 0xd 0x4 /* swizzled int B */ - 0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */ - 0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>; - }; }; }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi index c8b2daa40ac8..b37da56018b6 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi @@ -202,7 +202,7 @@ /include/ "pq3-etsec1-timer-0.dtsi" usb@22000 { - compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; + compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; reg = <0x22000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -210,7 +210,7 @@ }; usb@23000 { - compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; + compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; reg = <0x23000 0x1000>; #address-cells = <1>; #size-cells = <0>; diff --git a/trunk/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi index 579d76cb8e32..9d8023a69d7d 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi @@ -89,21 +89,6 @@ }; }; -&rio { - compatible = "fsl,srio"; - interrupts = <48 2 0 0>; - #address-cells = <2>; - #size-cells = <2>; - fsl,srio-rmu-handle = <&rmu>; - ranges; - - port1 { - #address-cells = <2>; - #size-cells = <2>; - cell-index = <1>; - }; -}; - &soc { #address-cells = <1>; #size-cells = <1>; @@ -149,7 +134,6 @@ /include/ "pq3-sec2.1-0.dtsi" /include/ "pq3-mpic.dtsi" -/include/ "pq3-rmu-0.dtsi" global-utilities@e0000 { compatible = "fsl,mpc8548-guts"; diff --git a/trunk/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi b/trunk/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi index 720422d83529..289f1218d755 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi @@ -43,9 +43,7 @@ serial0 = &serial0; serial1 = &serial1; ethernet0 = &enet0; - ethernet1 = &enet1; - ethernet2 = &enet2; - ethernet3 = &enet3; + ethernet1 = &enet2; pci0 = &pci0; pci1 = &pci1; pci2 = &pci2; diff --git a/trunk/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi index 0bde9ee8afaf..a97d1263372c 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi @@ -156,9 +156,6 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" - usb@22000 { - compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; - }; /include/ "pq3-esdhc-0.dtsi" sdhc@2e000 { compatible = "fsl,p1010-esdhc", "fsl,esdhc"; diff --git a/trunk/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi index 68cc5e7f6477..5de5fc351314 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi @@ -142,13 +142,7 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" - usb@22000 { - compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; - }; /include/ "pq3-usb2-dr-1.dtsi" - usb@23000 { - compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; - }; /include/ "pq3-esdhc-0.dtsi" sdhc@2e000 { diff --git a/trunk/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi index 4252ef85fb7a..38ba54d1e32e 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi @@ -142,15 +142,8 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" - usb@22000 { - compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; - }; /include/ "pq3-esdhc-0.dtsi" - sdhc@2e000 { - sdhci,auto-cmd12; - }; - /include/ "pq3-sec3.3-0.dtsi" /include/ "pq3-mpic.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi index 06216b8c0af5..ff9ed1d87929 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi @@ -35,11 +35,7 @@ &lbc { #address-cells = <2>; #size-cells = <1>; - /* - * The localbus on the P1022 is not a simple-bus because of the eLBC - * pin muxing when the DIU is enabled. - */ - compatible = "fsl,p1022-elbc", "fsl,elbc"; + compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus"; interrupts = <19 2 0 0>; }; @@ -203,13 +199,7 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" - usb@22000 { - compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; - }; /include/ "pq3-usb2-dr-1.dtsi" - usb@23000 { - compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; - }; /include/ "pq3-esdhc-0.dtsi" sdhc@2e000 { diff --git a/trunk/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi index 941fa159cefb..b06bb4cc1fe8 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi @@ -142,9 +142,6 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" - usb@22000 { - compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; - }; crypto: crypto@300000 { compatible = "fsl,sec-v4.2", "fsl,sec-v4.0"; diff --git a/trunk/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi index 884e01bcb243..332e9e75e6c2 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi @@ -171,9 +171,6 @@ /include/ "pq3-dma-0.dtsi" /include/ "pq3-usb2-dr-0.dtsi" - usb@22000 { - compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; - }; /include/ "pq3-etsec1-0.dtsi" /include/ "pq3-etsec1-timer-0.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi index 531eab82c6c9..234a399ddeb2 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi @@ -309,14 +309,12 @@ /include/ "qoriq-gpio-0.dtsi" /include/ "qoriq-usb2-mph-0.dtsi" usb0: usb@210000 { - compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; phy_type = "utmi"; port0; }; /include/ "qoriq-usb2-dr-0.dtsi" usb1: usb@211000 { - compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; dr_mode = "host"; phy_type = "utmi"; }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi index af4ebc8009e3..d41d08de7f7e 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi @@ -336,14 +336,12 @@ /include/ "qoriq-gpio-0.dtsi" /include/ "qoriq-usb2-mph-0.dtsi" usb0: usb@210000 { - compatible = "fsl-usb2-mph-v1.6", "fsl-usb2-mph"; phy_type = "utmi"; port0; }; /include/ "qoriq-usb2-dr-0.dtsi" usb1: usb@211000 { - compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; dr_mode = "host"; phy_type = "utmi"; }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi index b3e56929eee2..a63edd195ae5 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi @@ -291,12 +291,6 @@ /include/ "qoriq-duart-1.dtsi" /include/ "qoriq-gpio-0.dtsi" /include/ "qoriq-usb2-mph-0.dtsi" - usb@210000 { - compatible = "fsl-usb2-mph-v2.2", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; - }; /include/ "qoriq-usb2-dr-0.dtsi" - usb@211000 { - compatible = "fsl-usb2-dr-v2.2", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; - }; /include/ "qoriq-sec4.1-0.dtsi" }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/trunk/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi index 64b6abea8464..914074b91a85 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi @@ -339,14 +339,12 @@ /include/ "qoriq-gpio-0.dtsi" /include/ "qoriq-usb2-mph-0.dtsi" usb0: usb@210000 { - compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; phy_type = "utmi"; port0; }; /include/ "qoriq-usb2-dr-0.dtsi" usb1: usb@211000 { - compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; dr_mode = "host"; phy_type = "utmi"; }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi b/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi index 3b0650a98478..a1979ae334a7 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x24000 ] * - * Copyright 2011-2012 Freescale Semiconductor Inc. + * Copyright 2011 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,7 +41,6 @@ ethernet@24000 { compatible = "gianfar"; reg = <0x24000 0x1000>; ranges = <0x0 0x24000 0x1000>; - fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>; }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi b/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi index 96693b41f0f1..4c4fdde1ec2a 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x25000 ] * - * Copyright 2011-2012 Freescale Semiconductor Inc. + * Copyright 2011 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,7 +41,6 @@ ethernet@25000 { compatible = "gianfar"; reg = <0x25000 0x1000>; ranges = <0x0 0x25000 0x1000>; - fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>; }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi b/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi index 6b3fab19da1f..4b8ab438668a 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x26000 ] * - * Copyright 2011-2012 Freescale Semiconductor Inc. + * Copyright 2011 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,7 +41,6 @@ ethernet@26000 { compatible = "gianfar"; reg = <0x26000 0x1000>; ranges = <0x0 0x26000 0x1000>; - fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 0 0 32 2 0 0 33 2 0 0>; }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi b/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi index 0da592d93ddd..40c9137729ae 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x27000 ] * - * Copyright 2011-2012 Freescale Semiconductor Inc. + * Copyright 2011 Freescale Semiconductor Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -41,7 +41,6 @@ ethernet@27000 { compatible = "gianfar"; reg = <0x27000 0x1000>; ranges = <0x0 0x27000 0x1000>; - fsl,magic-packet; local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 0 0 38 2 0 0 39 2 0 0>; }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi b/trunk/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi index fdedf7b1fe0f..5c8046065844 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi @@ -39,9 +39,6 @@ mpic: pic@40000 { reg = <0x40000 0x40000>; compatible = "fsl,mpic"; device_type = "open-pic"; - big-endian; - single-cpu-affinity; - last-interrupt-source = <255>; }; timer@41100 { diff --git a/trunk/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi b/trunk/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi index d4c9d5daab21..bf957a7fca2a 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi @@ -33,32 +33,32 @@ */ crypto@30000 { - compatible = "fsl,sec-v4.4", "fsl,sec-v4.0"; + compatible = "fsl,sec4.4", "fsl,sec4.0"; #address-cells = <1>; #size-cells = <1>; reg = <0x30000 0x10000>; interrupts = <58 2 0 0>; sec_jr0: jr@1000 { - compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; reg = <0x1000 0x1000>; interrupts = <45 2 0 0>; }; sec_jr1: jr@2000 { - compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; reg = <0x2000 0x1000>; interrupts = <45 2 0 0>; }; sec_jr2: jr@3000 { - compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; reg = <0x3000 0x1000>; interrupts = <45 2 0 0>; }; sec_jr3: jr@4000 { - compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; + compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; reg = <0x4000 0x1000>; interrupts = <45 2 0 0>; }; diff --git a/trunk/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi b/trunk/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi index 08f42271f86a..b9bada6a87dc 100644 --- a/trunk/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi +++ b/trunk/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi @@ -53,7 +53,7 @@ timer@41100 { msi0: msi@41600 { compatible = "fsl,mpic-msi"; - reg = <0x41600 0x200 0x44140 4>; + reg = <0x41600 0x200>; msi-available-ranges = <0 0x100>; interrupts = < 0xe0 0 0 0 @@ -68,7 +68,7 @@ msi0: msi@41600 { msi1: msi@41800 { compatible = "fsl,mpic-msi"; - reg = <0x41800 0x200 0x45140 4>; + reg = <0x41800 0x200>; msi-available-ranges = <0 0x100>; interrupts = < 0xe8 0 0 0 @@ -83,7 +83,7 @@ msi1: msi@41800 { msi2: msi@41a00 { compatible = "fsl,mpic-msi"; - reg = <0x41a00 0x200 0x46140 4>; + reg = <0x41a00 0x200>; msi-available-ranges = <0 0x100>; interrupts = < 0xf0 0 0 0 diff --git a/trunk/arch/powerpc/boot/dts/ge_imp3a.dts b/trunk/arch/powerpc/boot/dts/ge_imp3a.dts deleted file mode 100644 index fefae416a097..000000000000 --- a/trunk/arch/powerpc/boot/dts/ge_imp3a.dts +++ /dev/null @@ -1,255 +0,0 @@ -/* - * GE IMP3A Device Tree Source - * - * Copyright 2010-2011 GE Intelligent Platforms Embedded Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Based on: P2020 DS Device Tree Source - * Copyright 2009 Freescale Semiconductor Inc. - */ - -/include/ "fsl/p2020si-pre.dtsi" - -/ { - model = "GE_IMP3A"; - compatible = "ge,imp3a"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@fef05000 { - reg = <0 0xfef05000 0 0x1000>; - - ranges = <0x0 0x0 0x0 0xff000000 0x01000000 - 0x1 0x0 0x0 0xe0000000 0x08000000 - 0x2 0x0 0x0 0xe8000000 0x08000000 - 0x3 0x0 0x0 0xfc100000 0x00020000 - 0x4 0x0 0x0 0xfc000000 0x00008000 - 0x5 0x0 0x0 0xfc008000 0x00008000 - 0x6 0x0 0x0 0xfee00000 0x00040000 - 0x7 0x0 0x0 0xfee80000 0x00040000>; - - /* nor@0,0 is a mirror of part of the memory in nor@1,0 - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "ge,imp3a-firmware-mirror", "cfi-flash"; - reg = <0x0 0x0 0x1000000>; - bank-width = <2>; - device-width = <1>; - - partition@0 { - label = "firmware"; - reg = <0x0 0x1000000>; - read-only; - }; - }; - */ - - nor@1,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "ge,imp3a-paged-flash", "cfi-flash"; - reg = <0x1 0x0 0x8000000>; - bank-width = <2>; - device-width = <1>; - - partition@0 { - label = "user"; - reg = <0x0 0x7800000>; - }; - - partition@7800000 { - label = "firmware"; - reg = <0x7800000 0x800000>; - read-only; - }; - }; - - nvram@3,0 { - device_type = "nvram"; - compatible = "simtek,stk14ca8"; - reg = <0x3 0x0 0x20000>; - }; - - fpga@4,0 { - compatible = "ge,imp3a-fpga-regs"; - reg = <0x4 0x0 0x20>; - }; - - gef_pic: pic@4,20 { - #interrupt-cells = <1>; - interrupt-controller; - device_type = "interrupt-controller"; - compatible = "ge,imp3a-fpga-pic", "gef,fpga-pic-1.00"; - reg = <0x4 0x20 0x20>; - interrupts = <6 7 0 0>; - }; - - gef_gpio: gpio@4,400 { - #gpio-cells = <2>; - compatible = "ge,imp3a-gpio"; - reg = <0x4 0x400 0x24>; - gpio-controller; - }; - - wdt@4,800 { - compatible = "ge,imp3a-fpga-wdt", "gef,fpga-wdt-1.00", - "gef,fpga-wdt"; - reg = <0x4 0x800 0x8>; - interrupts = <10 4>; - interrupt-parent = <&gef_pic>; - }; - - /* Second watchdog available, driver currently supports one. - wdt@4,808 { - compatible = "gef,imp3a-fpga-wdt", "gef,fpga-wdt-1.00", - "gef,fpga-wdt"; - reg = <0x4 0x808 0x8>; - interrupts = <9 4>; - interrupt-parent = <&gef_pic>; - }; - */ - - nand@6,0 { - compatible = "fsl,elbc-fcm-nand"; - reg = <0x6 0x0 0x40000>; - }; - - nand@7,0 { - compatible = "fsl,elbc-fcm-nand"; - reg = <0x7 0x0 0x40000>; - }; - }; - - soc: soc@fef00000 { - ranges = <0x0 0 0xfef00000 0x100000>; - - i2c@3000 { - hwmon@48 { - compatible = "national,lm92"; - reg = <0x48>; - }; - - hwmon@4c { - compatible = "adi,adt7461"; - reg = <0x4c>; - }; - - rtc@51 { - compatible = "epson,rx8581"; - reg = <0x51>; - }; - - eti@6b { - compatible = "dallas,ds1682"; - reg = <0x6b>; - }; - }; - - usb@22000 { - phy_type = "ulpi"; - dr_mode = "host"; - }; - - mdio@24520 { - phy0: ethernet-phy@0 { - interrupt-parent = <&gef_pic>; - interrupts = <0xc 0x4>; - reg = <0x1>; - }; - phy1: ethernet-phy@1 { - interrupt-parent = <&gef_pic>; - interrupts = <0xb 0x4>; - reg = <0x2>; - }; - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - mdio@25520 { - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - mdio@26520 { - status = "disabled"; - }; - - enet0: ethernet@24000 { - tbi-handle = <&tbi0>; - phy-handle = <&phy0>; - phy-connection-type = "gmii"; - }; - - enet1: ethernet@25000 { - tbi-handle = <&tbi1>; - phy-handle = <&phy1>; - phy-connection-type = "gmii"; - }; - - enet2: ethernet@26000 { - status = "disabled"; - }; - }; - - pci0: pcie@fef08000 { - ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xfe020000 0x0 0x10000>; - reg = <0 0xfef08000 0 0x1000>; - - pcie@0 { - ranges = <0x2000000 0x0 0xc0000000 - 0x2000000 0x0 0xc0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x10000>; - }; - }; - - pci1: pcie@fef09000 { - reg = <0 0xfef09000 0 0x1000>; - ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xfe010000 0x0 0x10000>; - - pcie@0 { - ranges = <0x2000000 0x0 0xa0000000 - 0x2000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x10000>; - }; - - }; - - pci2: pcie@fef0a000 { - reg = <0 0xfef0a000 0 0x1000>; - ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xfe000000 0x0 0x10000>; - - pcie@0 { - ranges = <0x2000000 0x0 0x80000000 - 0x2000000 0x0 0x80000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x10000>; - }; - }; -}; - -/include/ "fsl/p2020si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts b/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts index 81dd513d6308..c0e450a551bf 100644 --- a/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc836x_mds.dts @@ -405,10 +405,6 @@ reg = <0x1>; device_type = "ethernet-phy"; }; - tbi-phy@2 { - device_type = "tbi-phy"; - reg = <0x2>; - }; }; qeic: interrupt-controller@80 { diff --git a/trunk/arch/powerpc/boot/dts/mpc8536ds.dts b/trunk/arch/powerpc/boot/dts/mpc8536ds.dts index 19736222a0b9..c15881574fdc 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8536ds.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8536ds.dts @@ -1,7 +1,7 @@ /* * MPC8536 DS Device Tree Source * - * Copyright 2008, 2011 Freescale Semiconductor, Inc. + * Copyright 2008 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -34,10 +34,6 @@ lbc: localbus@ffe05000 { reg = <0 0xffe05000 0 0x1000>; - - ranges = <0x0 0x0 0x0 0xe8000000 0x08000000 - 0x2 0x0 0x0 0xffa00000 0x00040000 - 0x3 0x0 0x0 0xffdf0000 0x00008000>; }; board_soc: soc: soc@ffe00000 { diff --git a/trunk/arch/powerpc/boot/dts/mpc8536ds.dtsi b/trunk/arch/powerpc/boot/dts/mpc8536ds.dtsi index cc46dbd9746d..1462e4cf49d7 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8536ds.dtsi +++ b/trunk/arch/powerpc/boot/dts/mpc8536ds.dtsi @@ -32,99 +32,6 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -&lbc { - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x8000000>; - bank-width = <2>; - device-width = <1>; - - partition@0 { - reg = <0x0 0x03000000>; - label = "ramdisk-nor"; - }; - - partition@3000000 { - reg = <0x03000000 0x00e00000>; - label = "diagnostic-nor"; - read-only; - }; - - partition@3e00000 { - reg = <0x03e00000 0x00200000>; - label = "dink-nor"; - read-only; - }; - - partition@4000000 { - reg = <0x04000000 0x00400000>; - label = "kernel-nor"; - }; - - partition@4400000 { - reg = <0x04400000 0x03b00000>; - label = "fs-nor"; - }; - - partition@7f00000 { - reg = <0x07f00000 0x00080000>; - label = "dtb-nor"; - }; - - partition@7f80000 { - reg = <0x07f80000 0x00080000>; - label = "u-boot-nor"; - read-only; - }; - }; - - nand@2,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,mpc8536-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <0x2 0x0 0x40000>; - - partition@0 { - reg = <0x0 0x02000000>; - label = "u-boot-nand"; - read-only; - }; - - partition@2000000 { - reg = <0x02000000 0x10000000>; - label = "fs-nand"; - }; - - partition@12000000 { - reg = <0x12000000 0x08000000>; - label = "ramdisk-nand"; - }; - - partition@1a000000 { - reg = <0x1a000000 0x04000000>; - label = "kernel-nand"; - }; - - partition@1e000000 { - reg = <0x1e000000 0x01000000>; - label = "dtb-nand"; - }; - - partition@1f000000 { - reg = <0x1f000000 0x21000000>; - label = "empty-nand"; - }; - }; - - board-control@3,0 { - compatible = "fsl,mpc8536ds-fpga-pixis"; - reg = <0x3 0x0 0x8000>; - }; -}; - &board_soc { i2c@3100 { rtc@68 { diff --git a/trunk/arch/powerpc/boot/dts/mpc8536ds_36b.dts b/trunk/arch/powerpc/boot/dts/mpc8536ds_36b.dts index f8a3b3413176..8f4b929b1d1d 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8536ds_36b.dts +++ b/trunk/arch/powerpc/boot/dts/mpc8536ds_36b.dts @@ -1,7 +1,7 @@ /* * MPC8536DS Device Tree Source (36-bit address map) * - * Copyright 2008-2009, 2011 Freescale Semiconductor, Inc. + * Copyright 2008-2009 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -33,11 +33,7 @@ }; lbc: localbus@ffe05000 { - reg = <0xf 0xffe05000 0 0x1000>; - - ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 - 0x2 0x0 0xf 0xffa00000 0x00040000 - 0x3 0x0 0xf 0xffdf0000 0x00008000>; + reg = <0 0xffe05000 0 0x1000>; }; board_soc: soc: soc@fffe00000 { diff --git a/trunk/arch/powerpc/boot/dts/mpc8548cds.dts b/trunk/arch/powerpc/boot/dts/mpc8548cds.dts new file mode 100644 index 000000000000..07b8dae0f46e --- /dev/null +++ b/trunk/arch/powerpc/boot/dts/mpc8548cds.dts @@ -0,0 +1,306 @@ +/* + * MPC8548 CDS Device Tree Source + * + * Copyright 2006, 2008 Freescale Semiconductor Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +/include/ "fsl/mpc8548si-pre.dtsi" + +/ { + model = "MPC8548CDS"; + compatible = "MPC8548CDS", "MPC85xxCDS"; + + aliases { + ethernet0 = &enet0; + ethernet1 = &enet1; + ethernet2 = &enet2; + ethernet3 = &enet3; + serial0 = &serial0; + serial1 = &serial1; + pci0 = &pci0; + pci1 = &pci1; + pci2 = &pci2; + }; + + memory { + device_type = "memory"; + reg = <0 0 0x0 0x8000000>; // 128M at 0x0 + }; + + lbc: localbus@e0005000 { + reg = <0 0xe0005000 0 0x1000>; + }; + + soc: soc8548@e0000000 { + ranges = <0 0x0 0xe0000000 0x100000>; + + i2c@3000 { + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + + eeprom@56 { + compatible = "atmel,24c64"; + reg = <0x56>; + }; + + eeprom@57 { + compatible = "atmel,24c64"; + reg = <0x57>; + }; + }; + + i2c@3100 { + eeprom@50 { + compatible = "atmel,24c64"; + reg = <0x50>; + }; + }; + + enet0: ethernet@24000 { + tbi-handle = <&tbi0>; + phy-handle = <&phy0>; + }; + + mdio@24520 { + phy0: ethernet-phy@0 { + interrupts = <5 1 0 0>; + reg = <0x0>; + device_type = "ethernet-phy"; + }; + phy1: ethernet-phy@1 { + interrupts = <5 1 0 0>; + reg = <0x1>; + device_type = "ethernet-phy"; + }; + phy2: ethernet-phy@2 { + interrupts = <5 1 0 0>; + reg = <0x2>; + device_type = "ethernet-phy"; + }; + phy3: ethernet-phy@3 { + interrupts = <5 1 0 0>; + reg = <0x3>; + device_type = "ethernet-phy"; + }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet1: ethernet@25000 { + tbi-handle = <&tbi1>; + phy-handle = <&phy1>; + }; + + mdio@25520 { + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet2: ethernet@26000 { + tbi-handle = <&tbi2>; + phy-handle = <&phy2>; + }; + + mdio@26520 { + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet3: ethernet@27000 { + tbi-handle = <&tbi3>; + phy-handle = <&phy3>; + }; + + mdio@27520 { + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + }; + + pci0: pci@e0008000 { + reg = <0 0xe0008000 0 0x1000>; + ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000 + 0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>; + clock-frequency = <66666666>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + /* IDSEL 0x4 (PCIX Slot 2) */ + 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x5 (PCIX Slot 3) */ + 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 + 0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 + 0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 + 0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 + + /* IDSEL 0x6 (PCIX Slot 4) */ + 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 + 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 + 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 + 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 + + /* IDSEL 0x8 (PCIX Slot 5) */ + 0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0xC (Tsi310 bridge) */ + 0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x14 (Slot 2) */ + 0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x15 (Slot 3) */ + 0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 + 0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 + 0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 + 0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 + + /* IDSEL 0x16 (Slot 4) */ + 0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 + 0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 + 0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 + 0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 + + /* IDSEL 0x18 (Slot 5) */ + 0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x1C (Tsi310 bridge PCI primary) */ + 0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; + + pci_bridge@1c { + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + + /* IDSEL 0x00 (PrPMC Site) */ + 0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x04 (VIA chip) */ + 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 + 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 + + /* IDSEL 0x05 (8139) */ + 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 + + /* IDSEL 0x06 (Slot 6) */ + 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 + 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 + 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 + 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 + + /* IDESL 0x07 (Slot 7) */ + 0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0 + 0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0 + 0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0 + 0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>; + + reg = <0xe000 0x0 0x0 0x0 0x0>; + #interrupt-cells = <1>; + #size-cells = <2>; + #address-cells = <3>; + ranges = <0x2000000 0x0 0x80000000 + 0x2000000 0x0 0x80000000 + 0x0 0x20000000 + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x80000>; + clock-frequency = <33333333>; + + isa@4 { + device_type = "isa"; + #interrupt-cells = <2>; + #size-cells = <1>; + #address-cells = <2>; + reg = <0x2000 0x0 0x0 0x0 0x0>; + ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>; + interrupt-parent = <&i8259>; + + i8259: interrupt-controller@20 { + interrupt-controller; + device_type = "interrupt-controller"; + reg = <0x1 0x20 0x2 + 0x1 0xa0 0x2 + 0x1 0x4d0 0x2>; + #address-cells = <0>; + #interrupt-cells = <2>; + compatible = "chrp,iic"; + interrupts = <0 1 0 0>; + interrupt-parent = <&mpic>; + }; + + rtc@70 { + compatible = "pnpPNP,b00"; + reg = <0x1 0x70 0x2>; + }; + }; + }; + }; + + pci1: pci@e0009000 { + reg = <0 0xe0009000 0 0x1000>; + ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000 + 0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>; + clock-frequency = <66666666>; + interrupt-map-mask = <0xf800 0x0 0x0 0x7>; + interrupt-map = < + + /* IDSEL 0x15 */ + 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0 + 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 + 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 + 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; + }; + + pci2: pcie@e000a000 { + reg = <0 0xe000a000 0 0x1000>; + ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>; + pcie@0 { + ranges = <0x2000000 0x0 0xa0000000 + 0x2000000 0x0 0xa0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "fsl/mpc8548si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/mpc8548cds.dtsi b/trunk/arch/powerpc/boot/dts/mpc8548cds.dtsi deleted file mode 100644 index c61f525e4740..000000000000 --- a/trunk/arch/powerpc/boot/dts/mpc8548cds.dtsi +++ /dev/null @@ -1,306 +0,0 @@ -/* - * MPC8548CDS Device Tree Source stub (no addresses or top-level ranges) - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -&board_lbc { - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x01000000>; - bank-width = <2>; - device-width = <2>; - - partition@0 { - reg = <0x0 0x0b00000>; - label = "ramdisk-nor"; - }; - - partition@300000 { - reg = <0x0b00000 0x0400000>; - label = "kernel-nor"; - }; - - partition@700000 { - reg = <0x0f00000 0x060000>; - label = "dtb-nor"; - }; - - partition@760000 { - reg = <0x0f60000 0x020000>; - label = "env-nor"; - read-only; - }; - - partition@780000 { - reg = <0x0f80000 0x080000>; - label = "u-boot-nor"; - read-only; - }; - }; - - board-control@1,0 { - compatible = "fsl,mpc8548cds-fpga"; - reg = <0x1 0x0 0x1000>; - }; -}; - -&board_soc { - i2c@3000 { - eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; - }; - - eeprom@56 { - compatible = "atmel,24c64"; - reg = <0x56>; - }; - - eeprom@57 { - compatible = "atmel,24c64"; - reg = <0x57>; - }; - }; - - i2c@3100 { - eeprom@50 { - compatible = "atmel,24c64"; - reg = <0x50>; - }; - }; - - enet0: ethernet@24000 { - tbi-handle = <&tbi0>; - phy-handle = <&phy0>; - }; - - mdio@24520 { - phy0: ethernet-phy@0 { - interrupts = <5 1 0 0>; - reg = <0x0>; - device_type = "ethernet-phy"; - }; - phy1: ethernet-phy@1 { - interrupts = <5 1 0 0>; - reg = <0x1>; - device_type = "ethernet-phy"; - }; - phy2: ethernet-phy@2 { - interrupts = <5 1 0 0>; - reg = <0x2>; - device_type = "ethernet-phy"; - }; - phy3: ethernet-phy@3 { - interrupts = <5 1 0 0>; - reg = <0x3>; - device_type = "ethernet-phy"; - }; - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet1: ethernet@25000 { - tbi-handle = <&tbi1>; - phy-handle = <&phy1>; - }; - - mdio@25520 { - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet2: ethernet@26000 { - tbi-handle = <&tbi2>; - phy-handle = <&phy2>; - }; - - mdio@26520 { - tbi2: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet3: ethernet@27000 { - tbi-handle = <&tbi3>; - phy-handle = <&phy3>; - }; - - mdio@27520 { - tbi3: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; -}; - -&board_pci0 { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - /* IDSEL 0x4 (PCIX Slot 2) */ - 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x5 (PCIX Slot 3) */ - 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 - 0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 - 0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 - 0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 - - /* IDSEL 0x6 (PCIX Slot 4) */ - 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 - 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 - 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 - 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 - - /* IDSEL 0x8 (PCIX Slot 5) */ - 0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0xC (Tsi310 bridge) */ - 0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x14 (Slot 2) */ - 0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x15 (Slot 3) */ - 0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 - 0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 - 0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 - 0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 - - /* IDSEL 0x16 (Slot 4) */ - 0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 - 0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 - 0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 - 0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 - - /* IDSEL 0x18 (Slot 5) */ - 0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x1C (Tsi310 bridge PCI primary) */ - 0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; - - pci_bridge@1c { - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x00 (PrPMC Site) */ - 0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x04 (VIA chip) */ - 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 - 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 - - /* IDSEL 0x05 (8139) */ - 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 - - /* IDSEL 0x06 (Slot 6) */ - 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 - 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 - 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 - 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 - - /* IDESL 0x07 (Slot 7) */ - 0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0 - 0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0 - 0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0 - 0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>; - - reg = <0xe000 0x0 0x0 0x0 0x0>; - #interrupt-cells = <1>; - #size-cells = <2>; - #address-cells = <3>; - ranges = <0x2000000 0x0 0x80000000 - 0x2000000 0x0 0x80000000 - 0x0 0x20000000 - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x80000>; - clock-frequency = <33333333>; - - isa@4 { - device_type = "isa"; - #interrupt-cells = <2>; - #size-cells = <1>; - #address-cells = <2>; - reg = <0x2000 0x0 0x0 0x0 0x0>; - ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>; - interrupt-parent = <&i8259>; - - i8259: interrupt-controller@20 { - interrupt-controller; - device_type = "interrupt-controller"; - reg = <0x1 0x20 0x2 - 0x1 0xa0 0x2 - 0x1 0x4d0 0x2>; - #address-cells = <0>; - #interrupt-cells = <2>; - compatible = "chrp,iic"; - interrupts = <0 1 0 0>; - interrupt-parent = <&mpic>; - }; - - rtc@70 { - compatible = "pnpPNP,b00"; - reg = <0x1 0x70 0x2>; - }; - }; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/mpc8548cds_32b.dts b/trunk/arch/powerpc/boot/dts/mpc8548cds_32b.dts deleted file mode 100644 index 6fd63163fc6b..000000000000 --- a/trunk/arch/powerpc/boot/dts/mpc8548cds_32b.dts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * MPC8548 CDS Device Tree Source (32-bit address map) - * - * Copyright 2006, 2008, 2011-2012 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/include/ "fsl/mpc8548si-pre.dtsi" - -/ { - model = "MPC8548CDS"; - compatible = "MPC8548CDS", "MPC85xxCDS"; - - memory { - device_type = "memory"; - reg = <0 0 0x0 0x8000000>; // 128M at 0x0 - }; - - board_lbc: lbc: localbus@e0005000 { - reg = <0 0xe0005000 0 0x1000>; - - ranges = <0x0 0x0 0x0 0xff000000 0x01000000 - 0x1 0x0 0x0 0xf8004000 0x00001000>; - - }; - - board_soc: soc: soc8548@e0000000 { - ranges = <0 0x0 0xe0000000 0x100000>; - }; - - board_pci0: pci0: pci@e0008000 { - reg = <0 0xe0008000 0 0x1000>; - ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000 - 0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>; - clock-frequency = <66666666>; - }; - - pci1: pci@e0009000 { - reg = <0 0xe0009000 0 0x1000>; - ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000 - 0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>; - clock-frequency = <66666666>; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x15 */ - 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0 - 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; - }; - - pci2: pcie@e000a000 { - reg = <0 0xe000a000 0 0x1000>; - ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>; - pcie@0 { - ranges = <0x2000000 0x0 0xa0000000 - 0x2000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - rio: rapidio@e00c0000 { - reg = <0x0 0xe00c0000 0x0 0x20000>; - port1 { - ranges = <0x0 0x0 0x0 0xc0000000 0x0 0x20000000>; - }; - }; -}; - -/* - * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings - * for interrupt-map & interrupt-map-mask. - */ - -/include/ "fsl/mpc8548si-post.dtsi" -/include/ "mpc8548cds.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/mpc8548cds_36b.dts b/trunk/arch/powerpc/boot/dts/mpc8548cds_36b.dts deleted file mode 100644 index 10e551b11bd6..000000000000 --- a/trunk/arch/powerpc/boot/dts/mpc8548cds_36b.dts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * MPC8548 CDS Device Tree Source (36-bit address map) - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/include/ "fsl/mpc8548si-pre.dtsi" - -/ { - model = "MPC8548CDS"; - compatible = "MPC8548CDS", "MPC85xxCDS"; - - memory { - device_type = "memory"; - reg = <0 0 0x0 0x8000000>; // 128M at 0x0 - }; - - board_lbc: lbc: localbus@fe0005000 { - reg = <0xf 0xe0005000 0 0x1000>; - - ranges = <0x0 0x0 0xf 0xff000000 0x01000000 - 0x1 0x0 0xf 0xf8004000 0x00001000>; - - }; - - board_soc: soc: soc8548@fe0000000 { - ranges = <0 0xf 0xe0000000 0x100000>; - }; - - board_pci0: pci0: pci@fe0008000 { - reg = <0xf 0xe0008000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x10000000 - 0x1000000 0x0 0x00000000 0xf 0xe2000000 0x0 0x800000>; - clock-frequency = <66666666>; - }; - - pci1: pci@fe0009000 { - reg = <0xf 0xe0009000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xc 0x10000000 0x0 0x10000000 - 0x1000000 0x0 0x00000000 0xf 0xe2800000 0x0 0x800000>; - clock-frequency = <66666666>; - interrupt-map-mask = <0xf800 0x0 0x0 0x7>; - interrupt-map = < - - /* IDSEL 0x15 */ - 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0 - 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 - 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 - 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; - }; - - pci2: pcie@fe000a000 { - reg = <0xf 0xe000a000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xe3000000 0x0 0x100000>; - pcie@0 { - ranges = <0x2000000 0x0 0xa0000000 - 0x2000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - rio: rapidio@fe00c0000 { - reg = <0xf 0xe00c0000 0x0 0x20000>; - port1 { - ranges = <0x0 0x0 0xc 0x40000000 0x0 0x20000000>; - }; - }; -}; - -/* - * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings - * for interrupt-map & interrupt-map-mask. - */ - -/include/ "fsl/mpc8548si-post.dtsi" -/include/ "mpc8548cds.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/mpc8572ds.dtsi b/trunk/arch/powerpc/boot/dts/mpc8572ds.dtsi index 14178944e220..c3d4fac0532a 100644 --- a/trunk/arch/powerpc/boot/dts/mpc8572ds.dtsi +++ b/trunk/arch/powerpc/boot/dts/mpc8572ds.dtsi @@ -41,47 +41,37 @@ bank-width = <2>; device-width = <1>; - partition@0 { + ramdisk@0 { reg = <0x0 0x03000000>; - label = "ramdisk-nor"; + read-only; }; - partition@3000000 { + diagnostic@3000000 { reg = <0x03000000 0x00e00000>; - label = "diagnostic-nor"; read-only; }; - partition@3e00000 { + dink@3e00000 { reg = <0x03e00000 0x00200000>; - label = "dink-nor"; read-only; }; - partition@4000000 { + kernel@4000000 { reg = <0x04000000 0x00400000>; - label = "kernel-nor"; + read-only; }; - partition@4400000 { + jffs2@4400000 { reg = <0x04400000 0x03b00000>; - label = "fs-nor"; - }; - - partition@7f00000 { - reg = <0x07f00000 0x00060000>; - label = "dtb-nor"; }; - partition@7f60000 { - reg = <0x07f60000 0x00020000>; - label = "env-nor"; + dtb@7f00000 { + reg = <0x07f00000 0x00080000>; read-only; }; - partition@7f80000 { + u-boot@7f80000 { reg = <0x07f80000 0x00080000>; - label = "u-boot-nor"; read-only; }; }; @@ -93,35 +83,31 @@ "fsl,elbc-fcm-nand"; reg = <0x2 0x0 0x40000>; - partition@0 { + u-boot@0 { reg = <0x0 0x02000000>; - label = "u-boot-nand"; read-only; }; - partition@2000000 { + jffs2@2000000 { reg = <0x02000000 0x10000000>; - label = "fs-nand"; }; - partition@12000000 { + ramdisk@12000000 { reg = <0x12000000 0x08000000>; - label = "ramdisk-nand"; + read-only; }; - partition@1a000000 { + kernel@1a000000 { reg = <0x1a000000 0x04000000>; - label = "kernel-nand"; }; - partition@1e000000 { + dtb@1e000000 { reg = <0x1e000000 0x01000000>; - label = "dtb-nand"; + read-only; }; - partition@1f000000 { + empty@1f000000 { reg = <0x1f000000 0x21000000>; - label = "empty-nand"; }; }; diff --git a/trunk/arch/powerpc/boot/dts/p1010rdb.dtsi b/trunk/arch/powerpc/boot/dts/p1010rdb.dtsi index 49776143a1b8..d4c4a7730285 100644 --- a/trunk/arch/powerpc/boot/dts/p1010rdb.dtsi +++ b/trunk/arch/powerpc/boot/dts/p1010rdb.dtsi @@ -138,7 +138,7 @@ #size-cells = <1>; compatible = "spansion,s25sl12801"; reg = <0>; - spi-max-frequency = <40000000>; + spi-max-frequency = <50000000>; partition@0 { /* 1MB for u-boot Bootloader Image */ @@ -196,7 +196,7 @@ }; tbi-phy@3 { - device_type = "tbi-phy"; + device-type = "tbi-phy"; reg = <0x3>; }; }; diff --git a/trunk/arch/powerpc/boot/dts/p1020rdb-pc.dtsi b/trunk/arch/powerpc/boot/dts/p1020rdb-pc.dtsi deleted file mode 100644 index c952cd37cf6d..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1020rdb-pc.dtsi +++ /dev/null @@ -1,247 +0,0 @@ -/* - * P1020 RDB-PC Device Tree Source stub (no addresses or top-level ranges) - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -&lbc { - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x1000000>; - bank-width = <2>; - device-width = <1>; - - partition@0 { - /* This location must not be altered */ - /* 256KB for Vitesse 7385 Switch firmware */ - reg = <0x0 0x00040000>; - label = "NOR Vitesse-7385 Firmware"; - read-only; - }; - - partition@40000 { - /* 256KB for DTB Image */ - reg = <0x00040000 0x00040000>; - label = "NOR DTB Image"; - }; - - partition@80000 { - /* 3.5 MB for Linux Kernel Image */ - reg = <0x00080000 0x00380000>; - label = "NOR Linux Kernel Image"; - }; - - partition@400000 { - /* 11MB for JFFS2 based Root file System */ - reg = <0x00400000 0x00b00000>; - label = "NOR JFFS2 Root File System"; - }; - - partition@f00000 { - /* This location must not be altered */ - /* 512KB for u-boot Bootloader Image */ - /* 512KB for u-boot Environment Variables */ - reg = <0x00f00000 0x00100000>; - label = "NOR U-Boot Image"; - read-only; - }; - }; - - nand@1,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,p1020-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <0x1 0x0 0x40000>; - - partition@0 { - /* This location must not be altered */ - /* 1MB for u-boot Bootloader Image */ - reg = <0x0 0x00100000>; - label = "NAND U-Boot Image"; - read-only; - }; - - partition@100000 { - /* 1MB for DTB Image */ - reg = <0x00100000 0x00100000>; - label = "NAND DTB Image"; - }; - - partition@200000 { - /* 4MB for Linux Kernel Image */ - reg = <0x00200000 0x00400000>; - label = "NAND Linux Kernel Image"; - }; - - partition@600000 { - /* 4MB for Compressed Root file System Image */ - reg = <0x00600000 0x00400000>; - label = "NAND Compressed RFS Image"; - }; - - partition@a00000 { - /* 7MB for JFFS2 based Root file System */ - reg = <0x00a00000 0x00700000>; - label = "NAND JFFS2 Root File System"; - }; - - partition@1100000 { - /* 15MB for JFFS2 based Root file System */ - reg = <0x01100000 0x00f00000>; - label = "NAND Writable User area"; - }; - }; - - L2switch@2,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "vitesse-7385"; - reg = <0x2 0x0 0x20000>; - }; - - cpld@3,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cpld"; - reg = <0x3 0x0 0x20000>; - read-only; - }; -}; - -&soc { - i2c@3000 { - rtc@68 { - compatible = "pericom,pt7c4338"; - reg = <0x68>; - }; - }; - - spi@7000 { - flash@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "spansion,s25sl12801"; - reg = <0>; - spi-max-frequency = <40000000>; /* input clock */ - - partition@u-boot { - /* 512KB for u-boot Bootloader Image */ - reg = <0x0 0x00080000>; - label = "u-boot"; - read-only; - }; - - partition@dtb { - /* 512KB for DTB Image*/ - reg = <0x00080000 0x00080000>; - label = "dtb"; - }; - - partition@kernel { - /* 4MB for Linux Kernel Image */ - reg = <0x00100000 0x00400000>; - label = "kernel"; - }; - - partition@fs { - /* 4MB for Compressed RFS Image */ - reg = <0x00500000 0x00400000>; - label = "file system"; - }; - - partition@jffs-fs { - /* 7MB for JFFS2 based RFS */ - reg = <0x00900000 0x00700000>; - label = "file system jffs2"; - }; - }; - }; - - usb@22000 { - phy_type = "ulpi"; - }; - - /* USB2 is shared with localbus, so it must be disabled - by default. We can't put 'status = "disabled";' here - since U-Boot doesn't clear the status property when - it enables USB2. OTOH, U-Boot does create a new node - when there isn't any. So, just comment it out. - usb@23000 { - phy_type = "ulpi"; - }; - */ - - mdio@24000 { - phy0: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x0>; - }; - - phy1: ethernet-phy@1 { - interrupt-parent = <&mpic>; - interrupts = <2 1>; - reg = <0x1>; - }; - - tbi0: tbi-phy@11 { - device_type = "tbi-phy"; - reg = <0x11>; - }; - }; - - mdio@25000 { - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet0: ethernet@b0000 { - fixed-link = <1 1 1000 0 0>; - phy-connection-type = "rgmii-id"; - - }; - - enet1: ethernet@b1000 { - phy-handle = <&phy0>; - tbi-handle = <&tbi1>; - phy-connection-type = "sgmii"; - }; - - enet2: ethernet@b2000 { - phy-handle = <&phy1>; - phy-connection-type = "rgmii-id"; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts b/trunk/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts deleted file mode 100644 index 4de69b726dc5..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * P1020 RDB-PC Device Tree Source (32-bit address map) - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p1020si-pre.dtsi" -/ { - model = "fsl,P1020RDB-PC"; - compatible = "fsl,P1020RDB-PC"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@ffe05000 { - reg = <0 0xffe05000 0 0x1000>; - - /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ - ranges = <0x0 0x0 0x0 0xef000000 0x01000000 - 0x1 0x0 0x0 0xff800000 0x00040000 - 0x2 0x0 0x0 0xffb00000 0x00020000 - 0x3 0x0 0x0 0xffa00000 0x00020000>; - }; - - soc: soc@ffe00000 { - ranges = <0x0 0x0 0xffe00000 0x100000>; - }; - - pci0: pcie@ffe09000 { - ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - reg = <0 0xffe09000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xa0000000 - 0x2000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@ffe0a000 { - reg = <0 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0x80000000 - 0x2000000 0x0 0x80000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "p1020rdb-pc.dtsi" -/include/ "fsl/p1020si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts b/trunk/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts deleted file mode 100644 index 5237da7441bc..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts +++ /dev/null @@ -1,90 +0,0 @@ -/* - * P1020 RDB-PC Device Tree Source (36-bit address map) - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p1020si-pre.dtsi" -/ { - model = "fsl,P1020RDB-PC"; - compatible = "fsl,P1020RDB-PC"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@fffe05000 { - reg = <0xf 0xffe05000 0 0x1000>; - - /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ - ranges = <0x0 0x0 0xf 0xef000000 0x01000000 - 0x1 0x0 0xf 0xff800000 0x00040000 - 0x2 0x0 0xf 0xffb00000 0x00040000 - 0x3 0x0 0xf 0xffa00000 0x00020000>; - }; - - soc: soc@fffe00000 { - ranges = <0x0 0xf 0xffe00000 0x100000>; - }; - - pci0: pcie@fffe09000 { - reg = <0xf 0xffe09000 0 0x1000>; - ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xc0000000 - 0x2000000 0x0 0xc0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@fffe0a000 { - reg = <0xf 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0x80000000 - 0x2000000 0x0 0x80000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "p1020rdb-pc.dtsi" -/include/ "fsl/p1020si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts b/trunk/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts deleted file mode 100644 index f411515937ec..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts +++ /dev/null @@ -1,64 +0,0 @@ -/* - * P1020 RDB-PC Core0 Device Tree Source in CAMP mode. - * - * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache - * can be shared, all the other devices must be assigned to one core only. - * This dts file allows core0 to have memory, l2, i2c, spi, gpio, tdm, dma, usb, - * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi. - * - * Please note to add "-b 0" for core0's dts compiling. - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/include/ "p1020rdb-pc_32b.dts" - -/ { - model = "fsl,P1020RDB-PC"; - compatible = "fsl,P1020RDB-PC"; - - aliases { - ethernet1 = &enet1; - ethernet2 = &enet2; - serial0 = &serial0; - pci0 = &pci0; - pci1 = &pci1; - }; - - cpus { - PowerPC,P1020@1 { - status = "disabled"; - }; - }; - - memory { - device_type = "memory"; - }; - - localbus@ffe05000 { - status = "disabled"; - }; - - soc@ffe00000 { - serial1: serial@4600 { - status = "disabled"; - }; - - enet0: ethernet@b0000 { - status = "disabled"; - }; - - mpic: pic@40000 { - protected-sources = < - 42 29 30 34 /* serial1, enet0-queue-group0 */ - 17 18 24 45 /* enet0-queue-group1, crypto */ - >; - pic-no-reset; - }; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts b/trunk/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts deleted file mode 100644 index a91335ad82c2..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts +++ /dev/null @@ -1,142 +0,0 @@ -/* - * P1020 RDB-PC Core1 Device Tree Source in CAMP mode. - * - * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache - * can be shared, all the other devices must be assigned to one core only. - * This dts allows core1 to have l2, eth0, crypto. - * - * Please note to add "-b 1" for core1's dts compiling. - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -/include/ "p1020rdb-pc_32b.dts" - -/ { - model = "fsl,P1020RDB-PC"; - compatible = "fsl,P1020RDB-PC"; - - aliases { - ethernet0 = &enet0; - serial0 = &serial1; - }; - - cpus { - PowerPC,P1020@0 { - status = "disabled"; - }; - }; - - memory { - device_type = "memory"; - }; - - localbus@ffe05000 { - status = "disabled"; - }; - - soc@ffe00000 { - ecm-law@0 { - status = "disabled"; - }; - - ecm@1000 { - status = "disabled"; - }; - - memory-controller@2000 { - status = "disabled"; - }; - - i2c@3000 { - status = "disabled"; - }; - - i2c@3100 { - status = "disabled"; - }; - - serial0: serial@4500 { - status = "disabled"; - }; - - spi@7000 { - status = "disabled"; - }; - - gpio: gpio-controller@f000 { - status = "disabled"; - }; - - dma@21300 { - status = "disabled"; - }; - - mdio@24000 { - status = "disabled"; - }; - - mdio@25000 { - status = "disabled"; - }; - - enet1: ethernet@b1000 { - status = "disabled"; - }; - - enet2: ethernet@b2000 { - status = "disabled"; - }; - - usb@22000 { - status = "disabled"; - }; - - sdhci@2e000 { - status = "disabled"; - }; - - mpic: pic@40000 { - protected-sources = < - 16 /* ecm, mem, L2, pci0, pci1 */ - 43 42 59 /* i2c, serial0, spi */ - 47 63 62 /* gpio, tdm */ - 20 21 22 23 /* dma */ - 03 02 /* mdio */ - 35 36 40 /* enet1-queue-group0 */ - 51 52 67 /* enet1-queue-group1 */ - 31 32 33 /* enet2-queue-group0 */ - 25 26 27 /* enet2-queue-group1 */ - 28 72 58 /* usb, sdhci, crypto */ - 0xb0 0xb1 0xb2 /* message */ - 0xb3 0xb4 0xb5 - 0xb6 0xb7 - 0xe0 0xe1 0xe2 /* msi */ - 0xe3 0xe4 0xe5 - 0xe6 0xe7 /* sdhci, crypto , pci */ - >; - pic-no-reset; - }; - - msi@41600 { - status = "disabled"; - }; - - global-utilities@e0000 { //global utilities block - status = "disabled"; - }; - }; - - pci0: pcie@ffe09000 { - status = "disabled"; - }; - - pci1: pcie@ffe0a000 { - status = "disabled"; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/p1021rdb.dts b/trunk/arch/powerpc/boot/dts/p1021rdb.dts deleted file mode 100644 index 90b6b4caa273..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1021rdb.dts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * P1021 RDB Device Tree Source - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p1021si-pre.dtsi" -/ { - model = "fsl,P1021RDB"; - compatible = "fsl,P1021RDB-PC"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@ffe05000 { - reg = <0 0xffe05000 0 0x1000>; - - /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ - ranges = <0x0 0x0 0x0 0xef000000 0x01000000 - 0x1 0x0 0x0 0xff800000 0x00040000 - 0x2 0x0 0x0 0xffb00000 0x00020000>; - }; - - soc: soc@ffe00000 { - ranges = <0x0 0x0 0xffe00000 0x100000>; - }; - - pci0: pcie@ffe09000 { - ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - reg = <0 0xffe09000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xa0000000 - 0x2000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@ffe0a000 { - reg = <0 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0x80000000 - 0x2000000 0x0 0x80000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - qe: qe@ffe80000 { - ranges = <0x0 0x0 0xffe80000 0x40000>; - reg = <0 0xffe80000 0 0x480>; - brg-frequency = <0>; - bus-frequency = <0>; - }; -}; - -/include/ "p1021rdb.dtsi" -/include/ "fsl/p1021si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p1021rdb.dtsi b/trunk/arch/powerpc/boot/dts/p1021rdb.dtsi deleted file mode 100644 index b973461ab751..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1021rdb.dtsi +++ /dev/null @@ -1,236 +0,0 @@ -/* - * P1021 RDB Device Tree Source stub (no addresses or top-level ranges) - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -&lbc { - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x1000000>; - bank-width = <2>; - device-width = <1>; - - partition@0 { - /* This location must not be altered */ - /* 256KB for Vitesse 7385 Switch firmware */ - reg = <0x0 0x00040000>; - label = "NOR Vitesse-7385 Firmware"; - read-only; - }; - - partition@40000 { - /* 256KB for DTB Image */ - reg = <0x00040000 0x00040000>; - label = "NOR DTB Image"; - }; - - partition@80000 { - /* 3.5 MB for Linux Kernel Image */ - reg = <0x00080000 0x00380000>; - label = "NOR Linux Kernel Image"; - }; - - partition@400000 { - /* 11MB for JFFS2 based Root file System */ - reg = <0x00400000 0x00b00000>; - label = "NOR JFFS2 Root File System"; - }; - - partition@f00000 { - /* This location must not be altered */ - /* 512KB for u-boot Bootloader Image */ - /* 512KB for u-boot Environment Variables */ - reg = <0x00f00000 0x00100000>; - label = "NOR U-Boot Image"; - }; - }; - - nand@1,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,p1021-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <0x1 0x0 0x40000>; - - partition@0 { - /* This location must not be altered */ - /* 1MB for u-boot Bootloader Image */ - reg = <0x0 0x00100000>; - label = "NAND U-Boot Image"; - read-only; - }; - - partition@100000 { - /* 1MB for DTB Image */ - reg = <0x00100000 0x00100000>; - label = "NAND DTB Image"; - }; - - partition@200000 { - /* 4MB for Linux Kernel Image */ - reg = <0x00200000 0x00400000>; - label = "NAND Linux Kernel Image"; - }; - - partition@600000 { - /* 4MB for Compressed Root file System Image */ - reg = <0x00600000 0x00400000>; - label = "NAND Compressed RFS Image"; - }; - - partition@a00000 { - /* 7MB for JFFS2 based Root file System */ - reg = <0x00a00000 0x00700000>; - label = "NAND JFFS2 Root File System"; - }; - - partition@1100000 { - /* 15MB for User Writable Area */ - reg = <0x01100000 0x00f00000>; - label = "NAND Writable User area"; - }; - }; - - L2switch@2,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "vitesse-7385"; - reg = <0x2 0x0 0x20000>; - }; -}; - -&soc { - i2c@3000 { - rtc@68 { - compatible = "pericom,pt7c4338"; - reg = <0x68>; - }; - }; - - spi@7000 { - flash@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "spansion,s25sl12801"; - reg = <0>; - spi-max-frequency = <40000000>; /* input clock */ - - partition@u-boot { - /* 512KB for u-boot Bootloader Image */ - reg = <0x0 0x00080000>; - label = "SPI Flash U-Boot Image"; - read-only; - }; - - partition@dtb { - /* 512KB for DTB Image */ - reg = <0x00080000 0x00080000>; - label = "SPI Flash DTB Image"; - }; - - partition@kernel { - /* 4MB for Linux Kernel Image */ - reg = <0x00100000 0x00400000>; - label = "SPI Flash Linux Kernel Image"; - }; - - partition@fs { - /* 4MB for Compressed RFS Image */ - reg = <0x00500000 0x00400000>; - label = "SPI Flash Compressed RFSImage"; - }; - - partition@jffs-fs { - /* 7MB for JFFS2 based RFS */ - reg = <0x00900000 0x00700000>; - label = "SPI Flash JFFS2 RFS"; - }; - }; - }; - - usb@22000 { - phy_type = "ulpi"; - }; - - mdio@24000 { - phy0: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <3 1 0 0>; - reg = <0x0>; - }; - - phy1: ethernet-phy@1 { - interrupt-parent = <&mpic>; - interrupts = <2 1 0 0>; - reg = <0x1>; - }; - - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - mdio@25000 { - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - mdio@26000 { - tbi2: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet0: ethernet@b0000 { - fixed-link = <1 1 1000 0 0>; - phy-connection-type = "rgmii-id"; - - }; - - enet1: ethernet@b1000 { - phy-handle = <&phy0>; - tbi-handle = <&tbi1>; - phy-connection-type = "sgmii"; - }; - - enet2: ethernet@b2000 { - phy-handle = <&phy1>; - tbi-handle = <&tbi2>; - phy-connection-type = "rgmii-id"; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/p1021rdb_36b.dts b/trunk/arch/powerpc/boot/dts/p1021rdb_36b.dts deleted file mode 100644 index ea6d8b5fa10b..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1021rdb_36b.dts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * P1021 RDB Device Tree Source (36-bit address map) - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p1021si-pre.dtsi" -/ { - model = "fsl,P1021RDB"; - compatible = "fsl,P1021RDB-PC"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@fffe05000 { - reg = <0xf 0xffe05000 0 0x1000>; - - /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ - ranges = <0x0 0x0 0xf 0xef000000 0x01000000 - 0x1 0x0 0xf 0xff800000 0x00040000 - 0x2 0x0 0xf 0xffb00000 0x00020000>; - }; - - soc: soc@fffe00000 { - ranges = <0x0 0xf 0xffe00000 0x100000>; - }; - - pci0: pcie@fffe09000 { - ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - reg = <0xf 0xffe09000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xa0000000 - 0x2000000 0x0 0xa0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@fffe0a000 { - reg = <0xf 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xc0000000 - 0x2000000 0x0 0xc0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - qe: qe@fffe80000 { - ranges = <0x0 0xf 0xffe80000 0x40000>; - reg = <0xf 0xffe80000 0 0x480>; - brg-frequency = <0>; - bus-frequency = <0>; - }; -}; - -/include/ "p1021rdb.dtsi" -/include/ "fsl/p1021si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p1022ds.dts b/trunk/arch/powerpc/boot/dts/p1022ds.dts new file mode 100644 index 000000000000..ef95717db4bc --- /dev/null +++ b/trunk/arch/powerpc/boot/dts/p1022ds.dts @@ -0,0 +1,274 @@ +/* + * P1022 DS 36Bit Physical Address Map Device Tree Source + * + * Copyright 2010 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +/include/ "fsl/p1022si-pre.dtsi" +/ { + model = "fsl,P1022DS"; + compatible = "fsl,P1022DS"; + + memory { + device_type = "memory"; + }; + + lbc: localbus@fffe05000 { + reg = <0xf 0xffe05000 0 0x1000>; + ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 + 0x1 0x0 0xf 0xe0000000 0x08000000 + 0x2 0x0 0xf 0xff800000 0x00040000 + 0x3 0x0 0xf 0xffdf0000 0x00008000>; + + /* + * This node is used to access the pixis via "indirect" mode, + * which is done by writing the pixis register index to chip + * select 0 and the value to/from chip select 1. Indirect + * mode is the only way to access the pixis when DIU video + * is enabled. Note that this assumes that the first column + * of the 'ranges' property above is the chip select number. + */ + board-control@0,0 { + compatible = "fsl,p1022ds-indirect-pixis"; + reg = <0x0 0x0 1 /* CS0 */ + 0x1 0x0 1>; /* CS1 */ + }; + + nor@0,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "cfi-flash"; + reg = <0x0 0x0 0x8000000>; + bank-width = <2>; + device-width = <1>; + + partition@0 { + reg = <0x0 0x03000000>; + label = "ramdisk-nor"; + read-only; + }; + + partition@3000000 { + reg = <0x03000000 0x00e00000>; + label = "diagnostic-nor"; + read-only; + }; + + partition@3e00000 { + reg = <0x03e00000 0x00200000>; + label = "dink-nor"; + read-only; + }; + + partition@4000000 { + reg = <0x04000000 0x00400000>; + label = "kernel-nor"; + read-only; + }; + + partition@4400000 { + reg = <0x04400000 0x03b00000>; + label = "jffs2-nor"; + }; + + partition@7f00000 { + reg = <0x07f00000 0x00080000>; + label = "dtb-nor"; + read-only; + }; + + partition@7f80000 { + reg = <0x07f80000 0x00080000>; + label = "u-boot-nor"; + read-only; + }; + }; + + nand@2,0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "fsl,elbc-fcm-nand"; + reg = <0x2 0x0 0x40000>; + + partition@0 { + reg = <0x0 0x02000000>; + label = "u-boot-nand"; + read-only; + }; + + partition@2000000 { + reg = <0x02000000 0x10000000>; + label = "jffs2-nand"; + }; + + partition@12000000 { + reg = <0x12000000 0x10000000>; + label = "ramdisk-nand"; + read-only; + }; + + partition@22000000 { + reg = <0x22000000 0x04000000>; + label = "kernel-nand"; + }; + + partition@26000000 { + reg = <0x26000000 0x01000000>; + label = "dtb-nand"; + read-only; + }; + + partition@27000000 { + reg = <0x27000000 0x19000000>; + label = "reserved-nand"; + }; + }; + + board-control@3,0 { + compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis"; + reg = <3 0 0x30>; + interrupt-parent = <&mpic>; + /* + * IRQ8 is generated if the "EVENT" switch is pressed + * and PX_CTL[EVESEL] is set to 00. + */ + interrupts = <8 8 0 0>; + }; + }; + + soc: soc@fffe00000 { + ranges = <0x0 0xf 0xffe00000 0x100000>; + + i2c@3100 { + wm8776:codec@1a { + compatible = "wlf,wm8776"; + reg = <0x1a>; + /* + * clock-frequency will be set by U-Boot if + * the clock is enabled. + */ + }; + }; + + spi@7000 { + flash@0 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "spansion,s25sl12801"; + reg = <0>; + spi-max-frequency = <40000000>; /* input clock */ + + partition@0 { + label = "u-boot-spi"; + reg = <0x00000000 0x00100000>; + read-only; + }; + partition@100000 { + label = "kernel-spi"; + reg = <0x00100000 0x00500000>; + read-only; + }; + partition@600000 { + label = "dtb-spi"; + reg = <0x00600000 0x00100000>; + read-only; + }; + partition@700000 { + label = "file system-spi"; + reg = <0x00700000 0x00900000>; + }; + }; + }; + + ssi@15000 { + fsl,mode = "i2s-slave"; + codec-handle = <&wm8776>; + fsl,ssi-asynchronous; + }; + + usb@22000 { + phy_type = "ulpi"; + }; + + usb@23000 { + status = "disabled"; + }; + + mdio@24000 { + phy0: ethernet-phy@0 { + interrupts = <3 1 0 0>; + reg = <0x1>; + }; + phy1: ethernet-phy@1 { + interrupts = <9 1 0 0>; + reg = <0x2>; + }; + tbi-phy@2 { + device_type = "tbi-phy"; + reg = <0x2>; + }; + }; + + ethernet@b0000 { + phy-handle = <&phy0>; + phy-connection-type = "rgmii-id"; + }; + + ethernet@b1000 { + phy-handle = <&phy1>; + phy-connection-type = "rgmii-id"; + }; + }; + + pci0: pcie@fffe09000 { + reg = <0xf 0xffe09000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci1: pcie@fffe0a000 { + reg = <0xf 0xffe0a000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>; + pcie@0 { + reg = <0x0 0x0 0x0 0x0 0x0>; + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; + + pci2: pcie@fffe0b000 { + reg = <0xf 0xffe0b000 0 0x1000>; + ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 + 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; + pcie@0 { + ranges = <0x2000000 0x0 0xe0000000 + 0x2000000 0x0 0xe0000000 + 0x0 0x20000000 + + 0x1000000 0x0 0x0 + 0x1000000 0x0 0x0 + 0x0 0x100000>; + }; + }; +}; + +/include/ "fsl/p1022si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p1022ds.dtsi b/trunk/arch/powerpc/boot/dts/p1022ds.dtsi deleted file mode 100644 index 7cdb505036bb..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1022ds.dtsi +++ /dev/null @@ -1,234 +0,0 @@ -/* - * P1022 DS Device Tree Source stub (no addresses or top-level ranges) - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -&board_lbc { - /* - * This node is used to access the pixis via "indirect" mode, - * which is done by writing the pixis register index to chip - * select 0 and the value to/from chip select 1. Indirect - * mode is the only way to access the pixis when DIU video - * is enabled. Note that this assumes that the first column - * of the 'ranges' property above is the chip select number. - */ - board-control@0,0 { - compatible = "fsl,p1022ds-indirect-pixis"; - reg = <0x0 0x0 1 /* CS0 */ - 0x1 0x0 1>; /* CS1 */ - interrupt-parent = <&mpic>; - interrupts = <8 0 0 0>; - }; - - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x8000000>; - bank-width = <2>; - device-width = <1>; - - partition@0 { - reg = <0x0 0x03000000>; - label = "ramdisk-nor"; - read-only; - }; - - partition@3000000 { - reg = <0x03000000 0x00e00000>; - label = "diagnostic-nor"; - read-only; - }; - - partition@3e00000 { - reg = <0x03e00000 0x00200000>; - label = "dink-nor"; - read-only; - }; - - partition@4000000 { - reg = <0x04000000 0x00400000>; - label = "kernel-nor"; - read-only; - }; - - partition@4400000 { - reg = <0x04400000 0x03b00000>; - label = "jffs2-nor"; - }; - - partition@7f00000 { - reg = <0x07f00000 0x00080000>; - label = "dtb-nor"; - read-only; - }; - - partition@7f80000 { - reg = <0x07f80000 0x00080000>; - label = "u-boot-nor"; - read-only; - }; - }; - - nand@2,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,elbc-fcm-nand"; - reg = <0x2 0x0 0x40000>; - - partition@0 { - reg = <0x0 0x02000000>; - label = "u-boot-nand"; - read-only; - }; - - partition@2000000 { - reg = <0x02000000 0x10000000>; - label = "jffs2-nand"; - }; - - partition@12000000 { - reg = <0x12000000 0x10000000>; - label = "ramdisk-nand"; - read-only; - }; - - partition@22000000 { - reg = <0x22000000 0x04000000>; - label = "kernel-nand"; - }; - - partition@26000000 { - reg = <0x26000000 0x01000000>; - label = "dtb-nand"; - read-only; - }; - - partition@27000000 { - reg = <0x27000000 0x19000000>; - label = "reserved-nand"; - }; - }; - - board-control@3,0 { - compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis"; - reg = <3 0 0x30>; - interrupt-parent = <&mpic>; - /* - * IRQ8 is generated if the "EVENT" switch is pressed - * and PX_CTL[EVESEL] is set to 00. - */ - interrupts = <8 0 0 0>; - }; -}; - -&board_soc { - i2c@3100 { - wm8776:codec@1a { - compatible = "wlf,wm8776"; - reg = <0x1a>; - /* - * clock-frequency will be set by U-Boot if - * the clock is enabled. - */ - }; - }; - - spi@7000 { - flash@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "spansion,s25sl12801"; - reg = <0>; - spi-max-frequency = <40000000>; /* input clock */ - - partition@0 { - label = "u-boot-spi"; - reg = <0x00000000 0x00100000>; - read-only; - }; - partition@100000 { - label = "kernel-spi"; - reg = <0x00100000 0x00500000>; - read-only; - }; - partition@600000 { - label = "dtb-spi"; - reg = <0x00600000 0x00100000>; - read-only; - }; - partition@700000 { - label = "file system-spi"; - reg = <0x00700000 0x00900000>; - }; - }; - }; - - ssi@15000 { - fsl,mode = "i2s-slave"; - codec-handle = <&wm8776>; - fsl,ssi-asynchronous; - }; - - usb@22000 { - phy_type = "ulpi"; - }; - - usb@23000 { - status = "disabled"; - }; - - mdio@24000 { - phy0: ethernet-phy@0 { - interrupts = <3 1 0 0>; - reg = <0x1>; - }; - phy1: ethernet-phy@1 { - interrupts = <9 1 0 0>; - reg = <0x2>; - }; - tbi-phy@2 { - device_type = "tbi-phy"; - reg = <0x2>; - }; - }; - - ethernet@b0000 { - phy-handle = <&phy0>; - phy-connection-type = "rgmii-id"; - }; - - ethernet@b1000 { - phy-handle = <&phy1>; - phy-connection-type = "rgmii-id"; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/p1022ds_32b.dts b/trunk/arch/powerpc/boot/dts/p1022ds_32b.dts deleted file mode 100644 index d96cae00a9e3..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1022ds_32b.dts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * P1022 DS 32-bit Physical Address Map Device Tree Source - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p1022si-pre.dtsi" -/ { - model = "fsl,P1022DS"; - compatible = "fsl,P1022DS"; - - memory { - device_type = "memory"; - }; - - board_lbc: lbc: localbus@ffe05000 { - ranges = <0x0 0x0 0x0 0xe8000000 0x08000000 - 0x1 0x0 0x0 0xe0000000 0x08000000 - 0x2 0x0 0x0 0xff800000 0x00040000 - 0x3 0x0 0x0 0xffdf0000 0x00008000>; - reg = <0x0 0xffe05000 0 0x1000>; - }; - - board_soc: soc: soc@ffe00000 { - ranges = <0x0 0x0 0xffe00000 0x100000>; - }; - - pci0: pcie@ffe09000 { - ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - reg = <0x0 0xffe09000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@ffe0a000 { - ranges = <0x2000000 0x0 0xe0000000 0 0xc0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; - reg = <0 0xffe0a000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci2: pcie@ffe0b000 { - ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - reg = <0 0xffe0b000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "fsl/p1022si-post.dtsi" -/include/ "p1022ds.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p1022ds_36b.dts b/trunk/arch/powerpc/boot/dts/p1022ds_36b.dts deleted file mode 100644 index f7aacce40bf6..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1022ds_36b.dts +++ /dev/null @@ -1,103 +0,0 @@ -/* - * P1022 DS 36-bit Physical Address Map Device Tree Source - * - * Copyright 2012 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p1022si-pre.dtsi" -/ { - model = "fsl,P1022DS"; - compatible = "fsl,P1022DS"; - - memory { - device_type = "memory"; - }; - - board_lbc: lbc: localbus@fffe05000 { - ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 - 0x1 0x0 0xf 0xe0000000 0x08000000 - 0x2 0x0 0xf 0xff800000 0x00040000 - 0x3 0x0 0xf 0xffdf0000 0x00008000>; - reg = <0xf 0xffe05000 0 0x1000>; - }; - - board_soc: soc: soc@fffe00000 { - ranges = <0x0 0xf 0xffe00000 0x100000>; - }; - - pci0: pcie@fffe09000 { - ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - reg = <0xf 0xffe09000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@fffe0a000 { - ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>; - reg = <0xf 0xffe0a000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci2: pcie@fffe0b000 { - ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; - reg = <0xf 0xffe0b000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "fsl/p1022si-post.dtsi" -/include/ "p1022ds.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p1025rdb.dtsi b/trunk/arch/powerpc/boot/dts/p1025rdb.dtsi deleted file mode 100644 index cf3676fc714b..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1025rdb.dtsi +++ /dev/null @@ -1,286 +0,0 @@ -/* - * P1025 RDB Device Tree Source stub (no addresses or top-level ranges) - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -&lbc { - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x1000000>; - bank-width = <2>; - device-width = <1>; - - partition@0 { - /* This location must not be altered */ - /* 256KB for Vitesse 7385 Switch firmware */ - reg = <0x0 0x00040000>; - label = "NOR Vitesse-7385 Firmware"; - read-only; - }; - - partition@40000 { - /* 256KB for DTB Image */ - reg = <0x00040000 0x00040000>; - label = "NOR DTB Image"; - }; - - partition@80000 { - /* 3.5 MB for Linux Kernel Image */ - reg = <0x00080000 0x00380000>; - label = "NOR Linux Kernel Image"; - }; - - partition@400000 { - /* 11MB for JFFS2 based Root file System */ - reg = <0x00400000 0x00b00000>; - label = "NOR JFFS2 Root File System"; - }; - - partition@f00000 { - /* This location must not be altered */ - /* 512KB for u-boot Bootloader Image */ - /* 512KB for u-boot Environment Variables */ - reg = <0x00f00000 0x00100000>; - label = "NOR U-Boot Image"; - read-only; - }; - }; - - nand@1,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,p1025-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <0x1 0x0 0x40000>; - - partition@0 { - /* This location must not be altered */ - /* 1MB for u-boot Bootloader Image */ - reg = <0x0 0x00100000>; - label = "NAND U-Boot Image"; - read-only; - }; - - partition@100000 { - /* 1MB for DTB Image */ - reg = <0x00100000 0x00100000>; - label = "NAND DTB Image"; - }; - - partition@200000 { - /* 4MB for Linux Kernel Image */ - reg = <0x00200000 0x00400000>; - label = "NAND Linux Kernel Image"; - }; - - partition@600000 { - /* 4MB for Compressed Root file System Image */ - reg = <0x00600000 0x00400000>; - label = "NAND Compressed RFS Image"; - }; - - partition@a00000 { - /* 7MB for JFFS2 based Root file System */ - reg = <0x00a00000 0x00700000>; - label = "NAND JFFS2 Root File System"; - }; - - partition@1100000 { - /* 15MB for JFFS2 based Root file System */ - reg = <0x01100000 0x00f00000>; - label = "NAND Writable User area"; - }; - }; - -}; - -&soc { - i2c@3000 { - rtc@68 { - compatible = "dallas,ds1339"; - reg = <0x68>; - }; - }; - - spi@7000 { - flash@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "spansion,s25sl12801"; - reg = <0>; - spi-max-frequency = <40000000>; /* input clock */ - - partition@u-boot { - /* 512KB for u-boot Bootloader Image */ - reg = <0x0 0x00080000>; - label = "u-boot"; - read-only; - }; - - partition@dtb { - /* 512KB for DTB Image */ - reg = <0x00080000 0x00080000>; - label = "dtb"; - }; - - partition@kernel { - /* 4MB for Linux Kernel Image */ - reg = <0x00100000 0x00400000>; - label = "kernel"; - }; - - partition@fs { - /* 4MB for Compressed RFS Image */ - reg = <0x00500000 0x00400000>; - label = "file system"; - }; - - partition@jffs-fs { - /* 7MB for JFFS2 based RFS */ - reg = <0x00900000 0x00700000>; - label = "file system jffs2"; - }; - }; - }; - - usb@22000 { - phy_type = "ulpi"; - }; - - /* USB2 is shared with localbus, so it must be disabled - by default. We can't put 'status = "disabled";' here - since U-Boot doesn't clear the status property when - it enables USB2. OTOH, U-Boot does create a new node - when there isn't any. So, just comment it out. - usb@23000 { - phy_type = "ulpi"; - }; - */ - - mdio@24000 { - phy0: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <3 1>; - reg = <0x0>; - }; - - phy1: ethernet-phy@1 { - interrupt-parent = <&mpic>; - interrupts = <2 1>; - reg = <0x1>; - }; - - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - mdio@25000 { - tbi1: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - mdio@26000 { - tbi2: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet0: ethernet@b0000 { - fixed-link = <1 1 1000 0 0>; - phy-connection-type = "rgmii-id"; - - }; - - enet1: ethernet@b1000 { - phy-handle = <&phy0>; - tbi-handle = <&tbi1>; - phy-connection-type = "sgmii"; - }; - - enet2: ethernet@b2000 { - phy-handle = <&phy1>; - phy-connection-type = "rgmii-id"; - }; - - par_io@e0100 { - #address-cells = <1>; - #size-cells = <1>; - reg = <0xe0100 0x60>; - ranges = <0x0 0xe0100 0x60>; - device_type = "par_io"; - num-ports = <3>; - pio1: ucc_pin@01 { - pio-map = < - /* port pin dir open_drain assignment has_irq */ - 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ - 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ - 0x0 0x17 0x2 0x0 0x2 0x0 /* CLK12 */ - 0x0 0x18 0x2 0x0 0x1 0x0 /* CLK9 */ - 0x0 0x7 0x1 0x0 0x2 0x0 /* ENET1_TXD0_SER1_TXD0 */ - 0x0 0x9 0x1 0x0 0x2 0x0 /* ENET1_TXD1_SER1_TXD1 */ - 0x0 0xb 0x1 0x0 0x2 0x0 /* ENET1_TXD2_SER1_TXD2 */ - 0x0 0xc 0x1 0x0 0x2 0x0 /* ENET1_TXD3_SER1_TXD3 */ - 0x0 0x6 0x2 0x0 0x2 0x0 /* ENET1_RXD0_SER1_RXD0 */ - 0x0 0xa 0x2 0x0 0x2 0x0 /* ENET1_RXD1_SER1_RXD1 */ - 0x0 0xe 0x2 0x0 0x2 0x0 /* ENET1_RXD2_SER1_RXD2 */ - 0x0 0xf 0x2 0x0 0x2 0x0 /* ENET1_RXD3_SER1_RXD3 */ - 0x0 0x5 0x1 0x0 0x2 0x0 /* ENET1_TX_EN_SER1_RTS_B */ - 0x0 0xd 0x1 0x0 0x2 0x0 /* ENET1_TX_ER */ - 0x0 0x4 0x2 0x0 0x2 0x0 /* ENET1_RX_DV_SER1_CTS_B */ - 0x0 0x8 0x2 0x0 0x2 0x0 /* ENET1_RX_ER_SER1_CD_B */ - 0x0 0x11 0x2 0x0 0x2 0x0 /* ENET1_CRS */ - 0x0 0x10 0x2 0x0 0x2 0x0>; /* ENET1_COL */ - }; - - pio2: ucc_pin@02 { - pio-map = < - /* port pin dir open_drain assignment has_irq */ - 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ - 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ - 0x1 0xb 0x2 0x0 0x1 0x0 /* CLK13 */ - 0x1 0x7 0x1 0x0 0x2 0x0 /* ENET5_TXD0_SER5_TXD0 */ - 0x1 0xa 0x1 0x0 0x2 0x0 /* ENET5_TXD1_SER5_TXD1 */ - 0x1 0x6 0x2 0x0 0x2 0x0 /* ENET5_RXD0_SER5_RXD0 */ - 0x1 0x9 0x2 0x0 0x2 0x0 /* ENET5_RXD1_SER5_RXD1 */ - 0x1 0x5 0x1 0x0 0x2 0x0 /* ENET5_TX_EN_SER5_RTS_B */ - 0x1 0x4 0x2 0x0 0x2 0x0 /* ENET5_RX_DV_SER5_CTS_B */ - 0x1 0x8 0x2 0x0 0x2 0x0>; /* ENET5_RX_ER_SER5_CD_B */ - }; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/p1025rdb_32b.dts b/trunk/arch/powerpc/boot/dts/p1025rdb_32b.dts deleted file mode 100644 index ac5729c14eda..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1025rdb_32b.dts +++ /dev/null @@ -1,135 +0,0 @@ -/* - * P1025 RDB Device Tree Source (32-bit address map) - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p1021si-pre.dtsi" -/ { - model = "fsl,P1025RDB"; - compatible = "fsl,P1025RDB"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@ffe05000 { - reg = <0 0xffe05000 0 0x1000>; - - /* NOR, NAND Flashes */ - ranges = <0x0 0x0 0x0 0xef000000 0x01000000 - 0x1 0x0 0x0 0xff800000 0x00040000>; - }; - - soc: soc@ffe00000 { - ranges = <0x0 0x0 0xffe00000 0x100000>; - }; - - pci0: pcie@ffe09000 { - ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - reg = <0 0xffe09000 0 0x1000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@ffe0a000 { - reg = <0 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - qe: qe@ffe80000 { - ranges = <0x0 0x0 0xffe80000 0x40000>; - reg = <0 0xffe80000 0 0x480>; - brg-frequency = <0>; - bus-frequency = <0>; - status = "disabled"; /* no firmware loaded */ - - enet3: ucc@2000 { - device_type = "network"; - compatible = "ucc_geth"; - rx-clock-name = "clk12"; - tx-clock-name = "clk9"; - pio-handle = <&pio1>; - phy-handle = <&qe_phy0>; - phy-connection-type = "mii"; - }; - - mdio@2120 { - qe_phy0: ethernet-phy@0 { - interrupt-parent = <&mpic>; - interrupts = <4 1 0 0>; - reg = <0x6>; - device_type = "ethernet-phy"; - }; - qe_phy1: ethernet-phy@03 { - interrupt-parent = <&mpic>; - interrupts = <5 1 0 0>; - reg = <0x3>; - device_type = "ethernet-phy"; - }; - tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - enet4: ucc@2400 { - device_type = "network"; - compatible = "ucc_geth"; - rx-clock-name = "none"; - tx-clock-name = "clk13"; - pio-handle = <&pio2>; - phy-handle = <&qe_phy1>; - phy-connection-type = "rmii"; - }; - }; -}; - -/include/ "p1025rdb.dtsi" -/include/ "fsl/p1021si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p1025rdb_36b.dts b/trunk/arch/powerpc/boot/dts/p1025rdb_36b.dts deleted file mode 100644 index 4ce4bfa0eda4..000000000000 --- a/trunk/arch/powerpc/boot/dts/p1025rdb_36b.dts +++ /dev/null @@ -1,88 +0,0 @@ -/* - * P1025 RDB Device Tree Source (36-bit address map) - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p1021si-pre.dtsi" -/ { - model = "fsl,P1025RDB"; - compatible = "fsl,P1025RDB"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@fffe05000 { - reg = <0xf 0xffe05000 0 0x1000>; - - /* NOR, NAND Flashes */ - ranges = <0x0 0x0 0xf 0xef000000 0x01000000 - 0x1 0x0 0xf 0xff800000 0x00040000>; - }; - - soc: soc@fffe00000 { - ranges = <0x0 0xf 0xffe00000 0x100000>; - }; - - pci0: pcie@fffe09000 { - reg = <0xf 0xffe09000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xe 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci1: pcie@fffe0a000 { - reg = <0xf 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "p1025rdb.dtsi" -/include/ "fsl/p1021si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p2020rdb-pc.dtsi b/trunk/arch/powerpc/boot/dts/p2020rdb-pc.dtsi deleted file mode 100644 index c21d1c7d16cd..000000000000 --- a/trunk/arch/powerpc/boot/dts/p2020rdb-pc.dtsi +++ /dev/null @@ -1,241 +0,0 @@ -/* - * P2020 RDB-PC Device Tree Source stub (no addresses or top-level ranges) - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -&lbc { - nor@0,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cfi-flash"; - reg = <0x0 0x0 0x1000000>; - bank-width = <2>; - device-width = <1>; - - partition@0 { - /* This location must not be altered */ - /* 256KB for Vitesse 7385 Switch firmware */ - reg = <0x0 0x00040000>; - label = "NOR Vitesse-7385 Firmware"; - read-only; - }; - - partition@40000 { - /* 256KB for DTB Image */ - reg = <0x00040000 0x00040000>; - label = "NOR DTB Image"; - }; - - partition@80000 { - /* 3.5 MB for Linux Kernel Image */ - reg = <0x00080000 0x00380000>; - label = "NOR Linux Kernel Image"; - }; - - partition@400000 { - /* 11MB for JFFS2 based Root file System */ - reg = <0x00400000 0x00b00000>; - label = "NOR JFFS2 Root File System"; - }; - - partition@f00000 { - /* This location must not be altered */ - /* 512KB for u-boot Bootloader Image */ - /* 512KB for u-boot Environment Variables */ - reg = <0x00f00000 0x00100000>; - label = "NOR U-Boot Image"; - read-only; - }; - }; - - nand@1,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "fsl,p2020-fcm-nand", - "fsl,elbc-fcm-nand"; - reg = <0x1 0x0 0x40000>; - - partition@0 { - /* This location must not be altered */ - /* 1MB for u-boot Bootloader Image */ - reg = <0x0 0x00100000>; - label = "NAND U-Boot Image"; - read-only; - }; - - partition@100000 { - /* 1MB for DTB Image */ - reg = <0x00100000 0x00100000>; - label = "NAND DTB Image"; - }; - - partition@200000 { - /* 4MB for Linux Kernel Image */ - reg = <0x00200000 0x00400000>; - label = "NAND Linux Kernel Image"; - }; - - partition@600000 { - /* 4MB for Compressed Root file System Image */ - reg = <0x00600000 0x00400000>; - label = "NAND Compressed RFS Image"; - }; - - partition@a00000 { - /* 7MB for JFFS2 based Root file System */ - reg = <0x00a00000 0x00700000>; - label = "NAND JFFS2 Root File System"; - }; - - partition@1100000 { - /* 15MB for JFFS2 based Root file System */ - reg = <0x01100000 0x00f00000>; - label = "NAND Writable User area"; - }; - }; - - L2switch@2,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "vitesse-7385"; - reg = <0x2 0x0 0x20000>; - }; - - cpld@3,0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "cpld"; - reg = <0x3 0x0 0x20000>; - read-only; - }; -}; - -&soc { - i2c@3000 { - rtc@68 { - compatible = "pericom,pt7c4338"; - reg = <0x68>; - }; - }; - - spi@7000 { - flash@0 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "spansion,m25p80"; - reg = <0>; - spi-max-frequency = <40000000>; - - partition@0 { - /* 512KB for u-boot Bootloader Image */ - reg = <0x0 0x00080000>; - label = "SPI U-Boot Image"; - read-only; - }; - - partition@80000 { - /* 512KB for DTB Image */ - reg = <0x00080000 0x00080000>; - label = "SPI DTB Image"; - }; - - partition@100000 { - /* 4MB for Linux Kernel Image */ - reg = <0x00100000 0x00400000>; - label = "SPI Linux Kernel Image"; - }; - - partition@500000 { - /* 4MB for Compressed RFS Image */ - reg = <0x00500000 0x00400000>; - label = "SPI Compressed RFS Image"; - }; - - partition@900000 { - /* 7MB for JFFS2 based RFS */ - reg = <0x00900000 0x00700000>; - label = "SPI JFFS2 RFS"; - }; - }; - }; - - usb@22000 { - phy_type = "ulpi"; - }; - - mdio@24520 { - phy0: ethernet-phy@0 { - interrupts = <3 1 0 0>; - reg = <0x0>; - }; - phy1: ethernet-phy@1 { - interrupts = <2 1 0 0>; - reg = <0x1>; - }; - }; - - mdio@25520 { - tbi0: tbi-phy@11 { - reg = <0x11>; - device_type = "tbi-phy"; - }; - }; - - mdio@26520 { - status = "disabled"; - }; - - ptp_clock@24e00 { - fsl,tclk-period = <5>; - fsl,tmr-prsc = <200>; - fsl,tmr-add = <0xCCCCCCCD>; - fsl,tmr-fiper1 = <0x3B9AC9FB>; - fsl,tmr-fiper2 = <0x0001869B>; - fsl,max-adj = <249999999>; - }; - - enet0: ethernet@24000 { - fixed-link = <1 1 1000 0 0>; - phy-connection-type = "rgmii-id"; - }; - - enet1: ethernet@25000 { - tbi-handle = <&tbi0>; - phy-handle = <&phy0>; - phy-connection-type = "sgmii"; - }; - - enet2: ethernet@26000 { - phy-handle = <&phy1>; - phy-connection-type = "rgmii-id"; - }; -}; diff --git a/trunk/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts b/trunk/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts deleted file mode 100644 index 852e5b27485d..000000000000 --- a/trunk/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * P2020 RDB-PC 32Bit Physical Address Map Device Tree Source - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p2020si-pre.dtsi" - -/ { - model = "fsl,P2020RDB"; - compatible = "fsl,P2020RDB-PC"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@ffe05000 { - reg = <0 0xffe05000 0 0x1000>; - - /* NOR and NAND Flashes */ - ranges = <0x0 0x0 0x0 0xef000000 0x01000000 - 0x1 0x0 0x0 0xff800000 0x00040000 - 0x2 0x0 0x0 0xffb00000 0x00020000 - 0x3 0x0 0x0 0xffa00000 0x00020000>; - }; - - soc: soc@ffe00000 { - ranges = <0x0 0x0 0xffe00000 0x100000>; - }; - - pci0: pcie@ffe08000 { - reg = <0 0xffe08000 0 0x1000>; - status = "disabled"; - }; - - pci1: pcie@ffe09000 { - reg = <0 0xffe09000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci2: pcie@ffe0a000 { - reg = <0 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "p2020rdb-pc.dtsi" -/include/ "fsl/p2020si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts b/trunk/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts deleted file mode 100644 index b5a56ca51cf7..000000000000 --- a/trunk/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * P2020 RDB-PC 36Bit Physical Address Map Device Tree Source - * - * Copyright 2011 Freescale Semiconductor Inc. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Freescale Semiconductor nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * - * ALTERNATIVELY, this software may be distributed under the terms of the - * GNU General Public License ("GPL") as published by the Free Software - * Foundation, either version 2 of that License or (at your option) any - * later version. - * - * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/include/ "fsl/p2020si-pre.dtsi" - -/ { - model = "fsl,P2020RDB"; - compatible = "fsl,P2020RDB-PC"; - - memory { - device_type = "memory"; - }; - - lbc: localbus@fffe05000 { - reg = <0xf 0xffe05000 0 0x1000>; - - /* NOR and NAND Flashes */ - ranges = <0x0 0x0 0xf 0xef000000 0x01000000 - 0x1 0x0 0xf 0xff800000 0x00040000 - 0x2 0x0 0xf 0xffb00000 0x00020000 - 0x3 0x0 0xf 0xffa00000 0x00020000>; - }; - - soc: soc@fffe00000 { - ranges = <0x0 0xf 0xffe00000 0x100000>; - }; - - pci0: pcie@fffe08000 { - reg = <0xf 0xffe08000 0 0x1000>; - status = "disabled"; - }; - - pci1: pcie@fffe09000 { - reg = <0xf 0xffe09000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; - - pci2: pcie@fffe0a000 { - reg = <0xf 0xffe0a000 0 0x1000>; - ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 - 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; - pcie@0 { - ranges = <0x2000000 0x0 0xe0000000 - 0x2000000 0x0 0xe0000000 - 0x0 0x20000000 - - 0x1000000 0x0 0x0 - 0x1000000 0x0 0x0 - 0x0 0x100000>; - }; - }; -}; - -/include/ "p2020rdb-pc.dtsi" -/include/ "fsl/p2020si-post.dtsi" diff --git a/trunk/arch/powerpc/boot/dts/p2020rdb.dts b/trunk/arch/powerpc/boot/dts/p2020rdb.dts index 153bc76bb48e..eb8a6aa2bda5 100644 --- a/trunk/arch/powerpc/boot/dts/p2020rdb.dts +++ b/trunk/arch/powerpc/boot/dts/p2020rdb.dts @@ -34,7 +34,7 @@ /* NOR and NAND Flashes */ ranges = <0x0 0x0 0x0 0xef000000 0x01000000 - 0x1 0x0 0x0 0xff800000 0x00040000 + 0x1 0x0 0x0 0xffa00000 0x00040000 0x2 0x0 0x0 0xffb00000 0x00020000>; nor@0,0 { @@ -157,7 +157,7 @@ #size-cells = <1>; compatible = "spansion,s25sl12801"; reg = <0>; - spi-max-frequency = <40000000>; + spi-max-frequency = <50000000>; partition@0 { /* 512KB for u-boot Bootloader Image */ diff --git a/trunk/arch/powerpc/boot/wrapper b/trunk/arch/powerpc/boot/wrapper index 6761c746048d..f090e6d2907e 100755 --- a/trunk/arch/powerpc/boot/wrapper +++ b/trunk/arch/powerpc/boot/wrapper @@ -144,7 +144,6 @@ tmp=$tmpdir/zImage.$$.o ksection=.kernel:vmlinux.strip isection=.kernel:initrd link_address='0x400000' -make_space=y case "$platform" in pseries) @@ -211,7 +210,6 @@ ps3) ksection=.kernel:vmlinux.bin isection=.kernel:initrd link_address='' - make_space=n pie= ;; ep88xc|ep405|ep8248e) @@ -280,19 +278,17 @@ else rm -f $vmz.$$ fi -if [ "$make_space" = "y" ]; then - # Round the size to next higher MB limit - round_size=$(((strip_size + 0xfffff) & 0xfff00000)) +# Round the size to next higher MB limit +round_size=$(((strip_size + 0xfffff) & 0xfff00000)) - round_size=0x$(printf "%x" $round_size) - link_addr=$(printf "%d" $link_address) +round_size=0x$(printf "%x" $round_size) +link_addr=$(printf "%d" $link_address) - if [ $link_addr -lt $strip_size ]; then - echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \ - "overlaps the address of the wrapper($link_address)" - echo "INFO: Fixing the link_address of wrapper to ($round_size)" - link_address=$round_size - fi +if [ $link_addr -lt $strip_size ]; then + echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \ + "overlaps the address of the wrapper($link_address)" + echo "INFO: Fixing the link_address of wrapper to ($round_size)" + link_address=$round_size fi vmz="$vmz$gzip" diff --git a/trunk/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/trunk/arch/powerpc/configs/85xx/ge_imp3a_defconfig deleted file mode 100644 index f8c51a4ab995..000000000000 --- a/trunk/arch/powerpc/configs/85xx/ge_imp3a_defconfig +++ /dev/null @@ -1,257 +0,0 @@ -CONFIG_PPC_85xx=y -CONFIG_SMP=y -CONFIG_NR_CPUS=2 -CONFIG_EXPERIMENTAL=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_SPARSE_IRQ=y -CONFIG_IKCONFIG=y -CONFIG_IKCONFIG_PROC=y -# CONFIG_UTS_NS is not set -# CONFIG_IPC_NS is not set -# CONFIG_USER_NS is not set -# CONFIG_PID_NS is not set -# CONFIG_NET_NS is not set -CONFIG_SYSFS_DEPRECATED=y -CONFIG_SYSFS_DEPRECATED_V2=y -CONFIG_RELAY=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_PERF_EVENTS=y -CONFIG_SLAB=y -CONFIG_MODULES=y -CONFIG_MODULE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -CONFIG_GE_IMP3A=y -CONFIG_QUICC_ENGINE=y -CONFIG_QE_GPIO=y -CONFIG_CPM2=y -CONFIG_HIGHMEM=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_HZ_1000=y -CONFIG_PREEMPT=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_BINFMT_MISC=m -CONFIG_MATH_EMULATION=y -CONFIG_IRQ_ALL_CPUS=y -CONFIG_FORCE_MAX_ZONEORDER=17 -CONFIG_PCI=y -CONFIG_PCIEPORTBUS=y -CONFIG_PCI_MSI=y -CONFIG_PCCARD=y -# CONFIG_PCMCIA_LOAD_CIS is not set -CONFIG_YENTA=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=m -CONFIG_NET_KEY=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_IP_PNP=y -CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y -CONFIG_NET_IPIP=m -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -# CONFIG_INET_XFRM_MODE_BEET is not set -CONFIG_INET6_AH=m -CONFIG_INET6_IPCOMP=m -CONFIG_IPV6_TUNNEL=m -CONFIG_NET_PKTGEN=m -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_MTD=y -CONFIG_MTD_OF_PARTS=y -CONFIG_MTD_CHAR=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_JEDECPROBE=y -CONFIG_MTD_CFI_INTELEXT=y -CONFIG_MTD_CFI_AMDSTD=y -CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_FSL_ELBC=y -CONFIG_PROC_DEVICETREE=y -CONFIG_BLK_DEV_LOOP=m -CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_BLK_DEV_NBD=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=131072 -CONFIG_MISC_DEVICES=y -CONFIG_DS1682=y -CONFIG_BLK_DEV_SD=y -CONFIG_CHR_DEV_ST=y -CONFIG_BLK_DEV_SR=y -CONFIG_ATA=y -CONFIG_SATA_AHCI=y -CONFIG_SATA_SIL24=y -# CONFIG_ATA_SFF is not set -CONFIG_NETDEVICES=y -CONFIG_BONDING=m -CONFIG_DUMMY=m -CONFIG_NETCONSOLE=y -CONFIG_NETPOLL_TRAP=y -CONFIG_TUN=m -# CONFIG_NET_VENDOR_3COM is not set -CONFIG_FS_ENET=y -CONFIG_UCC_GETH=y -CONFIG_GIANFAR=y -CONFIG_PPP=m -CONFIG_PPP_BSDCOMP=m -CONFIG_PPP_DEFLATE=m -CONFIG_PPP_FILTER=y -CONFIG_PPP_MULTILINK=y -CONFIG_PPPOE=m -CONFIG_PPP_ASYNC=m -CONFIG_PPP_SYNC_TTY=m -CONFIG_SLIP=m -CONFIG_SLIP_COMPRESSED=y -CONFIG_SLIP_SMART=y -CONFIG_SLIP_MODE_SLIP6=y -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_LEGACY_PTYS is not set -CONFIG_SERIAL_8250=y -CONFIG_SERIAL_8250_CONSOLE=y -CONFIG_SERIAL_8250_NR_UARTS=2 -CONFIG_SERIAL_8250_RUNTIME_UARTS=2 -CONFIG_SERIAL_8250_EXTENDED=y -CONFIG_SERIAL_8250_MANY_PORTS=y -CONFIG_SERIAL_8250_DETECT_IRQ=y -CONFIG_SERIAL_8250_RSA=y -CONFIG_SERIAL_QE=m -CONFIG_NVRAM=y -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_CPM=m -CONFIG_I2C_MPC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_GE_FPGA=y -CONFIG_SENSORS_LM90=y -CONFIG_SENSORS_LM92=y -CONFIG_WATCHDOG=y -CONFIG_GEF_WDT=y -CONFIG_VIDEO_OUTPUT_CONTROL=m -CONFIG_HID_DRAGONRISE=y -CONFIG_HID_GYRATION=y -CONFIG_HID_TWINHAN=y -CONFIG_HID_ORTEK=y -CONFIG_HID_PANTHERLORD=y -CONFIG_HID_PETALYNX=y -CONFIG_HID_SAMSUNG=y -CONFIG_HID_SONY=y -CONFIG_HID_SUNPLUS=y -CONFIG_HID_GREENASIA=y -CONFIG_HID_SMARTJOYPLUS=y -CONFIG_HID_TOPSEED=y -CONFIG_HID_THRUSTMASTER=y -CONFIG_HID_ZEROPLUS=y -CONFIG_USB=y -CONFIG_USB_DEVICEFS=y -CONFIG_USB_EHCI_HCD=y -# CONFIG_USB_EHCI_TT_NEWSCHED is not set -CONFIG_USB_EHCI_FSL=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_OHCI_HCD_PPC_OF_BE=y -CONFIG_USB_OHCI_HCD_PPC_OF_LE=y -CONFIG_USB_STORAGE=y -CONFIG_EDAC=y -CONFIG_EDAC_MM_EDAC=y -CONFIG_EDAC_MPC85XX=y -CONFIG_RTC_CLASS=y -# CONFIG_RTC_INTF_PROC is not set -CONFIG_RTC_DRV_RX8581=y -CONFIG_DMADEVICES=y -CONFIG_FSL_DMA=y -# CONFIG_NET_DMA is not set -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT3_FS=y -# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT4_FS=y -CONFIG_FUSE_FS=y -CONFIG_ISO9660_FS=y -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -CONFIG_FAT_DEFAULT_CODEPAGE=850 -CONFIG_FAT_DEFAULT_IOCHARSET="ascii" -CONFIG_NTFS_FS=y -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_JFFS2_FS=y -CONFIG_NFS_FS=y -CONFIG_NFS_V3=y -CONFIG_NFS_V4=y -CONFIG_ROOT_NFS=y -CONFIG_NFSD=y -CONFIG_NFSD_V4=y -CONFIG_CIFS=m -CONFIG_CIFS_XATTR=y -CONFIG_CIFS_POSIX=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=y -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_UTF8=y -CONFIG_CRC_CCITT=y -CONFIG_CRC_T10DIF=y -CONFIG_LIBCRC32C=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_SYSCTL_SYSCALL_CHECK=y -CONFIG_CRYPTO_CBC=y -CONFIG_CRYPTO_MD5=y -CONFIG_CRYPTO_SHA256=m -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_DES=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_CRYPTO_DEV_TALITOS=y diff --git a/trunk/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/trunk/arch/powerpc/configs/86xx/gef_ppc9a_defconfig index da731c2fe984..d41857a5152d 100644 --- a/trunk/arch/powerpc/configs/86xx/gef_ppc9a_defconfig +++ b/trunk/arch/powerpc/configs/86xx/gef_ppc9a_defconfig @@ -131,7 +131,6 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_GE_FPGA=y CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y diff --git a/trunk/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/trunk/arch/powerpc/configs/86xx/gef_sbc310_defconfig index 2149360a1e62..38303ec11bcd 100644 --- a/trunk/arch/powerpc/configs/86xx/gef_sbc310_defconfig +++ b/trunk/arch/powerpc/configs/86xx/gef_sbc310_defconfig @@ -132,7 +132,6 @@ CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_GE_FPGA=y CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y diff --git a/trunk/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/trunk/arch/powerpc/configs/86xx/gef_sbc610_defconfig index af2e8e1edba6..98533973d20f 100644 --- a/trunk/arch/powerpc/configs/86xx/gef_sbc610_defconfig +++ b/trunk/arch/powerpc/configs/86xx/gef_sbc610_defconfig @@ -183,8 +183,6 @@ CONFIG_NVRAM=y CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_MPC=y -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_GE_FPGA=y CONFIG_SENSORS_LM90=y CONFIG_SENSORS_LM92=y CONFIG_WATCHDOG=y diff --git a/trunk/arch/powerpc/configs/iseries_defconfig b/trunk/arch/powerpc/configs/iseries_defconfig new file mode 100644 index 000000000000..27c46d679968 --- /dev/null +++ b/trunk/arch/powerpc/configs/iseries_defconfig @@ -0,0 +1,236 @@ +CONFIG_PPC64=y +CONFIG_SMP=y +CONFIG_EXPERIMENTAL=y +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +CONFIG_AUDITSYSCALL=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_COMPAT_BRK is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_MODULE_SRCVERSION_ALL=y +# CONFIG_PPC_PSERIES is not set +CONFIG_LPARCFG=y +CONFIG_PPC_ISERIES=y +CONFIG_VIODASD=y +CONFIG_VIOCD=m +CONFIG_VIOTAPE=m +# CONFIG_PPC_PMAC is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_ALL_CPUS=y +# CONFIG_MIGRATION is not set +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=m +CONFIG_XFRM_SUB_POLICY=y +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_NET_IPIP=y +CONFIG_SYN_COOKIES=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_XFRM_MODE_BEET=m +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +CONFIG_NETFILTER=y +CONFIG_NETFILTER_NETLINK_QUEUE=m +CONFIG_NETFILTER_NETLINK_LOG=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_EVENTS=y +# CONFIG_NF_CT_PROTO_SCTP is not set +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_TPROXY=m +CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NF_CONNTRACK_IPV4=m +CONFIG_IP_NF_QUEUE=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_ADDRTYPE=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_TARGET_LOG=m +CONFIG_IP_NF_TARGET_ULOG=m +CONFIG_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_CLUSTERIP=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPTABLES=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_PROC_DEVICETREE=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_NBD=m +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=65536 +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_ST=y +CONFIG_BLK_DEV_SR=y +CONFIG_BLK_DEV_SR_VENDOR=y +CONFIG_CHR_DEV_SG=y +CONFIG_SCSI_MULTI_LUN=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SPI_ATTRS=y +CONFIG_SCSI_FC_ATTRS=y +CONFIG_SCSI_SAS_LIBSAS=m +CONFIG_SCSI_IBMVSCSI=m +CONFIG_MD=y +CONFIG_BLK_DEV_MD=y +CONFIG_MD_LINEAR=y +CONFIG_MD_RAID0=y +CONFIG_MD_RAID1=y +CONFIG_MD_RAID10=m +CONFIG_MD_MULTIPATH=m +CONFIG_MD_FAULTY=m +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=m +CONFIG_DM_SNAPSHOT=m +CONFIG_DM_MIRROR=m +CONFIG_DM_ZERO=m +CONFIG_NETDEVICES=y +CONFIG_DUMMY=m +CONFIG_BONDING=m +CONFIG_TUN=m +CONFIG_NET_ETHERNET=y +CONFIG_NET_PCI=y +CONFIG_PCNET32=y +CONFIG_E100=y +CONFIG_ACENIC=m +CONFIG_E1000=m +CONFIG_ISERIES_VETH=y +CONFIG_PPP=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPPOE=m +CONFIG_NETCONSOLE=y +CONFIG_NETPOLL_TRAP=y +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO is not set +CONFIG_SERIAL_ICOM=m +# CONFIG_HW_RANDOM is not set +CONFIG_GEN_RTC=y +CONFIG_RAW_DRIVER=y +# CONFIG_HWMON is not set +# CONFIG_HID_SUPPORT is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT2_FS_XIP=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +CONFIG_EXT4_FS=y +CONFIG_REISERFS_FS=y +CONFIG_REISERFS_FS_XATTR=y +CONFIG_REISERFS_FS_POSIX_ACL=y +CONFIG_REISERFS_FS_SECURITY=y +CONFIG_JFS_FS=m +CONFIG_JFS_POSIX_ACL=y +CONFIG_JFS_SECURITY=y +CONFIG_XFS_FS=m +CONFIG_XFS_POSIX_ACL=y +CONFIG_GFS2_FS=m +CONFIG_AUTOFS_FS=m +CONFIG_ISO9660_FS=y +CONFIG_JOLIET=y +CONFIG_ZISOFS=y +CONFIG_UDF_FS=m +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_PROC_KCORE=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_CRAMFS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_NFS_V3_ACL=y +CONFIG_NFS_V4=y +CONFIG_NFSD=m +CONFIG_NFSD_V3_ACL=y +CONFIG_NFSD_V4=y +CONFIG_RPCSEC_GSS_SPKM3=m +CONFIG_CIFS=m +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_DLM=m +CONFIG_CRC_T10DIF=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_KERNEL=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set +CONFIG_LATENCYTOP=y +CONFIG_SYSCTL_SYSCALL_CHECK=y +CONFIG_DEBUG_STACKOVERFLOW=y +CONFIG_DEBUG_STACK_USAGE=y +CONFIG_CRYPTO_NULL=m +CONFIG_CRYPTO_TEST=m +CONFIG_CRYPTO_ECB=m +CONFIG_CRYPTO_PCBC=m +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_MD4=m +CONFIG_CRYPTO_MICHAEL_MIC=m +CONFIG_CRYPTO_SHA256=m +CONFIG_CRYPTO_SHA512=m +CONFIG_CRYPTO_TGR192=m +CONFIG_CRYPTO_WP512=m +CONFIG_CRYPTO_AES=m +CONFIG_CRYPTO_ANUBIS=m +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_BLOWFISH=m +CONFIG_CRYPTO_CAST6=m +CONFIG_CRYPTO_KHAZAD=m +CONFIG_CRYPTO_SEED=m +CONFIG_CRYPTO_SERPENT=m +CONFIG_CRYPTO_TEA=m +CONFIG_CRYPTO_TWOFISH=m +# CONFIG_CRYPTO_ANSI_CPRNG is not set +# CONFIG_CRYPTO_HW is not set diff --git a/trunk/arch/powerpc/configs/mpc5200_defconfig b/trunk/arch/powerpc/configs/mpc5200_defconfig index 6640a35bebb7..2a1320fb2723 100644 --- a/trunk/arch/powerpc/configs/mpc5200_defconfig +++ b/trunk/arch/powerpc/configs/mpc5200_defconfig @@ -1,8 +1,8 @@ CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y -CONFIG_SPARSE_IRQ=y CONFIG_LOG_BUF_SHIFT=14 CONFIG_BLK_DEV_INITRD=y +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_BLK_DEV_BSG is not set @@ -13,12 +13,15 @@ CONFIG_PPC_EFIKA=y CONFIG_PPC_LITE5200=y CONFIG_PPC_MEDIA5200=y CONFIG_PPC_MPC5200_BUGFIX=y +CONFIG_PPC_MPC5200_GPIO=y CONFIG_PPC_MPC5200_LPBFIFO=m # CONFIG_PPC_PMAC is not set CONFIG_PPC_BESTCOMM=y CONFIG_SIMPLE_GPIO=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y +CONFIG_SPARSE_IRQ=y +CONFIG_PM=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -33,20 +36,23 @@ CONFIG_SYN_COOKIES=y # CONFIG_IPV6 is not set CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_MTD=y +CONFIG_MTD_CONCAT=y +CONFIG_MTD_PARTITIONS=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_OF_PARTS=y CONFIG_MTD_CHAR=y CONFIG_MTD_BLOCK=y CONFIG_MTD_CFI=y CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_RAM=y CONFIG_MTD_ROM=y CONFIG_MTD_PHYSMAP_OF=y -CONFIG_MTD_PLATRAM=y CONFIG_MTD_UBI=m CONFIG_PROC_DEVICETREE=y CONFIG_BLK_DEV_LOOP=y CONFIG_BLK_DEV_RAM=y CONFIG_BLK_DEV_RAM_SIZE=32768 +CONFIG_MISC_DEVICES=y CONFIG_EEPROM_AT24=y CONFIG_SCSI_TGT=y CONFIG_BLK_DEV_SD=y @@ -55,10 +61,11 @@ CONFIG_ATA=y CONFIG_PATA_MPC52xx=y CONFIG_PATA_PLATFORM=y CONFIG_NETDEVICES=y -CONFIG_FEC_MPC52xx=y -CONFIG_AMD_PHY=y CONFIG_LXT_PHY=y -CONFIG_FIXED_PHY=y +CONFIG_NET_ETHERNET=y +CONFIG_FEC_MPC52xx=y +# CONFIG_NETDEV_1000 is not set +# CONFIG_NETDEV_10000 is not set # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO is not set @@ -73,17 +80,11 @@ CONFIG_SPI_GPIO=m CONFIG_SPI_MPC52xx=m CONFIG_SPI_MPC52xx_PSC=m CONFIG_SPI_SPIDEV=m -CONFIG_GPIO_SYSFS=y -CONFIG_SENSORS_LM80=y -CONFIG_SENSORS_LM87=m CONFIG_WATCHDOG=y -CONFIG_MFD_SM501=m CONFIG_DRM=y CONFIG_VIDEO_OUTPUT_CONTROL=y CONFIG_FB=y -CONFIG_FB_FOREIGN_ENDIAN=y CONFIG_FB_RADEON=y -CONFIG_FB_SM501=m # CONFIG_VGA_CONSOLE is not set CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_LOGO=y @@ -123,11 +124,10 @@ CONFIG_USB_STORAGE=y CONFIG_NEW_LEDS=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_DS1307=y -CONFIG_RTC_DRV_DS1374=y -CONFIG_RTC_DRV_PCF8563=m CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set +CONFIG_INOTIFY=y CONFIG_MSDOS_FS=y CONFIG_VFAT_FS=y CONFIG_PROC_KCORE=y @@ -145,4 +145,5 @@ CONFIG_PRINTK_TIME=y CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_HUNG_TASK=y CONFIG_DEBUG_INFO=y +# CONFIG_RCU_CPU_STALL_DETECTOR is not set # CONFIG_CRYPTO_ANSI_CPRNG is not set diff --git a/trunk/arch/powerpc/configs/mpc85xx_defconfig b/trunk/arch/powerpc/configs/mpc85xx_defconfig index 5fb0c8a94811..f37a2ab48881 100644 --- a/trunk/arch/powerpc/configs/mpc85xx_defconfig +++ b/trunk/arch/powerpc/configs/mpc85xx_defconfig @@ -1,5 +1,4 @@ CONFIG_PPC_85xx=y -CONFIG_PHYS_64BIT=y CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y diff --git a/trunk/arch/powerpc/configs/mpc85xx_smp_defconfig b/trunk/arch/powerpc/configs/mpc85xx_smp_defconfig index fb51bc90edd2..abdcd317cda7 100644 --- a/trunk/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/trunk/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -1,5 +1,4 @@ CONFIG_PPC_85xx=y -CONFIG_PHYS_64BIT=y CONFIG_SMP=y CONFIG_NR_CPUS=8 CONFIG_EXPERIMENTAL=y diff --git a/trunk/arch/powerpc/include/asm/abs_addr.h b/trunk/arch/powerpc/include/asm/abs_addr.h index 9d92ba04b033..5ab0b71531be 100644 --- a/trunk/arch/powerpc/include/asm/abs_addr.h +++ b/trunk/arch/powerpc/include/asm/abs_addr.h @@ -17,6 +17,7 @@ #include #include #include +#include struct mschunks_map { unsigned long num_chunks; @@ -45,12 +46,30 @@ static inline unsigned long addr_to_chunk(unsigned long addr) static inline unsigned long phys_to_abs(unsigned long pa) { - return pa; + unsigned long chunk; + + /* This is a no-op on non-iSeries */ + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return pa; + + chunk = addr_to_chunk(pa); + + if (chunk < mschunks_map.num_chunks) + chunk = mschunks_map.mapping[chunk]; + + return chunk_to_addr(chunk) + (pa & MSCHUNKS_OFFSET_MASK); } /* Convenience macros */ #define virt_to_abs(va) phys_to_abs(__pa(va)) #define abs_to_virt(aa) __va(aa) +/* + * Converts Virtual Address to Real Address for + * Legacy iSeries Hypervisor calls + */ +#define iseries_hv_addr(virtaddr) \ + (0x8000000000000000UL | virt_to_abs(virtaddr)) + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_ABS_ADDR_H */ diff --git a/trunk/arch/powerpc/include/asm/atomic.h b/trunk/arch/powerpc/include/asm/atomic.h index 14174e838ad9..02e41b53488d 100644 --- a/trunk/arch/powerpc/include/asm/atomic.h +++ b/trunk/arch/powerpc/include/asm/atomic.h @@ -212,36 +212,6 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) return t; } -/** - * atomic_inc_not_zero - increment unless the number is zero - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1, so long as @v is non-zero. - * Returns non-zero if @v was non-zero, and zero otherwise. - */ -static __inline__ int atomic_inc_not_zero(atomic_t *v) -{ - int t1, t2; - - __asm__ __volatile__ ( - PPC_ATOMIC_ENTRY_BARRIER -"1: lwarx %0,0,%2 # atomic_inc_not_zero\n\ - cmpwi 0,%0,0\n\ - beq- 2f\n\ - addic %1,%0,1\n" - PPC405_ERR77(0,%2) -" stwcx. %1,0,%2\n\ - bne- 1b\n" - PPC_ATOMIC_EXIT_BARRIER - "\n\ -2:" - : "=&r" (t1), "=&r" (t2) - : "r" (&v->counter) - : "cc", "xer", "memory"); - - return t1; -} -#define atomic_inc_not_zero(v) atomic_inc_not_zero((v)) #define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0) #define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0) @@ -497,34 +467,7 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) return t != u; } -/** - * atomic_inc64_not_zero - increment unless the number is zero - * @v: pointer of type atomic64_t - * - * Atomically increments @v by 1, so long as @v is non-zero. - * Returns non-zero if @v was non-zero, and zero otherwise. - */ -static __inline__ long atomic64_inc_not_zero(atomic64_t *v) -{ - long t1, t2; - - __asm__ __volatile__ ( - PPC_ATOMIC_ENTRY_BARRIER -"1: ldarx %0,0,%2 # atomic64_inc_not_zero\n\ - cmpdi 0,%0,0\n\ - beq- 2f\n\ - addic %1,%0,1\n\ - stdcx. %1,0,%2\n\ - bne- 1b\n" - PPC_ATOMIC_EXIT_BARRIER - "\n\ -2:" - : "=&r" (t1), "=&r" (t2) - : "r" (&v->counter) - : "cc", "xer", "memory"); - - return t1; -} +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) #endif /* __powerpc64__ */ diff --git a/trunk/arch/powerpc/include/asm/cputable.h b/trunk/arch/powerpc/include/asm/cputable.h index b9219e99bd2a..ad55a1ccb9fb 100644 --- a/trunk/arch/powerpc/include/asm/cputable.h +++ b/trunk/arch/powerpc/include/asm/cputable.h @@ -390,10 +390,6 @@ extern const char *powerpc_base_platform; CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ CPU_FTR_DEBUG_LVL_EXC) -#define CPU_FTRS_E6500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ - CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ - CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ - CPU_FTR_DEBUG_LVL_EXC) #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) /* 64-bit CPUs */ @@ -446,7 +442,7 @@ extern const char *powerpc_base_platform; #ifdef __powerpc64__ #ifdef CONFIG_PPC_BOOK3E -#define CPU_FTRS_POSSIBLE (CPU_FTRS_E6500 | CPU_FTRS_E5500 | CPU_FTRS_A2) +#define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500 | CPU_FTRS_A2) #else #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ @@ -487,7 +483,7 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC | - CPU_FTRS_E5500 | CPU_FTRS_E6500 | + CPU_FTRS_E5500 | #endif 0, }; @@ -495,7 +491,7 @@ enum { #ifdef __powerpc64__ #ifdef CONFIG_PPC_BOOK3E -#define CPU_FTRS_ALWAYS (CPU_FTRS_E6500 & CPU_FTRS_E5500 & CPU_FTRS_A2) +#define CPU_FTRS_ALWAYS (CPU_FTRS_E5500 & CPU_FTRS_A2) #else #define CPU_FTRS_ALWAYS \ (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \ @@ -532,7 +528,7 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC & - CPU_FTRS_E5500 & CPU_FTRS_E6500 & + CPU_FTRS_E5500 & #endif CPU_FTRS_POSSIBLE, }; diff --git a/trunk/arch/powerpc/include/asm/device.h b/trunk/arch/powerpc/include/asm/device.h index 63d5ca49cece..d57c08acedfc 100644 --- a/trunk/arch/powerpc/include/asm/device.h +++ b/trunk/arch/powerpc/include/asm/device.h @@ -31,9 +31,6 @@ struct dev_archdata { #ifdef CONFIG_SWIOTLB dma_addr_t max_direct_dma_addr; #endif -#ifdef CONFIG_EEH - struct eeh_dev *edev; -#endif }; struct pdev_archdata { diff --git a/trunk/arch/powerpc/include/asm/dma.h b/trunk/arch/powerpc/include/asm/dma.h index adadb9943610..a7e06e25c708 100644 --- a/trunk/arch/powerpc/include/asm/dma.h +++ b/trunk/arch/powerpc/include/asm/dma.h @@ -34,6 +34,8 @@ /* Doesn't really apply... */ #define MAX_DMA_ADDRESS (~0UL) +#if !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) + #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER #define dma_outb outb_p #else @@ -352,5 +354,7 @@ extern int isa_dma_bridge_buggy; #define isa_dma_bridge_buggy (0) #endif +#endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */ + #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_DMA_H */ diff --git a/trunk/arch/powerpc/include/asm/eeh.h b/trunk/arch/powerpc/include/asm/eeh.h index d60f99814ffb..66ea9b8b95c5 100644 --- a/trunk/arch/powerpc/include/asm/eeh.h +++ b/trunk/arch/powerpc/include/asm/eeh.h @@ -1,6 +1,6 @@ /* + * eeh.h * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. - * Copyright 2001-2012 IBM Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,105 +31,44 @@ struct device_node; #ifdef CONFIG_EEH -/* - * The struct is used to trace EEH state for the associated - * PCI device node or PCI device. In future, it might - * represent PE as well so that the EEH device to form - * another tree except the currently existing tree of PCI - * buses and PCI devices - */ -#define EEH_MODE_SUPPORTED (1<<0) /* EEH supported on the device */ -#define EEH_MODE_NOCHECK (1<<1) /* EEH check should be skipped */ -#define EEH_MODE_ISOLATED (1<<2) /* The device has been isolated */ -#define EEH_MODE_RECOVERING (1<<3) /* Recovering the device */ -#define EEH_MODE_IRQ_DISABLED (1<<4) /* Interrupt disabled */ - -struct eeh_dev { - int mode; /* EEH mode */ - int class_code; /* Class code of the device */ - int config_addr; /* Config address */ - int pe_config_addr; /* PE config address */ - int check_count; /* Times of ignored error */ - int freeze_count; /* Times of froze up */ - int false_positives; /* Times of reported #ff's */ - u32 config_space[16]; /* Saved PCI config space */ - struct pci_controller *phb; /* Associated PHB */ - struct device_node *dn; /* Associated device node */ - struct pci_dev *pdev; /* Associated PCI device */ -}; - -static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev) -{ - return edev->dn; -} - -static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev) -{ - return edev->pdev; -} - -/* - * The struct is used to trace the registered EEH operation - * callback functions. Actually, those operation callback - * functions are heavily platform dependent. That means the - * platform should register its own EEH operation callback - * functions before any EEH further operations. - */ -#define EEH_OPT_DISABLE 0 /* EEH disable */ -#define EEH_OPT_ENABLE 1 /* EEH enable */ -#define EEH_OPT_THAW_MMIO 2 /* MMIO enable */ -#define EEH_OPT_THAW_DMA 3 /* DMA enable */ -#define EEH_STATE_UNAVAILABLE (1 << 0) /* State unavailable */ -#define EEH_STATE_NOT_SUPPORT (1 << 1) /* EEH not supported */ -#define EEH_STATE_RESET_ACTIVE (1 << 2) /* Active reset */ -#define EEH_STATE_MMIO_ACTIVE (1 << 3) /* Active MMIO */ -#define EEH_STATE_DMA_ACTIVE (1 << 4) /* Active DMA */ -#define EEH_STATE_MMIO_ENABLED (1 << 5) /* MMIO enabled */ -#define EEH_STATE_DMA_ENABLED (1 << 6) /* DMA enabled */ -#define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */ -#define EEH_RESET_HOT 1 /* Hot reset */ -#define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */ -#define EEH_LOG_TEMP 1 /* EEH temporary error log */ -#define EEH_LOG_PERM 2 /* EEH permanent error log */ - -struct eeh_ops { - char *name; - int (*init)(void); - int (*set_option)(struct device_node *dn, int option); - int (*get_pe_addr)(struct device_node *dn); - int (*get_state)(struct device_node *dn, int *state); - int (*reset)(struct device_node *dn, int option); - int (*wait_state)(struct device_node *dn, int max_wait); - int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len); - int (*configure_bridge)(struct device_node *dn); - int (*read_config)(struct device_node *dn, int where, int size, u32 *val); - int (*write_config)(struct device_node *dn, int where, int size, u32 val); -}; - -extern struct eeh_ops *eeh_ops; extern int eeh_subsystem_enabled; -/* - * Max number of EEH freezes allowed before we consider the device - * to be permanently disabled. - */ +/* Values for eeh_mode bits in device_node */ +#define EEH_MODE_SUPPORTED (1<<0) +#define EEH_MODE_NOCHECK (1<<1) +#define EEH_MODE_ISOLATED (1<<2) +#define EEH_MODE_RECOVERING (1<<3) +#define EEH_MODE_IRQ_DISABLED (1<<4) + +/* Max number of EEH freezes allowed before we consider the device + * to be permanently disabled. */ #define EEH_MAX_ALLOWED_FREEZES 5 -void * __devinit eeh_dev_init(struct device_node *dn, void *data); -void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb); -void __init eeh_dev_phb_init(void); void __init eeh_init(void); -#ifdef CONFIG_PPC_PSERIES -int __init eeh_pseries_init(void); -#endif -int __init eeh_ops_register(struct eeh_ops *ops); -int __exit eeh_ops_unregister(const char *name); unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val); int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); void __init pci_addr_cache_build(void); + +/** + * eeh_add_device_early + * eeh_add_device_late + * + * Perform eeh initialization for devices added after boot. + * Call eeh_add_device_early before doing any i/o to the + * device (including config space i/o). Call eeh_add_device_late + * to finish the eeh setup for this device. + */ void eeh_add_device_tree_early(struct device_node *); void eeh_add_device_tree_late(struct pci_bus *); + +/** + * eeh_remove_device_recursive - undo EEH for device & children. + * @dev: pci device to be removed + * + * As above, this removes the device; it also removes child + * pci devices as well. + */ void eeh_remove_bus_device(struct pci_dev *); /** @@ -148,25 +87,8 @@ void eeh_remove_bus_device(struct pci_dev *); #define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8)) #else /* !CONFIG_EEH */ - -static inline void *eeh_dev_init(struct device_node *dn, void *data) -{ - return NULL; -} - -static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { } - -static inline void eeh_dev_phb_init(void) { } - static inline void eeh_init(void) { } -#ifdef CONFIG_PPC_PSERIES -static inline int eeh_pseries_init(void) -{ - return 0; -} -#endif /* CONFIG_PPC_PSERIES */ - static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) { return val; diff --git a/trunk/arch/powerpc/include/asm/eeh_event.h b/trunk/arch/powerpc/include/asm/eeh_event.h index c68b012b7797..cc3cb04539ac 100644 --- a/trunk/arch/powerpc/include/asm/eeh_event.h +++ b/trunk/arch/powerpc/include/asm/eeh_event.h @@ -1,4 +1,6 @@ /* + * eeh_event.h + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -20,19 +22,32 @@ #define ASM_POWERPC_EEH_EVENT_H #ifdef __KERNEL__ -/* - * structure holding pci controller data that describes a - * change in the isolation status of a PCI slot. A pointer - * to this struct is passed as the data pointer in a notify - * callback. +/** EEH event -- structure holding pci controller data that describes + * a change in the isolation status of a PCI slot. A pointer + * to this struct is passed as the data pointer in a notify callback. */ struct eeh_event { - struct list_head list; /* to form event queue */ - struct eeh_dev *edev; /* EEH device */ + struct list_head list; + struct device_node *dn; /* struct device node */ + struct pci_dev *dev; /* affected device */ }; -int eeh_send_failure_event(struct eeh_dev *edev); -struct eeh_dev *handle_eeh_events(struct eeh_event *); +/** + * eeh_send_failure_event - generate a PCI error event + * @dev pci device + * + * This routine builds a PCI error event which will be delivered + * to all listeners on the eeh_notifier_chain. + * + * This routine can be called within an interrupt context; + * the actual event will be delivered in a normal context + * (from a workqueue). + */ +int eeh_send_failure_event (struct device_node *dn, + struct pci_dev *dev); + +/* Main recovery function */ +struct pci_dn * handle_eeh_events (struct eeh_event *); #endif /* __KERNEL__ */ #endif /* ASM_POWERPC_EEH_EVENT_H */ diff --git a/trunk/arch/powerpc/include/asm/exception-64s.h b/trunk/arch/powerpc/include/asm/exception-64s.h index 548da3aa0a30..8057f4f6980f 100644 --- a/trunk/arch/powerpc/include/asm/exception-64s.h +++ b/trunk/arch/powerpc/include/asm/exception-64s.h @@ -232,30 +232,23 @@ label##_hv: \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ EXC_HV, KVMTEST, vec) -/* This associate vector numbers with bits in paca->irq_happened */ -#define SOFTEN_VALUE_0x500 PACA_IRQ_EE -#define SOFTEN_VALUE_0x502 PACA_IRQ_EE -#define SOFTEN_VALUE_0x900 PACA_IRQ_DEC -#define SOFTEN_VALUE_0x982 PACA_IRQ_DEC - -#define __SOFTEN_TEST(h, vec) \ +#define __SOFTEN_TEST(h) \ lbz r10,PACASOFTIRQEN(r13); \ cmpwi r10,0; \ - li r10,SOFTEN_VALUE_##vec; \ beq masked_##h##interrupt -#define _SOFTEN_TEST(h, vec) __SOFTEN_TEST(h, vec) +#define _SOFTEN_TEST(h) __SOFTEN_TEST(h) #define SOFTEN_TEST_PR(vec) \ KVMTEST_PR(vec); \ - _SOFTEN_TEST(EXC_STD, vec) + _SOFTEN_TEST(EXC_STD) #define SOFTEN_TEST_HV(vec) \ KVMTEST(vec); \ - _SOFTEN_TEST(EXC_HV, vec) + _SOFTEN_TEST(EXC_HV) #define SOFTEN_TEST_HV_201(vec) \ KVMTEST(vec); \ - _SOFTEN_TEST(EXC_STD, vec) + _SOFTEN_TEST(EXC_STD) #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ HMT_MEDIUM; \ @@ -279,55 +272,73 @@ label##_hv: \ _MASKABLE_EXCEPTION_PSERIES(vec, label, \ EXC_HV, SOFTEN_TEST_HV) -/* - * Our exception common code can be passed various "additions" - * to specify the behaviour of interrupts, whether to kick the - * runlatch, etc... - */ - -/* Exception addition: Hard disable interrupts */ -#define DISABLE_INTS SOFT_DISABLE_INTS(r10,r11) +#ifdef CONFIG_PPC_ISERIES +#define DISABLE_INTS \ + li r11,0; \ + stb r11,PACASOFTIRQEN(r13); \ +BEGIN_FW_FTR_SECTION; \ + stb r11,PACAHARDIRQEN(r13); \ +END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ + TRACE_DISABLE_INTS; \ +BEGIN_FW_FTR_SECTION; \ + mfmsr r10; \ + ori r10,r10,MSR_EE; \ + mtmsrd r10,1; \ +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +#else +#define DISABLE_INTS \ + li r11,0; \ + stb r11,PACASOFTIRQEN(r13); \ + stb r11,PACAHARDIRQEN(r13); \ + TRACE_DISABLE_INTS +#endif /* CONFIG_PPC_ISERIES */ -/* Exception addition: Keep interrupt state */ #define ENABLE_INTS \ - ld r11,PACAKMSR(r13); \ ld r12,_MSR(r1); \ + mfmsr r11; \ rlwimi r11,r12,0,MSR_EE; \ mtmsrd r11,1 -#define ADD_NVGPRS \ - bl .save_nvgprs - -#define RUNLATCH_ON \ -BEGIN_FTR_SECTION \ - clrrdi r3,r1,THREAD_SHIFT; \ - ld r4,TI_LOCAL_FLAGS(r3); \ - andi. r0,r4,_TLF_RUNLATCH; \ - beql ppc64_runlatch_on_trampoline; \ -END_FTR_SECTION_IFSET(CPU_FTR_CTRL) - -#define EXCEPTION_COMMON(trap, label, hdlr, ret, additions) \ - .align 7; \ - .globl label##_common; \ -label##_common: \ - EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ - additions; \ - addi r3,r1,STACK_FRAME_OVERHEAD; \ - bl hdlr; \ - b ret - -#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ - EXCEPTION_COMMON(trap, label, hdlr, ret_from_except, \ - ADD_NVGPRS;DISABLE_INTS) +#define STD_EXCEPTION_COMMON(trap, label, hdlr) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + DISABLE_INTS; \ + bl .save_nvgprs; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b .ret_from_except /* * Like STD_EXCEPTION_COMMON, but for exceptions that can occur - * in the idle task and therefore need the special idle handling - * (finish nap and runlatch) + * in the idle task and therefore need the special idle handling. */ -#define STD_EXCEPTION_COMMON_ASYNC(trap, label, hdlr) \ - EXCEPTION_COMMON(trap, label, hdlr, ret_from_except_lite, \ - FINISH_NAP;RUNLATCH_ON;DISABLE_INTS) +#define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + FINISH_NAP; \ + DISABLE_INTS; \ + bl .save_nvgprs; \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b .ret_from_except + +#define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \ + .align 7; \ + .globl label##_common; \ +label##_common: \ + EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ + FINISH_NAP; \ + DISABLE_INTS; \ +BEGIN_FTR_SECTION \ + bl .ppc64_runlatch_on; \ +END_FTR_SECTION_IFSET(CPU_FTR_CTRL) \ + addi r3,r1,STACK_FRAME_OVERHEAD; \ + bl hdlr; \ + b .ret_from_except_lite /* * When the idle code in power4_idle puts the CPU into NAP mode, diff --git a/trunk/arch/powerpc/include/asm/fadump.h b/trunk/arch/powerpc/include/asm/fadump.h deleted file mode 100644 index 88dbf9659185..000000000000 --- a/trunk/arch/powerpc/include/asm/fadump.h +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Firmware Assisted dump header file. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright 2011 IBM Corporation - * Author: Mahesh Salgaonkar - */ - -#ifndef __PPC64_FA_DUMP_H__ -#define __PPC64_FA_DUMP_H__ - -#ifdef CONFIG_FA_DUMP - -/* - * The RMA region will be saved for later dumping when kernel crashes. - * RMA is Real Mode Area, the first block of logical memory address owned - * by logical partition, containing the storage that may be accessed with - * translate off. - */ -#define RMA_START 0x0 -#define RMA_END (ppc64_rma_size) - -/* - * On some Power systems where RMO is 128MB, it still requires minimum of - * 256MB for kernel to boot successfully. When kdump infrastructure is - * configured to save vmcore over network, we run into OOM issue while - * loading modules related to network setup. Hence we need aditional 64M - * of memory to avoid OOM issue. - */ -#define MIN_BOOT_MEM (((RMA_END < (0x1UL << 28)) ? (0x1UL << 28) : RMA_END) \ - + (0x1UL << 26)) - -#define memblock_num_regions(memblock_type) (memblock.memblock_type.cnt) - -#ifndef ELF_CORE_EFLAGS -#define ELF_CORE_EFLAGS 0 -#endif - -/* Firmware provided dump sections */ -#define FADUMP_CPU_STATE_DATA 0x0001 -#define FADUMP_HPTE_REGION 0x0002 -#define FADUMP_REAL_MODE_REGION 0x0011 - -/* Dump request flag */ -#define FADUMP_REQUEST_FLAG 0x00000001 - -/* FAD commands */ -#define FADUMP_REGISTER 1 -#define FADUMP_UNREGISTER 2 -#define FADUMP_INVALIDATE 3 - -/* Dump status flag */ -#define FADUMP_ERROR_FLAG 0x2000 - -#define FADUMP_CPU_ID_MASK ((1UL << 32) - 1) - -#define CPU_UNKNOWN (~((u32)0)) - -/* Utility macros */ -#define SKIP_TO_NEXT_CPU(reg_entry) \ -({ \ - while (reg_entry->reg_id != REG_ID("CPUEND")) \ - reg_entry++; \ - reg_entry++; \ -}) - -/* Kernel Dump section info */ -struct fadump_section { - u32 request_flag; - u16 source_data_type; - u16 error_flags; - u64 source_address; - u64 source_len; - u64 bytes_dumped; - u64 destination_address; -}; - -/* ibm,configure-kernel-dump header. */ -struct fadump_section_header { - u32 dump_format_version; - u16 dump_num_sections; - u16 dump_status_flag; - u32 offset_first_dump_section; - - /* Fields for disk dump option. */ - u32 dd_block_size; - u64 dd_block_offset; - u64 dd_num_blocks; - u32 dd_offset_disk_path; - - /* Maximum time allowed to prevent an automatic dump-reboot. */ - u32 max_time_auto; -}; - -/* - * Firmware Assisted dump memory structure. This structure is required for - * registering future kernel dump with power firmware through rtas call. - * - * No disk dump option. Hence disk dump path string section is not included. - */ -struct fadump_mem_struct { - struct fadump_section_header header; - - /* Kernel dump sections */ - struct fadump_section cpu_state_data; - struct fadump_section hpte_region; - struct fadump_section rmr_region; -}; - -/* Firmware-assisted dump configuration details. */ -struct fw_dump { - unsigned long cpu_state_data_size; - unsigned long hpte_region_size; - unsigned long boot_memory_size; - unsigned long reserve_dump_area_start; - unsigned long reserve_dump_area_size; - /* cmd line option during boot */ - unsigned long reserve_bootvar; - - unsigned long fadumphdr_addr; - unsigned long cpu_notes_buf; - unsigned long cpu_notes_buf_size; - - int ibm_configure_kernel_dump; - - unsigned long fadump_enabled:1; - unsigned long fadump_supported:1; - unsigned long dump_active:1; - unsigned long dump_registered:1; -}; - -/* - * Copy the ascii values for first 8 characters from a string into u64 - * variable at their respective indexes. - * e.g. - * The string "FADMPINF" will be converted into 0x4641444d50494e46 - */ -static inline u64 str_to_u64(const char *str) -{ - u64 val = 0; - int i; - - for (i = 0; i < sizeof(val); i++) - val = (*str) ? (val << 8) | *str++ : val << 8; - return val; -} -#define STR_TO_HEX(x) str_to_u64(x) -#define REG_ID(x) str_to_u64(x) - -#define FADUMP_CRASH_INFO_MAGIC STR_TO_HEX("FADMPINF") -#define REGSAVE_AREA_MAGIC STR_TO_HEX("REGSAVE") - -/* The firmware-assisted dump format. - * - * The register save area is an area in the partition's memory used to preserve - * the register contents (CPU state data) for the active CPUs during a firmware - * assisted dump. The dump format contains register save area header followed - * by register entries. Each list of registers for a CPU starts with - * "CPUSTRT" and ends with "CPUEND". - */ - -/* Register save area header. */ -struct fadump_reg_save_area_header { - u64 magic_number; - u32 version; - u32 num_cpu_offset; -}; - -/* Register entry. */ -struct fadump_reg_entry { - u64 reg_id; - u64 reg_value; -}; - -/* fadump crash info structure */ -struct fadump_crash_info_header { - u64 magic_number; - u64 elfcorehdr_addr; - u32 crashing_cpu; - struct pt_regs regs; - struct cpumask cpu_online_mask; -}; - -/* Crash memory ranges */ -#define INIT_CRASHMEM_RANGES (INIT_MEMBLOCK_REGIONS + 2) - -struct fad_crash_memory_ranges { - unsigned long long base; - unsigned long long size; -}; - -extern int early_init_dt_scan_fw_dump(unsigned long node, - const char *uname, int depth, void *data); -extern int fadump_reserve_mem(void); -extern int setup_fadump(void); -extern int is_fadump_active(void); -extern void crash_fadump(struct pt_regs *, const char *); -extern void fadump_cleanup(void); - -extern void vmcore_cleanup(void); -#else /* CONFIG_FA_DUMP */ -static inline int is_fadump_active(void) { return 0; } -static inline void crash_fadump(struct pt_regs *regs, const char *str) { } -#endif -#endif diff --git a/trunk/arch/powerpc/include/asm/firmware.h b/trunk/arch/powerpc/include/asm/firmware.h index ad0b751b0d78..14db29b18d0e 100644 --- a/trunk/arch/powerpc/include/asm/firmware.h +++ b/trunk/arch/powerpc/include/asm/firmware.h @@ -41,6 +41,7 @@ #define FW_FEATURE_XDABR ASM_CONST(0x0000000000040000) #define FW_FEATURE_MULTITCE ASM_CONST(0x0000000000080000) #define FW_FEATURE_SPLPAR ASM_CONST(0x0000000000100000) +#define FW_FEATURE_ISERIES ASM_CONST(0x0000000000200000) #define FW_FEATURE_LPAR ASM_CONST(0x0000000000400000) #define FW_FEATURE_PS3_LV1 ASM_CONST(0x0000000000800000) #define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000) @@ -64,6 +65,8 @@ enum { FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR | FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO, FW_FEATURE_PSERIES_ALWAYS = 0, + FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, + FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2, FW_FEATURE_POWERNV_ALWAYS = 0, FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1, @@ -76,6 +79,9 @@ enum { #ifdef CONFIG_PPC_PSERIES FW_FEATURE_PSERIES_POSSIBLE | #endif +#ifdef CONFIG_PPC_ISERIES + FW_FEATURE_ISERIES_POSSIBLE | +#endif #ifdef CONFIG_PPC_POWERNV FW_FEATURE_POWERNV_POSSIBLE | #endif @@ -93,6 +99,9 @@ enum { #ifdef CONFIG_PPC_PSERIES FW_FEATURE_PSERIES_ALWAYS & #endif +#ifdef CONFIG_PPC_ISERIES + FW_FEATURE_ISERIES_ALWAYS & +#endif #ifdef CONFIG_PPC_POWERNV FW_FEATURE_POWERNV_ALWAYS & #endif diff --git a/trunk/arch/powerpc/include/asm/fsl_guts.h b/trunk/arch/powerpc/include/asm/fsl_guts.h index ce04530d2000..bebd12463ec9 100644 --- a/trunk/arch/powerpc/include/asm/fsl_guts.h +++ b/trunk/arch/powerpc/include/asm/fsl_guts.h @@ -4,7 +4,7 @@ * Authors: Jeff Brown * Timur Tabi * - * Copyright 2004,2007,2012 Freescale Semiconductor, Inc + * Copyright 2004,2007 Freescale Semiconductor, Inc * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -114,10 +114,6 @@ struct ccsr_guts_86xx { __be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */ } __attribute__ ((packed)); - -/* Alternate function signal multiplex control */ -#define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x)) - #ifdef CONFIG_PPC_86xx #define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */ diff --git a/trunk/arch/powerpc/include/asm/hw_irq.h b/trunk/arch/powerpc/include/asm/hw_irq.h index 51010bfc792e..bb712c9488b3 100644 --- a/trunk/arch/powerpc/include/asm/hw_irq.h +++ b/trunk/arch/powerpc/include/asm/hw_irq.h @@ -11,27 +11,6 @@ #include #include -#ifdef CONFIG_PPC64 - -/* - * PACA flags in paca->irq_happened. - * - * This bits are set when interrupts occur while soft-disabled - * and allow a proper replay. Additionally, PACA_IRQ_HARD_DIS - * is set whenever we manually hard disable. - */ -#define PACA_IRQ_HARD_DIS 0x01 -#define PACA_IRQ_DBELL 0x02 -#define PACA_IRQ_EE 0x04 -#define PACA_IRQ_DEC 0x08 /* Or FIT */ -#define PACA_IRQ_EE_EDGE 0x10 /* BookE only */ - -#endif /* CONFIG_PPC64 */ - -#ifndef __ASSEMBLY__ - -extern void __replay_interrupt(unsigned int vector); - extern void timer_interrupt(struct pt_regs *); #ifdef CONFIG_PPC64 @@ -63,6 +42,7 @@ static inline unsigned long arch_local_irq_disable(void) } extern void arch_local_irq_restore(unsigned long); +extern void iseries_handle_interrupts(void); static inline void arch_local_irq_enable(void) { @@ -88,33 +68,16 @@ static inline bool arch_irqs_disabled(void) #define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory"); #define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory"); #else -#define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1) -#define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1) +#define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) +#define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) #endif -static inline void hard_irq_disable(void) -{ - __hard_irq_disable(); - get_paca()->soft_enabled = 0; - get_paca()->irq_happened |= PACA_IRQ_HARD_DIS; -} - -/* - * This is called by asynchronous interrupts to conditionally - * re-enable hard interrupts when soft-disabled after having - * cleared the source of the interrupt - */ -static inline void may_hard_irq_enable(void) -{ - get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS; - if (!(get_paca()->irq_happened & PACA_IRQ_EE)) - __hard_irq_enable(); -} - -static inline bool arch_irq_disabled_regs(struct pt_regs *regs) -{ - return !regs->softe; -} +#define hard_irq_disable() \ + do { \ + __hard_irq_disable(); \ + get_paca()->soft_enabled = 0; \ + get_paca()->hard_enabled = 0; \ + } while(0) #else /* CONFIG_PPC64 */ @@ -176,13 +139,6 @@ static inline bool arch_irqs_disabled(void) #define hard_irq_disable() arch_local_irq_disable() -static inline bool arch_irq_disabled_regs(struct pt_regs *regs) -{ - return !(regs->msr & MSR_EE); -} - -static inline void may_hard_irq_enable(void) { } - #endif /* CONFIG_PPC64 */ #define ARCH_IRQ_INIT_FLAGS IRQ_NOREQUEST @@ -193,6 +149,5 @@ static inline void may_hard_irq_enable(void) { } */ struct irq_chip; -#endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_HW_IRQ_H */ diff --git a/trunk/arch/powerpc/include/asm/irqflags.h b/trunk/arch/powerpc/include/asm/irqflags.h index 6f9b6e23dc5a..b0b06d85788d 100644 --- a/trunk/arch/powerpc/include/asm/irqflags.h +++ b/trunk/arch/powerpc/include/asm/irqflags.h @@ -39,31 +39,24 @@ #define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) #define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) -/* - * This is used by assembly code to soft-disable interrupts - */ -#define SOFT_DISABLE_INTS(__rA, __rB) \ - lbz __rA,PACASOFTIRQEN(r13); \ - lbz __rB,PACAIRQHAPPENED(r13); \ - cmpwi cr0,__rA,0; \ - li __rA,0; \ - ori __rB,__rB,PACA_IRQ_HARD_DIS; \ - stb __rB,PACAIRQHAPPENED(r13); \ - beq 44f; \ - stb __rA,PACASOFTIRQEN(r13); \ - TRACE_DISABLE_INTS; \ -44: - +#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) \ + cmpdi en,0; \ + bne 95f; \ + stb en,PACASOFTIRQEN(r13); \ + TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) \ + b skip; \ +95: TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) \ + li en,1; +#define TRACE_AND_RESTORE_IRQ(en) \ + TRACE_AND_RESTORE_IRQ_PARTIAL(en,96f); \ + stb en,PACASOFTIRQEN(r13); \ +96: #else #define TRACE_ENABLE_INTS #define TRACE_DISABLE_INTS - -#define SOFT_DISABLE_INTS(__rA, __rB) \ - lbz __rA,PACAIRQHAPPENED(r13); \ - li __rB,0; \ - ori __rA,__rA,PACA_IRQ_HARD_DIS; \ - stb __rB,PACASOFTIRQEN(r13); \ - stb __rA,PACAIRQHAPPENED(r13) +#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) +#define TRACE_AND_RESTORE_IRQ(en) \ + stb en,PACASOFTIRQEN(r13) #endif #endif diff --git a/trunk/arch/powerpc/include/asm/iseries/alpaca.h b/trunk/arch/powerpc/include/asm/iseries/alpaca.h new file mode 100644 index 000000000000..c0cce6727a69 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/alpaca.h @@ -0,0 +1,31 @@ +/* + * Copyright © 2008 Stephen Rothwell IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ASM_POWERPC_ISERIES_ALPACA_H +#define _ASM_POWERPC_ISERIES_ALPACA_H + +/* + * This is the part of the paca that the iSeries hypervisor + * needs to be statically initialised. Immediately after boot + * we switch to the normal Linux paca. + */ +struct alpaca { + struct lppaca *lppaca_ptr; /* Pointer to LpPaca for PLIC */ + const void *reg_save_ptr; /* Pointer to LpRegSave for PLIC */ +}; + +#endif /* _ASM_POWERPC_ISERIES_ALPACA_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/hv_call.h b/trunk/arch/powerpc/include/asm/iseries/hv_call.h new file mode 100644 index 000000000000..162d653ad51f --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/hv_call.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ +#ifndef _ASM_POWERPC_ISERIES_HV_CALL_H +#define _ASM_POWERPC_ISERIES_HV_CALL_H + +#include +#include +#include + +/* Type of yield for HvCallBaseYieldProcessor */ +#define HvCall_YieldTimed 0 /* Yield until specified time (tb) */ +#define HvCall_YieldToActive 1 /* Yield until all active procs have run */ +#define HvCall_YieldToProc 2 /* Yield until the specified processor has run */ + +/* interrupt masks for setEnabledInterrupts */ +#define HvCall_MaskIPI 0x00000001 +#define HvCall_MaskLpEvent 0x00000002 +#define HvCall_MaskLpProd 0x00000004 +#define HvCall_MaskTimeout 0x00000008 + +/* Log buffer formats */ +#define HvCall_LogBuffer_ASCII 0 +#define HvCall_LogBuffer_EBCDIC 1 + +#define HvCallBaseAckDeferredInts HvCallBase + 0 +#define HvCallBaseCpmPowerOff HvCallBase + 1 +#define HvCallBaseGetHwPatch HvCallBase + 2 +#define HvCallBaseReIplSpAttn HvCallBase + 3 +#define HvCallBaseSetASR HvCallBase + 4 +#define HvCallBaseSetASRAndRfi HvCallBase + 5 +#define HvCallBaseSetIMR HvCallBase + 6 +#define HvCallBaseSendIPI HvCallBase + 7 +#define HvCallBaseTerminateMachine HvCallBase + 8 +#define HvCallBaseTerminateMachineSrc HvCallBase + 9 +#define HvCallBaseProcessPlicInterrupts HvCallBase + 10 +#define HvCallBaseIsPrimaryCpmOrMsdIpl HvCallBase + 11 +#define HvCallBaseSetVirtualSIT HvCallBase + 12 +#define HvCallBaseVaryOffThisProcessor HvCallBase + 13 +#define HvCallBaseVaryOffMemoryChunk HvCallBase + 14 +#define HvCallBaseVaryOffInteractivePercentage HvCallBase + 15 +#define HvCallBaseSendLpProd HvCallBase + 16 +#define HvCallBaseSetEnabledInterrupts HvCallBase + 17 +#define HvCallBaseYieldProcessor HvCallBase + 18 +#define HvCallBaseVaryOffSharedProcUnits HvCallBase + 19 +#define HvCallBaseSetVirtualDecr HvCallBase + 20 +#define HvCallBaseClearLogBuffer HvCallBase + 21 +#define HvCallBaseGetLogBufferCodePage HvCallBase + 22 +#define HvCallBaseGetLogBufferFormat HvCallBase + 23 +#define HvCallBaseGetLogBufferLength HvCallBase + 24 +#define HvCallBaseReadLogBuffer HvCallBase + 25 +#define HvCallBaseSetLogBufferFormatAndCodePage HvCallBase + 26 +#define HvCallBaseWriteLogBuffer HvCallBase + 27 +#define HvCallBaseRouter28 HvCallBase + 28 +#define HvCallBaseRouter29 HvCallBase + 29 +#define HvCallBaseRouter30 HvCallBase + 30 +#define HvCallBaseSetDebugBus HvCallBase + 31 + +#define HvCallCcSetDABR HvCallCc + 7 + +static inline void HvCall_setVirtualDecr(void) +{ + /* + * Ignore any error return codes - most likely means that the + * target value for the LP has been increased and this vary off + * would bring us below the new target. + */ + HvCall0(HvCallBaseSetVirtualDecr); +} + +static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm) +{ + HvCall2(HvCallBaseYieldProcessor, typeOfYield, yieldParm); +} + +static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts) +{ + HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts); +} + +static inline void HvCall_setLogBufferFormatAndCodepage(int format, + u32 codePage) +{ + HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage); +} + +extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen); + +static inline void HvCall_sendIPI(struct paca_struct *targetPaca) +{ + HvCall1(HvCallBaseSendIPI, targetPaca->paca_index); +} + +#endif /* _ASM_POWERPC_ISERIES_HV_CALL_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/hv_call_event.h b/trunk/arch/powerpc/include/asm/iseries/hv_call_event.h new file mode 100644 index 000000000000..cc029d388e11 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/hv_call_event.h @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ +#ifndef _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H +#define _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H + +#include +#include + +#include +#include +#include + +struct HvLpEvent; + +typedef u8 HvLpEvent_Type; +typedef u8 HvLpEvent_AckInd; +typedef u8 HvLpEvent_AckType; + +typedef u8 HvLpDma_Direction; +typedef u8 HvLpDma_AddressType; + +typedef u64 HvLpEvent_Rc; +typedef u64 HvLpDma_Rc; + +#define HvCallEventAckLpEvent HvCallEvent + 0 +#define HvCallEventCancelLpEvent HvCallEvent + 1 +#define HvCallEventCloseLpEventPath HvCallEvent + 2 +#define HvCallEventDmaBufList HvCallEvent + 3 +#define HvCallEventDmaSingle HvCallEvent + 4 +#define HvCallEventDmaToSp HvCallEvent + 5 +#define HvCallEventGetOverflowLpEvents HvCallEvent + 6 +#define HvCallEventGetSourceLpInstanceId HvCallEvent + 7 +#define HvCallEventGetTargetLpInstanceId HvCallEvent + 8 +#define HvCallEventOpenLpEventPath HvCallEvent + 9 +#define HvCallEventSetLpEventStack HvCallEvent + 10 +#define HvCallEventSignalLpEvent HvCallEvent + 11 +#define HvCallEventSignalLpEventParms HvCallEvent + 12 +#define HvCallEventSetInterLpQueueIndex HvCallEvent + 13 +#define HvCallEventSetLpEventQueueInterruptProc HvCallEvent + 14 +#define HvCallEventRouter15 HvCallEvent + 15 + +static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex) +{ + HvCall1(HvCallEventGetOverflowLpEvents, queueIndex); +} + +static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex) +{ + HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex); +} + +static inline void HvCallEvent_setLpEventStack(u8 queueIndex, + char *eventStackAddr, u32 eventStackSize) +{ + HvCall3(HvCallEventSetLpEventStack, queueIndex, + virt_to_abs(eventStackAddr), eventStackSize); +} + +static inline void HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex, + u16 lpLogicalProcIndex) +{ + HvCall2(HvCallEventSetLpEventQueueInterruptProc, queueIndex, + lpLogicalProcIndex); +} + +static inline HvLpEvent_Rc HvCallEvent_signalLpEvent(struct HvLpEvent *event) +{ + return HvCall1(HvCallEventSignalLpEvent, virt_to_abs(event)); +} + +static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp, + HvLpEvent_Type type, u16 subtype, HvLpEvent_AckInd ackInd, + HvLpEvent_AckType ackType, HvLpInstanceId sourceInstanceId, + HvLpInstanceId targetInstanceId, u64 correlationToken, + u64 eventData1, u64 eventData2, u64 eventData3, + u64 eventData4, u64 eventData5) +{ + /* Pack the misc bits into a single Dword to pass to PLIC */ + union { + struct { + u8 ack_and_target; + u8 type; + u16 subtype; + HvLpInstanceId src_inst; + HvLpInstanceId target_inst; + } parms; + u64 dword; + } packed; + + packed.parms.ack_and_target = (ackType << 7) | (ackInd << 6) | targetLp; + packed.parms.type = type; + packed.parms.subtype = subtype; + packed.parms.src_inst = sourceInstanceId; + packed.parms.target_inst = targetInstanceId; + + return HvCall7(HvCallEventSignalLpEventParms, packed.dword, + correlationToken, eventData1, eventData2, + eventData3, eventData4, eventData5); +} + +extern void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag); +extern void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle); +extern dma_addr_t iseries_hv_map(void *vaddr, size_t size, + enum dma_data_direction direction); +extern void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); + +static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event) +{ + return HvCall1(HvCallEventAckLpEvent, virt_to_abs(event)); +} + +static inline HvLpEvent_Rc HvCallEvent_cancelLpEvent(struct HvLpEvent *event) +{ + return HvCall1(HvCallEventCancelLpEvent, virt_to_abs(event)); +} + +static inline HvLpInstanceId HvCallEvent_getSourceLpInstanceId( + HvLpIndex targetLp, HvLpEvent_Type type) +{ + return HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type); +} + +static inline HvLpInstanceId HvCallEvent_getTargetLpInstanceId( + HvLpIndex targetLp, HvLpEvent_Type type) +{ + return HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type); +} + +static inline void HvCallEvent_openLpEventPath(HvLpIndex targetLp, + HvLpEvent_Type type) +{ + HvCall2(HvCallEventOpenLpEventPath, targetLp, type); +} + +static inline void HvCallEvent_closeLpEventPath(HvLpIndex targetLp, + HvLpEvent_Type type) +{ + HvCall2(HvCallEventCloseLpEventPath, targetLp, type); +} + +static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type, + HvLpIndex remoteLp, HvLpDma_Direction direction, + HvLpInstanceId localInstanceId, + HvLpInstanceId remoteInstanceId, + HvLpDma_AddressType localAddressType, + HvLpDma_AddressType remoteAddressType, + /* Do these need to be converted to absolute addresses? */ + u64 localBufList, u64 remoteBufList, u32 transferLength) +{ + /* Pack the misc bits into a single Dword to pass to PLIC */ + union { + struct { + u8 flags; + HvLpIndex remote; + u8 type; + u8 reserved; + HvLpInstanceId local_inst; + HvLpInstanceId remote_inst; + } parms; + u64 dword; + } packed; + + packed.parms.flags = (direction << 7) | + (localAddressType << 6) | (remoteAddressType << 5); + packed.parms.remote = remoteLp; + packed.parms.type = type; + packed.parms.reserved = 0; + packed.parms.local_inst = localInstanceId; + packed.parms.remote_inst = remoteInstanceId; + + return HvCall4(HvCallEventDmaBufList, packed.dword, localBufList, + remoteBufList, transferLength); +} + +static inline HvLpDma_Rc HvCallEvent_dmaToSp(void *local, u32 remote, + u32 length, HvLpDma_Direction dir) +{ + return HvCall4(HvCallEventDmaToSp, virt_to_abs(local), remote, + length, dir); +} + +#endif /* _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/hv_call_sc.h b/trunk/arch/powerpc/include/asm/iseries/hv_call_sc.h new file mode 100644 index 000000000000..f5d210959250 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/hv_call_sc.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ASM_POWERPC_ISERIES_HV_CALL_SC_H +#define _ASM_POWERPC_ISERIES_HV_CALL_SC_H + +#include + +#define HvCallBase 0x8000000000000000ul +#define HvCallCc 0x8001000000000000ul +#define HvCallCfg 0x8002000000000000ul +#define HvCallEvent 0x8003000000000000ul +#define HvCallHpt 0x8004000000000000ul +#define HvCallPci 0x8005000000000000ul +#define HvCallSm 0x8007000000000000ul +#define HvCallXm 0x8009000000000000ul + +extern u64 HvCall0(u64); +extern u64 HvCall1(u64, u64); +extern u64 HvCall2(u64, u64, u64); +extern u64 HvCall3(u64, u64, u64, u64); +extern u64 HvCall4(u64, u64, u64, u64, u64); +extern u64 HvCall5(u64, u64, u64, u64, u64, u64); +extern u64 HvCall6(u64, u64, u64, u64, u64, u64, u64); +extern u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64); + +extern u64 HvCall0Ret16(u64, void *); +extern u64 HvCall1Ret16(u64, void *, u64); +extern u64 HvCall2Ret16(u64, void *, u64, u64); +extern u64 HvCall3Ret16(u64, void *, u64, u64, u64); +extern u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64); +extern u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64); +extern u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64); +extern u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64); + +#endif /* _ASM_POWERPC_ISERIES_HV_CALL_SC_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/hv_call_xm.h b/trunk/arch/powerpc/include/asm/iseries/hv_call_xm.h new file mode 100644 index 000000000000..392ac3f54df0 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/hv_call_xm.h @@ -0,0 +1,61 @@ +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from SLIC. + */ +#ifndef _ASM_POWERPC_ISERIES_HV_CALL_XM_H +#define _ASM_POWERPC_ISERIES_HV_CALL_XM_H + +#include +#include + +#define HvCallXmGetTceTableParms HvCallXm + 0 +#define HvCallXmTestBus HvCallXm + 1 +#define HvCallXmConnectBusUnit HvCallXm + 2 +#define HvCallXmLoadTod HvCallXm + 8 +#define HvCallXmTestBusUnit HvCallXm + 9 +#define HvCallXmSetTce HvCallXm + 11 +#define HvCallXmSetTces HvCallXm + 13 + +static inline void HvCallXm_getTceTableParms(u64 cb) +{ + HvCall1(HvCallXmGetTceTableParms, cb); +} + +static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce) +{ + return HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce); +} + +static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset, + u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4) +{ + return HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces, + tce1, tce2, tce3, tce4); +} + +static inline u64 HvCallXm_testBus(u16 busNumber) +{ + return HvCall1(HvCallXmTestBus, busNumber); +} + +static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber, + u8 deviceId) +{ + return HvCall2(HvCallXmTestBusUnit, busNumber, + (subBusNumber << 8) | deviceId); +} + +static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber, + u8 deviceId, u64 interruptToken) +{ + return HvCall5(HvCallXmConnectBusUnit, busNumber, + (subBusNumber << 8) | deviceId, interruptToken, 0, + 0 /* HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard)) */); +} + +static inline u64 HvCallXm_loadTod(void) +{ + return HvCall0(HvCallXmLoadTod); +} + +#endif /* _ASM_POWERPC_ISERIES_HV_CALL_XM_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/hv_lp_config.h b/trunk/arch/powerpc/include/asm/iseries/hv_lp_config.h new file mode 100644 index 000000000000..a006fd1e4a2c --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/hv_lp_config.h @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H +#define _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H + +/* + * This file contains the interface to the LPAR configuration data + * to determine which resources should be allocated to each partition. + */ + +#include +#include + +enum { + HvCallCfg_Cur = 0, + HvCallCfg_Init = 1, + HvCallCfg_Max = 2, + HvCallCfg_Min = 3 +}; + +#define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6 +#define HvCallCfgGetPhysicalProcessors HvCallCfg + 7 +#define HvCallCfgGetMsChunks HvCallCfg + 9 +#define HvCallCfgGetSharedPoolIndex HvCallCfg + 20 +#define HvCallCfgGetSharedProcUnits HvCallCfg + 21 +#define HvCallCfgGetNumProcsInSharedPool HvCallCfg + 22 +#define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30 +#define HvCallCfgGetHostingLpIndex HvCallCfg + 32 + +extern HvLpIndex HvLpConfig_getLpIndex_outline(void); +extern HvLpIndex HvLpConfig_getLpIndex(void); +extern HvLpIndex HvLpConfig_getPrimaryLpIndex(void); + +static inline u64 HvLpConfig_getMsChunks(void) +{ + return HvCall2(HvCallCfgGetMsChunks, HvLpConfig_getLpIndex(), + HvCallCfg_Cur); +} + +static inline u64 HvLpConfig_getSystemPhysicalProcessors(void) +{ + return HvCall0(HvCallCfgGetSystemPhysicalProcessors); +} + +static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) +{ + return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); +} + +static inline u64 HvLpConfig_getPhysicalProcessors(void) +{ + return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), + HvCallCfg_Cur); +} + +static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void) +{ + return HvCall1(HvCallCfgGetSharedPoolIndex, HvLpConfig_getLpIndex()); +} + +static inline u64 HvLpConfig_getSharedProcUnits(void) +{ + return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), + HvCallCfg_Cur); +} + +static inline u64 HvLpConfig_getMaxSharedProcUnits(void) +{ + return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), + HvCallCfg_Max); +} + +static inline u64 HvLpConfig_getMaxPhysicalProcessors(void) +{ + return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), + HvCallCfg_Max); +} + +static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp( + HvLpIndex lp) +{ + /* + * This is a new function in V5R1 so calls to this on older + * hypervisors will return -1 + */ + u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); + if (retVal == -1) + retVal = 0; + return retVal; +} + +static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) +{ + return HvLpConfig_getVirtualLanIndexMapForLp( + HvLpConfig_getLpIndex_outline()); +} + +static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, + HvLpIndex lp2) +{ + HvLpVirtualLanIndexMap virtualLanIndexMap1 = + HvLpConfig_getVirtualLanIndexMapForLp(lp1); + HvLpVirtualLanIndexMap virtualLanIndexMap2 = + HvLpConfig_getVirtualLanIndexMapForLp(lp2); + return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0); +} + +static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp) +{ + return HvCall1(HvCallCfgGetHostingLpIndex, lp); +} + +#endif /* _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/hv_lp_event.h b/trunk/arch/powerpc/include/asm/iseries/hv_lp_event.h new file mode 100644 index 000000000000..8f5da7d77202 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/hv_lp_event.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* This file contains the class for HV events in the system. */ + +#ifndef _ASM_POWERPC_ISERIES_HV_LP_EVENT_H +#define _ASM_POWERPC_ISERIES_HV_LP_EVENT_H + +#include +#include +#include +#include + +/* + * HvLpEvent is the structure for Lp Event messages passed between + * partitions through PLIC. + */ + +struct HvLpEvent { + u8 flags; /* Event flags x00-x00 */ + u8 xType; /* Type of message x01-x01 */ + u16 xSubtype; /* Subtype for event x02-x03 */ + u8 xSourceLp; /* Source LP x04-x04 */ + u8 xTargetLp; /* Target LP x05-x05 */ + u8 xSizeMinus1; /* Size of Derived class - 1 x06-x06 */ + u8 xRc; /* RC for Ack flows x07-x07 */ + u16 xSourceInstanceId; /* Source sides instance id x08-x09 */ + u16 xTargetInstanceId; /* Target sides instance id x0A-x0B */ + union { + u32 xSubtypeData; /* Data usable by the subtype x0C-x0F */ + u16 xSubtypeDataShort[2]; /* Data as 2 shorts */ + u8 xSubtypeDataChar[4]; /* Data as 4 chars */ + } x; + + u64 xCorrelationToken; /* Unique value for source/type x10-x17 */ +}; + +typedef void (*LpEventHandler)(struct HvLpEvent *); + +/* Register a handler for an event type - returns 0 on success */ +extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType, + LpEventHandler hdlr); + +/* + * Unregister a handler for an event type + * + * This call will sleep until the handler being removed is guaranteed to + * be no longer executing on any CPU. Do not call with locks held. + * + * returns 0 on success + * Unregister will fail if there are any paths open for the type + */ +extern int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType); + +/* + * Open an Lp Event Path for an event type + * returns 0 on success + * openPath will fail if there is no handler registered for the event type. + * The lpIndex specified is the partition index for the target partition + * (for VirtualIo, VirtualLan and SessionMgr) other types specify zero) + */ +extern int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex); + +/* + * Close an Lp Event Path for a type and partition + * returns 0 on success + */ +extern int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex); + +#define HvLpEvent_Type_Hypervisor 0 +#define HvLpEvent_Type_MachineFac 1 +#define HvLpEvent_Type_SessionMgr 2 +#define HvLpEvent_Type_SpdIo 3 +#define HvLpEvent_Type_VirtualBus 4 +#define HvLpEvent_Type_PciIo 5 +#define HvLpEvent_Type_RioIo 6 +#define HvLpEvent_Type_VirtualLan 7 +#define HvLpEvent_Type_VirtualIo 8 +#define HvLpEvent_Type_NumTypes 9 + +#define HvLpEvent_Rc_Good 0 +#define HvLpEvent_Rc_BufferNotAvailable 1 +#define HvLpEvent_Rc_Cancelled 2 +#define HvLpEvent_Rc_GenericError 3 +#define HvLpEvent_Rc_InvalidAddress 4 +#define HvLpEvent_Rc_InvalidPartition 5 +#define HvLpEvent_Rc_InvalidSize 6 +#define HvLpEvent_Rc_InvalidSubtype 7 +#define HvLpEvent_Rc_InvalidSubtypeData 8 +#define HvLpEvent_Rc_InvalidType 9 +#define HvLpEvent_Rc_PartitionDead 10 +#define HvLpEvent_Rc_PathClosed 11 +#define HvLpEvent_Rc_SubtypeError 12 + +#define HvLpEvent_Function_Ack 0 +#define HvLpEvent_Function_Int 1 + +#define HvLpEvent_AckInd_NoAck 0 +#define HvLpEvent_AckInd_DoAck 1 + +#define HvLpEvent_AckType_ImmediateAck 0 +#define HvLpEvent_AckType_DeferredAck 1 + +#define HV_LP_EVENT_INT 0x01 +#define HV_LP_EVENT_DO_ACK 0x02 +#define HV_LP_EVENT_DEFERRED_ACK 0x04 +#define HV_LP_EVENT_VALID 0x80 + +#define HvLpDma_Direction_LocalToRemote 0 +#define HvLpDma_Direction_RemoteToLocal 1 + +#define HvLpDma_AddressType_TceIndex 0 +#define HvLpDma_AddressType_RealAddress 1 + +#define HvLpDma_Rc_Good 0 +#define HvLpDma_Rc_Error 1 +#define HvLpDma_Rc_PartitionDead 2 +#define HvLpDma_Rc_PathClosed 3 +#define HvLpDma_Rc_InvalidAddress 4 +#define HvLpDma_Rc_InvalidLength 5 + +static inline int hvlpevent_is_valid(struct HvLpEvent *h) +{ + return h->flags & HV_LP_EVENT_VALID; +} + +static inline void hvlpevent_invalidate(struct HvLpEvent *h) +{ + h->flags &= ~ HV_LP_EVENT_VALID; +} + +static inline int hvlpevent_is_int(struct HvLpEvent *h) +{ + return h->flags & HV_LP_EVENT_INT; +} + +static inline int hvlpevent_is_ack(struct HvLpEvent *h) +{ + return !hvlpevent_is_int(h); +} + +static inline int hvlpevent_need_ack(struct HvLpEvent *h) +{ + return h->flags & HV_LP_EVENT_DO_ACK; +} + +#endif /* _ASM_POWERPC_ISERIES_HV_LP_EVENT_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/hv_types.h b/trunk/arch/powerpc/include/asm/iseries/hv_types.h new file mode 100644 index 000000000000..c3e6d2a1d1c3 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/hv_types.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ASM_POWERPC_ISERIES_HV_TYPES_H +#define _ASM_POWERPC_ISERIES_HV_TYPES_H + +/* + * General typedefs for the hypervisor. + */ + +#include + +typedef u8 HvLpIndex; +typedef u16 HvLpInstanceId; +typedef u64 HvLpTOD; +typedef u64 HvLpSystemSerialNum; +typedef u8 HvLpDeviceSerialNum[12]; +typedef u16 HvLpSanHwSet; +typedef u16 HvLpBus; +typedef u16 HvLpBoard; +typedef u16 HvLpCard; +typedef u8 HvLpDeviceType[4]; +typedef u8 HvLpDeviceModel[3]; +typedef u64 HvIoToken; +typedef u8 HvLpName[8]; +typedef u32 HvIoId; +typedef u64 HvRealMemoryIndex; +typedef u32 HvLpIndexMap; /* Must hold HVMAXARCHITECTEDLPS bits!!! */ +typedef u16 HvLpVrmIndex; +typedef u32 HvXmGenerationId; +typedef u8 HvLpBusPool; +typedef u8 HvLpSharedPoolIndex; +typedef u16 HvLpSharedProcUnitsX100; +typedef u8 HvLpVirtualLanIndex; +typedef u16 HvLpVirtualLanIndexMap; /* Must hold HVMAXARCHITECTEDVIRTUALLANS bits!!! */ +typedef u16 HvBusNumber; /* Hypervisor Bus Number */ +typedef u8 HvSubBusNumber; /* Hypervisor SubBus Number */ +typedef u8 HvAgentId; /* Hypervisor DevFn */ + + +#define HVMAXARCHITECTEDLPS 32 +#define HVMAXARCHITECTEDVIRTUALLANS 16 +#define HVMAXARCHITECTEDVIRTUALDISKS 32 +#define HVMAXARCHITECTEDVIRTUALCDROMS 8 +#define HVMAXARCHITECTEDVIRTUALTAPES 8 +#define HVCHUNKSIZE (256 * 1024) +#define HVPAGESIZE (4 * 1024) +#define HVLPMINMEGSPRIMARY 256 +#define HVLPMINMEGSSECONDARY 64 +#define HVCHUNKSPERMEG 4 +#define HVPAGESPERMEG 256 +#define HVPAGESPERCHUNK 64 + +#define HvLpIndexInvalid ((HvLpIndex)0xff) + +/* + * Enums for the sub-components under PLIC + * Used in HvCall and HvPrimaryCall + */ +enum { + HvCallCompId = 0, + HvCallCpuCtlsCompId = 1, + HvCallCfgCompId = 2, + HvCallEventCompId = 3, + HvCallHptCompId = 4, + HvCallPciCompId = 5, + HvCallSlmCompId = 6, + HvCallSmCompId = 7, + HvCallSpdCompId = 8, + HvCallXmCompId = 9, + HvCallRioCompId = 10, + HvCallRsvd3CompId = 11, + HvCallRsvd2CompId = 12, + HvCallRsvd1CompId = 13, + HvCallMaxCompId = 14, + HvPrimaryCallCompId = 0, + HvPrimaryCallCfgCompId = 1, + HvPrimaryCallPciCompId = 2, + HvPrimaryCallSmCompId = 3, + HvPrimaryCallSpdCompId = 4, + HvPrimaryCallXmCompId = 5, + HvPrimaryCallRioCompId = 6, + HvPrimaryCallRsvd7CompId = 7, + HvPrimaryCallRsvd6CompId = 8, + HvPrimaryCallRsvd5CompId = 9, + HvPrimaryCallRsvd4CompId = 10, + HvPrimaryCallRsvd3CompId = 11, + HvPrimaryCallRsvd2CompId = 12, + HvPrimaryCallRsvd1CompId = 13, + HvPrimaryCallMaxCompId = HvCallMaxCompId +}; + +struct HvLpBufferList { + u64 addr; + u64 len; +}; + +#endif /* _ASM_POWERPC_ISERIES_HV_TYPES_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/iommu.h b/trunk/arch/powerpc/include/asm/iseries/iommu.h new file mode 100644 index 000000000000..1b9692c60899 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/iommu.h @@ -0,0 +1,37 @@ +#ifndef _ASM_POWERPC_ISERIES_IOMMU_H +#define _ASM_POWERPC_ISERIES_IOMMU_H + +/* + * Copyright (C) 2005 Stephen Rothwell, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + */ + +struct pci_dev; +struct vio_dev; +struct device_node; +struct iommu_table; + +/* Get table parameters from HV */ +extern void iommu_table_getparms_iSeries(unsigned long busno, + unsigned char slotno, unsigned char virtbus, + struct iommu_table *tbl); + +extern struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev); +extern void iommu_vio_init(void); + +#endif /* _ASM_POWERPC_ISERIES_IOMMU_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/it_lp_queue.h b/trunk/arch/powerpc/include/asm/iseries/it_lp_queue.h new file mode 100644 index 000000000000..428278838821 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/it_lp_queue.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H +#define _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H + +/* + * This control block defines the simple LP queue structure that is + * shared between the hypervisor (PLIC) and the OS in order to send + * events to an LP. + */ + +#include +#include + +#define IT_LP_MAX_QUEUES 8 + +#define IT_LP_NOT_USED 0 /* Queue will not be used by PLIC */ +#define IT_LP_DEDICATED_IO 1 /* Queue dedicated to IO processor specified */ +#define IT_LP_DEDICATED_LP 2 /* Queue dedicated to LP specified */ +#define IT_LP_SHARED 3 /* Queue shared for both IO and LP */ + +#define IT_LP_EVENT_STACK_SIZE 4096 +#define IT_LP_EVENT_MAX_SIZE 256 +#define IT_LP_EVENT_ALIGN 64 + +struct hvlpevent_queue { +/* + * The hq_current_event is the pointer to the next event stack entry + * that will become valid. The OS must peek at this entry to determine + * if it is valid. PLIC will set the valid indicator as the very last + * store into that entry. + * + * When the OS has completed processing of the event then it will mark + * the event as invalid so that PLIC knows it can store into that event + * location again. + * + * If the event stack fills and there are overflow events, then PLIC + * will set the hq_overflow_pending flag in which case the OS will + * have to fetch the additional LP events once they have drained the + * event stack. + * + * The first 16-bytes are known by both the OS and PLIC. The remainder + * of the cache line is for use by the OS. + */ + u8 hq_overflow_pending; /* 0x00 Overflow events are pending */ + u8 hq_status; /* 0x01 DedicatedIo or DedicatedLp or NotUsed */ + u16 hq_proc_index; /* 0x02 Logical Proc Index for correlation */ + u8 hq_reserved1[12]; /* 0x04 */ + char *hq_current_event; /* 0x10 */ + char *hq_last_event; /* 0x18 */ + char *hq_event_stack; /* 0x20 */ + u8 hq_index; /* 0x28 unique sequential index. */ + u8 hq_reserved2[3]; /* 0x29-2b */ + spinlock_t hq_lock; +}; + +extern struct hvlpevent_queue hvlpevent_queue; + +extern int hvlpevent_is_pending(void); +extern void process_hvlpevents(void); +extern void setup_hvlpevent_queue(void); + +#endif /* _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/lpar_map.h b/trunk/arch/powerpc/include/asm/iseries/lpar_map.h new file mode 100644 index 000000000000..5e9f3e128ee2 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/lpar_map.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ASM_POWERPC_ISERIES_LPAR_MAP_H +#define _ASM_POWERPC_ISERIES_LPAR_MAP_H + +#ifndef __ASSEMBLY__ + +#include + +#endif + +/* + * The iSeries hypervisor will set up mapping for one or more + * ESID/VSID pairs (in SLB/segment registers) and will set up + * mappings of one or more ranges of pages to VAs. + * We will have the hypervisor set up the ESID->VSID mapping + * for the four kernel segments (C-F). With shared processors, + * the hypervisor will clear all segment registers and reload + * these four whenever the processor is switched from one + * partition to another. + */ + +/* The Vsid and Esid identified below will be used by the hypervisor + * to set up a memory mapping for part of the load area before giving + * control to the Linux kernel. The load area is 64 MB, but this must + * not attempt to map the whole load area. The Hashed Page Table may + * need to be located within the load area (if the total partition size + * is 64 MB), but cannot be mapped. Typically, this should specify + * to map half (32 MB) of the load area. + * + * The hypervisor will set up page table entries for the number of + * pages specified. + * + * In 32-bit mode, the hypervisor will load all four of the + * segment registers (identified by the low-order four bits of the + * Esid field. In 64-bit mode, the hypervisor will load one SLB + * entry to map the Esid to the Vsid. +*/ + +#define HvEsidsToMap 2 +#define HvRangesToMap 1 + +/* Hypervisor initially maps 32MB of the load area */ +#define HvPagesToMap 8192 + +#ifndef __ASSEMBLY__ +struct LparMap { + u64 xNumberEsids; // Number of ESID/VSID pairs + u64 xNumberRanges; // Number of VA ranges to map + u64 xSegmentTableOffs; // Page number within load area of seg table + u64 xRsvd[5]; + struct { + u64 xKernelEsid; // Esid used to map kernel load + u64 xKernelVsid; // Vsid used to map kernel load + } xEsids[HvEsidsToMap]; + struct { + u64 xPages; // Number of pages to be mapped + u64 xOffset; // Offset from start of load area + u64 xVPN; // Virtual Page Number + } xRanges[HvRangesToMap]; +}; + +extern const struct LparMap xLparMap; + +#endif /* __ASSEMBLY__ */ + +/* the fixed address where the LparMap exists */ +#define LPARMAP_PHYS 0x7000 + +#endif /* _ASM_POWERPC_ISERIES_LPAR_MAP_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/mf.h b/trunk/arch/powerpc/include/asm/iseries/mf.h new file mode 100644 index 000000000000..eb851a9c9e5c --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/mf.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2001 Troy D. Armstrong IBM Corporation + * Copyright (C) 2004 Stephen Rothwell IBM Corporation + * + * This modules exists as an interface between a Linux secondary partition + * running on an iSeries and the primary partition's Virtual Service + * Processor (VSP) object. The VSP has final authority over powering on/off + * all partitions in the iSeries. It also provides miscellaneous low-level + * machine facility type operations. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ASM_POWERPC_ISERIES_MF_H +#define _ASM_POWERPC_ISERIES_MF_H + +#include + +#include +#include + +struct rtc_time; + +typedef void (*MFCompleteHandler)(void *clientToken, int returnCode); + +extern void mf_allocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type, + unsigned size, unsigned amount, MFCompleteHandler hdlr, + void *userToken); +extern void mf_deallocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type, + unsigned count, MFCompleteHandler hdlr, void *userToken); + +extern void mf_power_off(void); +extern void mf_reboot(char *cmd); + +extern void mf_display_src(u32 word); +extern void mf_display_progress(u16 value); + +extern void mf_init(void); + +#endif /* _ASM_POWERPC_ISERIES_MF_H */ diff --git a/trunk/arch/powerpc/include/asm/iseries/vio.h b/trunk/arch/powerpc/include/asm/iseries/vio.h new file mode 100644 index 000000000000..f9ac0d00b951 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/iseries/vio.h @@ -0,0 +1,265 @@ +/* -*- linux-c -*- + * + * iSeries Virtual I/O Message Path header + * + * Authors: Dave Boutcher + * Ryan Arnold + * Colin Devilbiss + * + * (C) Copyright 2000 IBM Corporation + * + * This header file is used by the iSeries virtual I/O device + * drivers. It defines the interfaces to the common functions + * (implemented in drivers/char/viopath.h) as well as defining + * common functions and structures. Currently (at the time I + * wrote this comment) the iSeries virtual I/O device drivers + * that use this are + * drivers/block/viodasd.c + * drivers/char/viocons.c + * drivers/char/viotape.c + * drivers/cdrom/viocd.c + * + * The iSeries virtual ethernet support (veth.c) uses a whole + * different set of functions. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) anyu later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef _ASM_POWERPC_ISERIES_VIO_H +#define _ASM_POWERPC_ISERIES_VIO_H + +#include +#include + +/* + * iSeries virtual I/O events use the subtype field in + * HvLpEvent to figure out what kind of vio event is coming + * in. We use a table to route these, and this defines + * the maximum number of distinct subtypes + */ +#define VIO_MAX_SUBTYPES 8 + +#define VIOMAXBLOCKDMA 12 + +struct open_data { + u64 disk_size; + u16 max_disk; + u16 cylinders; + u16 tracks; + u16 sectors; + u16 bytes_per_sector; +}; + +struct rw_data { + u64 offset; + struct { + u32 token; + u32 reserved; + u64 len; + } dma_info[VIOMAXBLOCKDMA]; +}; + +struct vioblocklpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_result; + u16 disk; + u16 flags; + union { + struct open_data open_data; + struct rw_data rw_data; + u64 changed; + } u; +}; + +#define vioblockflags_ro 0x0001 + +enum vioblocksubtype { + vioblockopen = 0x0001, + vioblockclose = 0x0002, + vioblockread = 0x0003, + vioblockwrite = 0x0004, + vioblockflush = 0x0005, + vioblockcheck = 0x0007 +}; + +struct viocdlpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_result; + u16 disk; + u16 flags; + u32 token; + u64 offset; /* On open, max number of disks */ + u64 len; /* On open, size of the disk */ + u32 block_size; /* Only set on open */ + u32 media_size; /* Only set on open */ +}; + +enum viocdsubtype { + viocdopen = 0x0001, + viocdclose = 0x0002, + viocdread = 0x0003, + viocdwrite = 0x0004, + viocdlockdoor = 0x0005, + viocdgetinfo = 0x0006, + viocdcheck = 0x0007 +}; + +struct viotapelpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 sub_type_result; + u16 tape; + u16 flags; + u32 token; + u64 len; + union { + struct { + u32 tape_op; + u32 count; + } op; + struct { + u32 type; + u32 resid; + u32 dsreg; + u32 gstat; + u32 erreg; + u32 file_no; + u32 block_no; + } get_status; + struct { + u32 block_no; + } get_pos; + } u; +}; + +enum viotapesubtype { + viotapeopen = 0x0001, + viotapeclose = 0x0002, + viotaperead = 0x0003, + viotapewrite = 0x0004, + viotapegetinfo = 0x0005, + viotapeop = 0x0006, + viotapegetpos = 0x0007, + viotapesetpos = 0x0008, + viotapegetstatus = 0x0009 +}; + +/* + * Each subtype can register a handler to process their events. + * The handler must have this interface. + */ +typedef void (vio_event_handler_t) (struct HvLpEvent * event); + +extern int viopath_open(HvLpIndex remoteLp, int subtype, int numReq); +extern int viopath_close(HvLpIndex remoteLp, int subtype, int numReq); +extern int vio_setHandler(int subtype, vio_event_handler_t * beh); +extern int vio_clearHandler(int subtype); +extern int viopath_isactive(HvLpIndex lp); +extern HvLpInstanceId viopath_sourceinst(HvLpIndex lp); +extern HvLpInstanceId viopath_targetinst(HvLpIndex lp); +extern void vio_set_hostlp(void); +extern void *vio_get_event_buffer(int subtype); +extern void vio_free_event_buffer(int subtype, void *buffer); + +extern struct vio_dev *vio_create_viodasd(u32 unit); + +extern HvLpIndex viopath_hostLp; +extern HvLpIndex viopath_ourLp; + +#define VIOCHAR_MAX_DATA 200 + +#define VIOMAJOR_SUBTYPE_MASK 0xff00 +#define VIOMINOR_SUBTYPE_MASK 0x00ff +#define VIOMAJOR_SUBTYPE_SHIFT 8 + +#define VIOVERSION 0x0101 + +/* + * This is the general structure for VIO errors; each module should have + * a table of them, and each table should be terminated by an entry of + * { 0, 0, NULL }. Then, to find a specific error message, a module + * should pass its local table and the return code. + */ +struct vio_error_entry { + u16 rc; + int errno; + const char *msg; +}; +extern const struct vio_error_entry *vio_lookup_rc( + const struct vio_error_entry *local_table, u16 rc); + +enum viosubtypes { + viomajorsubtype_monitor = 0x0100, + viomajorsubtype_blockio = 0x0200, + viomajorsubtype_chario = 0x0300, + viomajorsubtype_config = 0x0400, + viomajorsubtype_cdio = 0x0500, + viomajorsubtype_tape = 0x0600, + viomajorsubtype_scsi = 0x0700 +}; + +enum vioconfigsubtype { + vioconfigget = 0x0001, +}; + +enum viorc { + viorc_good = 0x0000, + viorc_noConnection = 0x0001, + viorc_noReceiver = 0x0002, + viorc_noBufferAvailable = 0x0003, + viorc_invalidMessageType = 0x0004, + viorc_invalidRange = 0x0201, + viorc_invalidToken = 0x0202, + viorc_DMAError = 0x0203, + viorc_useError = 0x0204, + viorc_releaseError = 0x0205, + viorc_invalidDisk = 0x0206, + viorc_openRejected = 0x0301 +}; + +/* + * The structure of the events that flow between us and OS/400 for chario + * events. You can't mess with this unless the OS/400 side changes too. + */ +struct viocharlpevent { + struct HvLpEvent event; + u32 reserved; + u16 version; + u16 subtype_result_code; + u8 virtual_device; + u8 len; + u8 data[VIOCHAR_MAX_DATA]; +}; + +#define VIOCHAR_WINDOW 10 + +enum viocharsubtype { + viocharopen = 0x0001, + viocharclose = 0x0002, + viochardata = 0x0003, + viocharack = 0x0004, + viocharconfig = 0x0005 +}; + +enum viochar_rc { + viochar_rc_ebusy = 1 +}; + +#endif /* _ASM_POWERPC_ISERIES_VIO_H */ diff --git a/trunk/arch/powerpc/include/asm/lppaca.h b/trunk/arch/powerpc/include/asm/lppaca.h index a76254af0aaa..e0298d26ce5d 100644 --- a/trunk/arch/powerpc/include/asm/lppaca.h +++ b/trunk/arch/powerpc/include/asm/lppaca.h @@ -41,7 +41,15 @@ * We only have to have statically allocated lppaca structs on * legacy iSeries, which supports at most 64 cpus. */ +#ifdef CONFIG_PPC_ISERIES +#if NR_CPUS < 64 +#define NR_LPPACAS NR_CPUS +#else +#define NR_LPPACAS 64 +#endif +#else /* not iSeries */ #define NR_LPPACAS 1 +#endif /* The Hypervisor barfs if the lppaca crosses a page boundary. A 1k diff --git a/trunk/arch/powerpc/include/asm/mpic.h b/trunk/arch/powerpc/include/asm/mpic.h index c65b9294376e..a5b7c56237f9 100644 --- a/trunk/arch/powerpc/include/asm/mpic.h +++ b/trunk/arch/powerpc/include/asm/mpic.h @@ -273,6 +273,7 @@ struct mpic unsigned int isu_size; unsigned int isu_shift; unsigned int isu_mask; + unsigned int irq_count; /* Number of sources */ unsigned int num_sources; /* default senses array */ @@ -348,6 +349,8 @@ struct mpic #define MPIC_U3_HT_IRQS 0x00000004 /* Broken IPI registers (autodetected) */ #define MPIC_BROKEN_IPI 0x00000008 +/* MPIC wants a reset */ +#define MPIC_WANTS_RESET 0x00000010 /* Spurious vector requires EOI */ #define MPIC_SPV_EOI 0x00000020 /* No passthrough disable */ @@ -360,11 +363,15 @@ struct mpic #define MPIC_ENABLE_MCK 0x00000200 /* Disable bias among target selection, spread interrupts evenly */ #define MPIC_NO_BIAS 0x00000400 +/* Ignore NIRQS as reported by FRR */ +#define MPIC_BROKEN_FRR_NIRQS 0x00000800 /* Destination only supports a single CPU at a time */ #define MPIC_SINGLE_DEST_CPU 0x00001000 /* Enable CoreInt delivery of interrupts */ #define MPIC_ENABLE_COREINT 0x00002000 -/* Do not reset the MPIC during initialization */ +/* Disable resetting of the MPIC. + * NOTE: This flag trumps MPIC_WANTS_RESET. + */ #define MPIC_NO_RESET 0x00004000 /* Freescale MPIC (compatible includes "fsl,mpic") */ #define MPIC_FSL 0x00008000 diff --git a/trunk/arch/powerpc/include/asm/mpic_msgr.h b/trunk/arch/powerpc/include/asm/mpic_msgr.h deleted file mode 100644 index 3ec37dc9003e..000000000000 --- a/trunk/arch/powerpc/include/asm/mpic_msgr.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 of the - * License. - * - */ - -#ifndef _ASM_MPIC_MSGR_H -#define _ASM_MPIC_MSGR_H - -#include -#include - -struct mpic_msgr { - u32 __iomem *base; - u32 __iomem *mer; - int irq; - unsigned char in_use; - raw_spinlock_t lock; - int num; -}; - -/* Get a message register - * - * @reg_num: the MPIC message register to get - * - * A pointer to the message register is returned. If - * the message register asked for is already in use, then - * EBUSY is returned. If the number given is not associated - * with an actual message register, then ENODEV is returned. - * Successfully getting the register marks it as in use. - */ -extern struct mpic_msgr *mpic_msgr_get(unsigned int reg_num); - -/* Relinquish a message register - * - * @msgr: the message register to return - * - * Disables the given message register and marks it as free. - * After this call has completed successully the message - * register is available to be acquired by a call to - * mpic_msgr_get. - */ -extern void mpic_msgr_put(struct mpic_msgr *msgr); - -/* Enable a message register - * - * @msgr: the message register to enable - * - * The given message register is enabled for sending - * messages. - */ -extern void mpic_msgr_enable(struct mpic_msgr *msgr); - -/* Disable a message register - * - * @msgr: the message register to disable - * - * The given message register is disabled for sending - * messages. - */ -extern void mpic_msgr_disable(struct mpic_msgr *msgr); - -/* Write a message to a message register - * - * @msgr: the message register to write to - * @message: the message to write - * - * The given 32-bit message is written to the given message - * register. Writing to an enabled message registers fires - * an interrupt. - */ -static inline void mpic_msgr_write(struct mpic_msgr *msgr, u32 message) -{ - out_be32(msgr->base, message); -} - -/* Read a message from a message register - * - * @msgr: the message register to read from - * - * Returns the 32-bit value currently in the given message register. - * Upon reading the register any interrupts for that register are - * cleared. - */ -static inline u32 mpic_msgr_read(struct mpic_msgr *msgr) -{ - return in_be32(msgr->base); -} - -/* Clear a message register - * - * @msgr: the message register to clear - * - * Clears any interrupts associated with the given message register. - */ -static inline void mpic_msgr_clear(struct mpic_msgr *msgr) -{ - (void) mpic_msgr_read(msgr); -} - -/* Set the destination CPU for the message register - * - * @msgr: the message register whose destination is to be set - * @cpu_num: the Linux CPU number to bind the message register to - * - * Note that the CPU number given is the CPU number used by the kernel - * and *not* the actual hardware CPU number. - */ -static inline void mpic_msgr_set_destination(struct mpic_msgr *msgr, - u32 cpu_num) -{ - out_be32(msgr->base, 1 << get_hard_smp_processor_id(cpu_num)); -} - -/* Get the IRQ number for the message register - * @msgr: the message register whose IRQ is to be returned - * - * Returns the IRQ number associated with the given message register. - * NO_IRQ is returned if this message register is not capable of - * receiving interrupts. What message register can and cannot receive - * interrupts is specified in the device tree for the system. - */ -static inline int mpic_msgr_get_irq(struct mpic_msgr *msgr) -{ - return msgr->irq; -} - -#endif diff --git a/trunk/arch/powerpc/include/asm/paca.h b/trunk/arch/powerpc/include/asm/paca.h index daf813fea91f..269c05a36d91 100644 --- a/trunk/arch/powerpc/include/asm/paca.h +++ b/trunk/arch/powerpc/include/asm/paca.h @@ -132,7 +132,7 @@ struct paca_struct { u64 saved_msr; /* MSR saved here by enter_rtas */ u16 trap_save; /* Used when bad stack is encountered */ u8 soft_enabled; /* irq soft-enable flag */ - u8 irq_happened; /* irq happened while soft-disabled */ + u8 hard_enabled; /* set if irqs are enabled in MSR */ u8 io_sync; /* writel() needs spin_unlock sync */ u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */ u8 nap_state_lost; /* NV GPR values lost in power7_idle */ diff --git a/trunk/arch/powerpc/include/asm/phyp_dump.h b/trunk/arch/powerpc/include/asm/phyp_dump.h new file mode 100644 index 000000000000..fa74c6c3e106 --- /dev/null +++ b/trunk/arch/powerpc/include/asm/phyp_dump.h @@ -0,0 +1,47 @@ +/* + * Hypervisor-assisted dump + * + * Linas Vepstas, Manish Ahuja 2008 + * Copyright 2008 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef _PPC64_PHYP_DUMP_H +#define _PPC64_PHYP_DUMP_H + +#ifdef CONFIG_PHYP_DUMP + +/* The RMR region will be saved for later dumping + * whenever the kernel crashes. Set this to 256MB. */ +#define PHYP_DUMP_RMR_START 0x0 +#define PHYP_DUMP_RMR_END (1UL<<28) + +struct phyp_dump { + /* Memory that is reserved during very early boot. */ + unsigned long init_reserve_start; + unsigned long init_reserve_size; + /* cmd line options during boot */ + unsigned long reserve_bootvar; + unsigned long phyp_dump_at_boot; + /* Check status during boot if dump supported, active & present*/ + unsigned long phyp_dump_configured; + unsigned long phyp_dump_is_active; + /* store cpu & hpte size */ + unsigned long cpu_state_size; + unsigned long hpte_region_size; + /* previous scratch area values */ + unsigned long reserved_scratch_addr; + unsigned long reserved_scratch_size; +}; + +extern struct phyp_dump *phyp_dump_info; + +int early_init_dt_scan_phyp_dump(unsigned long node, + const char *uname, int depth, void *data); + +#endif /* CONFIG_PHYP_DUMP */ +#endif /* _PPC64_PHYP_DUMP_H */ diff --git a/trunk/arch/powerpc/include/asm/ppc-pci.h b/trunk/arch/powerpc/include/asm/ppc-pci.h index e660b37aa7d0..6d422979ebaf 100644 --- a/trunk/arch/powerpc/include/asm/ppc-pci.h +++ b/trunk/arch/powerpc/include/asm/ppc-pci.h @@ -47,21 +47,92 @@ extern int rtas_setup_phb(struct pci_controller *phb); extern unsigned long pci_probe_only; +/* ---- EEH internal-use-only related routines ---- */ #ifdef CONFIG_EEH -void pci_addr_cache_build(void); void pci_addr_cache_insert_device(struct pci_dev *dev); void pci_addr_cache_remove_device(struct pci_dev *dev); -struct pci_dev *pci_addr_cache_get_device(unsigned long addr); -void eeh_slot_error_detail(struct eeh_dev *edev, int severity); -int eeh_pci_enable(struct eeh_dev *edev, int function); -int eeh_reset_pe(struct eeh_dev *); -void eeh_restore_bars(struct eeh_dev *); +void pci_addr_cache_build(void); +struct pci_dev *pci_get_device_by_addr(unsigned long addr); + +/** + * eeh_slot_error_detail -- record and EEH error condition to the log + * @pdn: pci device node + * @severity: EEH_LOG_TEMP_FAILURE or EEH_LOG_PERM_FAILURE + * + * Obtains the EEH error details from the RTAS subsystem, + * and then logs these details with the RTAS error log system. + */ +#define EEH_LOG_TEMP_FAILURE 1 +#define EEH_LOG_PERM_FAILURE 2 +void eeh_slot_error_detail (struct pci_dn *pdn, int severity); + +/** + * rtas_pci_enable - enable IO transfers for this slot + * @pdn: pci device node + * @function: either EEH_THAW_MMIO or EEH_THAW_DMA + * + * Enable I/O transfers to this slot + */ +#define EEH_THAW_MMIO 2 +#define EEH_THAW_DMA 3 +int rtas_pci_enable(struct pci_dn *pdn, int function); + +/** + * rtas_set_slot_reset -- unfreeze a frozen slot + * @pdn: pci device node + * + * Clear the EEH-frozen condition on a slot. This routine + * does this by asserting the PCI #RST line for 1/8th of + * a second; this routine will sleep while the adapter is + * being reset. + * + * Returns a non-zero value if the reset failed. + */ +int rtas_set_slot_reset (struct pci_dn *); +int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs); + +/** + * eeh_restore_bars - Restore device configuration info. + * @pdn: pci device node + * + * A reset of a PCI device will clear out its config space. + * This routines will restore the config space for this + * device, and is children, to values previously obtained + * from the firmware. + */ +void eeh_restore_bars(struct pci_dn *); + +/** + * rtas_configure_bridge -- firmware initialization of pci bridge + * @pdn: pci device node + * + * Ask the firmware to configure all PCI bridges devices + * located behind the indicated node. Required after a + * pci device reset. Does essentially the same hing as + * eeh_restore_bars, but for brdges, and lets firmware + * do the work. + */ +void rtas_configure_bridge(struct pci_dn *); + int rtas_write_config(struct pci_dn *, int where, int size, u32 val); int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); -void eeh_mark_slot(struct device_node *dn, int mode_flag); -void eeh_clear_slot(struct device_node *dn, int mode_flag); -struct device_node *eeh_find_device_pe(struct device_node *dn); + +/** + * eeh_mark_slot -- set mode flags for pertition endpoint + * @pdn: pci device node + * + * mark and clear slots: find "partition endpoint" PE and set or + * clear the flags for each subnode of the PE. + */ +void eeh_mark_slot (struct device_node *dn, int mode_flag); +void eeh_clear_slot (struct device_node *dn, int mode_flag); + +/** + * find_device_pe -- Find the associated "Partiationable Endpoint" PE + * @pdn: pci device node + */ +struct device_node * find_device_pe(struct device_node *dn); void eeh_sysfs_add_device(struct pci_dev *pdev); void eeh_sysfs_remove_device(struct pci_dev *pdev); diff --git a/trunk/arch/powerpc/include/asm/ppc_asm.h b/trunk/arch/powerpc/include/asm/ppc_asm.h index 50f73aa2ba21..368f72f79808 100644 --- a/trunk/arch/powerpc/include/asm/ppc_asm.h +++ b/trunk/arch/powerpc/include/asm/ppc_asm.h @@ -60,8 +60,6 @@ BEGIN_FW_FTR_SECTION; \ cmpd cr1,r11,r10; \ beq+ cr1,33f; \ bl .accumulate_stolen_time; \ - ld r12,_MSR(r1); \ - andi. r10,r12,MSR_PR; /* Restore cr0 (coming from user) */ \ 33: \ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) diff --git a/trunk/arch/powerpc/include/asm/reg.h b/trunk/arch/powerpc/include/asm/reg.h index b1a215eabef6..7fdc2c0b7fa0 100644 --- a/trunk/arch/powerpc/include/asm/reg.h +++ b/trunk/arch/powerpc/include/asm/reg.h @@ -1079,12 +1079,30 @@ #define proc_trap() asm volatile("trap") -#define __get_SP() ({unsigned long sp; \ - asm volatile("mr %0,1": "=r" (sp)); sp;}) +#ifdef CONFIG_PPC64 + +extern void ppc64_runlatch_on(void); +extern void __ppc64_runlatch_off(void); + +#define ppc64_runlatch_off() \ + do { \ + if (cpu_has_feature(CPU_FTR_CTRL) && \ + test_thread_flag(TIF_RUNLATCH)) \ + __ppc64_runlatch_off(); \ + } while (0) extern unsigned long scom970_read(unsigned int address); extern void scom970_write(unsigned int address, unsigned long value); +#else +#define ppc64_runlatch_on() +#define ppc64_runlatch_off() + +#endif /* CONFIG_PPC64 */ + +#define __get_SP() ({unsigned long sp; \ + asm volatile("mr %0,1": "=r" (sp)); sp;}) + struct pt_regs; extern void ppc_save_regs(struct pt_regs *regs); diff --git a/trunk/arch/powerpc/include/asm/reg_booke.h b/trunk/arch/powerpc/include/asm/reg_booke.h index 8a97aa7289d3..500fe1dc43e6 100644 --- a/trunk/arch/powerpc/include/asm/reg_booke.h +++ b/trunk/arch/powerpc/include/asm/reg_booke.h @@ -62,7 +62,6 @@ #define SPRN_DVC2 0x13F /* Data Value Compare Register 2 */ #define SPRN_MAS8 0x155 /* MMU Assist Register 8 */ #define SPRN_TLB0PS 0x158 /* TLB 0 Page Size Register */ -#define SPRN_TLB1PS 0x159 /* TLB 1 Page Size Register */ #define SPRN_MAS5_MAS6 0x15c /* MMU Assist Register 5 || 6 */ #define SPRN_MAS8_MAS1 0x15d /* MMU Assist Register 8 || 1 */ #define SPRN_EPTCFG 0x15e /* Embedded Page Table Config */ diff --git a/trunk/arch/powerpc/include/asm/spinlock.h b/trunk/arch/powerpc/include/asm/spinlock.h index 7124fc06ad47..f9611bd69ed2 100644 --- a/trunk/arch/powerpc/include/asm/spinlock.h +++ b/trunk/arch/powerpc/include/asm/spinlock.h @@ -23,6 +23,7 @@ #ifdef CONFIG_PPC64 #include #include +#include #endif #include #include @@ -94,12 +95,12 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) * value. */ -#if defined(CONFIG_PPC_SPLPAR) +#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) /* We only yield to the hypervisor if we are in shared processor mode */ #define SHARED_PROCESSOR (get_lppaca()->shared_proc) extern void __spin_yield(arch_spinlock_t *lock); extern void __rw_yield(arch_rwlock_t *lock); -#else /* SPLPAR */ +#else /* SPLPAR || ISERIES */ #define __spin_yield(x) barrier() #define __rw_yield(x) barrier() #define SHARED_PROCESSOR 0 diff --git a/trunk/arch/powerpc/include/asm/system.h b/trunk/arch/powerpc/include/asm/system.h index a02883d5af43..c377457d1b89 100644 --- a/trunk/arch/powerpc/include/asm/system.h +++ b/trunk/arch/powerpc/include/asm/system.h @@ -550,43 +550,5 @@ extern void reloc_got2(unsigned long); extern struct dentry *powerpc_debugfs_root; -#ifdef CONFIG_PPC64 - -extern void __ppc64_runlatch_on(void); -extern void __ppc64_runlatch_off(void); - -/* - * We manually hard enable-disable, this is called - * in the idle loop and we don't want to mess up - * with soft-disable/enable & interrupt replay. - */ -#define ppc64_runlatch_off() \ - do { \ - if (cpu_has_feature(CPU_FTR_CTRL) && \ - test_thread_local_flags(_TLF_RUNLATCH)) { \ - unsigned long msr = mfmsr(); \ - __hard_irq_disable(); \ - __ppc64_runlatch_off(); \ - if (msr & MSR_EE) \ - __hard_irq_enable(); \ - } \ - } while (0) - -#define ppc64_runlatch_on() \ - do { \ - if (cpu_has_feature(CPU_FTR_CTRL) && \ - !test_thread_local_flags(_TLF_RUNLATCH)) { \ - unsigned long msr = mfmsr(); \ - __hard_irq_disable(); \ - __ppc64_runlatch_on(); \ - if (msr & MSR_EE) \ - __hard_irq_enable(); \ - } \ - } while (0) -#else -#define ppc64_runlatch_on() -#define ppc64_runlatch_off() -#endif /* CONFIG_PPC64 */ - #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_SYSTEM_H */ diff --git a/trunk/arch/powerpc/include/asm/thread_info.h b/trunk/arch/powerpc/include/asm/thread_info.h index 4a741c7efd02..964714940961 100644 --- a/trunk/arch/powerpc/include/asm/thread_info.h +++ b/trunk/arch/powerpc/include/asm/thread_info.h @@ -110,6 +110,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_NOERROR 12 /* Force successful syscall return */ #define TIF_NOTIFY_RESUME 13 /* callback before returning to user */ #define TIF_SYSCALL_TRACEPOINT 15 /* syscall tracepoint instrumentation */ +#define TIF_RUNLATCH 16 /* Is the runlatch enabled? */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<flags); } -static inline bool test_thread_local_flags(unsigned int flags) -{ - struct thread_info *ti = current_thread_info(); - return (ti->local_flags & flags) != 0; -} - #ifdef CONFIG_PPC64 #define is_32bit_task() (test_thread_flag(TIF_32BIT)) #else diff --git a/trunk/arch/powerpc/include/asm/time.h b/trunk/arch/powerpc/include/asm/time.h index 2136f58a54e8..7eb10fb96cd0 100644 --- a/trunk/arch/powerpc/include/asm/time.h +++ b/trunk/arch/powerpc/include/asm/time.h @@ -18,6 +18,11 @@ #include #include +#ifdef CONFIG_PPC_ISERIES +#include +#include +#include +#endif /* time.c */ extern unsigned long tb_ticks_per_jiffy; @@ -161,6 +166,15 @@ static inline void set_dec(int val) #else #ifndef CONFIG_BOOKE --val; +#endif +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES) && + get_lppaca()->shared_proc) { + get_lppaca()->virtual_decr = val; + if (get_dec() > val) + HvCall_setVirtualDecr(); + return; + } #endif mtspr(SPRN_DEC, val); #endif /* not 40x or 8xx_CPU6 */ @@ -203,6 +217,7 @@ DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); #endif extern void secondary_cpu_time_init(void); +extern void iSeries_time_init_early(void); DECLARE_PER_CPU(u64, decrementers_next_tb); diff --git a/trunk/arch/powerpc/kernel/Makefile b/trunk/arch/powerpc/kernel/Makefile index f5808a35688c..ee728e433aa2 100644 --- a/trunk/arch/powerpc/kernel/Makefile +++ b/trunk/arch/powerpc/kernel/Makefile @@ -60,7 +60,6 @@ obj-$(CONFIG_IBMVIO) += vio.o obj-$(CONFIG_IBMEBUS) += ibmebus.o obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o obj-$(CONFIG_CRASH_DUMP) += crash_dump.o -obj-$(CONFIG_FA_DUMP) += fadump.o ifeq ($(CONFIG_PPC32),y) obj-$(CONFIG_E500) += idle_e500.o endif @@ -114,6 +113,15 @@ obj-$(CONFIG_PPC_IO_WORKAROUNDS) += io-workarounds.o obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o +obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o + +obj-$(CONFIG_PPC_PERF_CTRS) += perf_event.o +obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \ + power5+-pmu.o power6-pmu.o power7-pmu.o +obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o + +obj-$(CONFIG_FSL_EMB_PERF_EVENT) += perf_event_fsl_emb.o +obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o diff --git a/trunk/arch/powerpc/kernel/asm-offsets.c b/trunk/arch/powerpc/kernel/asm-offsets.c index cc492e48ddfa..04caee7d9bc1 100644 --- a/trunk/arch/powerpc/kernel/asm-offsets.c +++ b/trunk/arch/powerpc/kernel/asm-offsets.c @@ -46,6 +46,9 @@ #include #include #endif +#ifdef CONFIG_PPC_ISERIES +#include +#endif #ifdef CONFIG_PPC_POWERNV #include #endif @@ -144,7 +147,7 @@ int main(void) DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase)); DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr)); DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled)); - DEFINE(PACAIRQHAPPENED, offsetof(struct paca_struct, irq_happened)); + DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled)); DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); #ifdef CONFIG_PPC_MM_SLICES DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct, @@ -381,6 +384,17 @@ int main(void) DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); #endif +#ifdef CONFIG_PPC_ISERIES + /* the assembler miscalculates the VSID values */ + DEFINE(PAGE_OFFSET_ESID, GET_ESID(PAGE_OFFSET)); + DEFINE(PAGE_OFFSET_VSID, KERNEL_VSID(PAGE_OFFSET)); + DEFINE(VMALLOC_START_ESID, GET_ESID(VMALLOC_START)); + DEFINE(VMALLOC_START_VSID, KERNEL_VSID(VMALLOC_START)); + + /* alpaca */ + DEFINE(ALPACA_SIZE, sizeof(struct alpaca)); +#endif + DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE); DEFINE(PTE_SIZE, sizeof(pte_t)); diff --git a/trunk/arch/powerpc/kernel/cputable.c b/trunk/arch/powerpc/kernel/cputable.c index 138ae183c440..81db9e2a8a20 100644 --- a/trunk/arch/powerpc/kernel/cputable.c +++ b/trunk/arch/powerpc/kernel/cputable.c @@ -1816,7 +1816,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .platform = "ppc440", }, { /* 464 in APM821xx */ - .pvr_mask = 0xfffffff0, + .pvr_mask = 0xffffff00, .pvr_value = 0x12C41C80, .cpu_name = "APM821XX", .cpu_features = CPU_FTRS_44X, @@ -2019,24 +2019,6 @@ static struct cpu_spec __initdata cpu_specs[] = { .machine_check = machine_check_e500mc, .platform = "ppce5500", }, - { /* e6500 */ - .pvr_mask = 0xffff0000, - .pvr_value = 0x80400000, - .cpu_name = "e6500", - .cpu_features = CPU_FTRS_E6500, - .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, - .mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS | - MMU_FTR_USE_TLBILX, - .icache_bsize = 64, - .dcache_bsize = 64, - .num_pmcs = 4, - .oprofile_cpu_type = "ppc/e6500", - .oprofile_type = PPC_OPROFILE_FSL_EMB, - .cpu_setup = __setup_cpu_e5500, - .cpu_restore = __restore_cpu_e5500, - .machine_check = machine_check_e500mc, - .platform = "ppce6500", - }, #ifdef CONFIG_PPC32 { /* default match */ .pvr_mask = 0x00000000, diff --git a/trunk/arch/powerpc/kernel/dbell.c b/trunk/arch/powerpc/kernel/dbell.c index 5b25c8060fd6..2cc451aaaca7 100644 --- a/trunk/arch/powerpc/kernel/dbell.c +++ b/trunk/arch/powerpc/kernel/dbell.c @@ -37,8 +37,6 @@ void doorbell_exception(struct pt_regs *regs) irq_enter(); - may_hard_irq_enable(); - smp_ipi_demux(); irq_exit(); diff --git a/trunk/arch/powerpc/perf/e500-pmu.c b/trunk/arch/powerpc/kernel/e500-pmu.c similarity index 100% rename from trunk/arch/powerpc/perf/e500-pmu.c rename to trunk/arch/powerpc/kernel/e500-pmu.c diff --git a/trunk/arch/powerpc/kernel/entry_64.S b/trunk/arch/powerpc/kernel/entry_64.S index f8a7a1a1a9f4..866462cbe2d8 100644 --- a/trunk/arch/powerpc/kernel/entry_64.S +++ b/trunk/arch/powerpc/kernel/entry_64.S @@ -32,7 +32,6 @@ #include #include #include -#include /* * System calls. @@ -116,33 +115,39 @@ BEGIN_FW_FTR_SECTION END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) #endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */ - /* - * A syscall should always be called with interrupts enabled - * so we just unconditionally hard-enable here. When some kind - * of irq tracing is used, we additionally check that condition - * is correct - */ -#if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_BUG) - lbz r10,PACASOFTIRQEN(r13) - xori r10,r10,1 -1: tdnei r10,0 - EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING -#endif +#ifdef CONFIG_TRACE_IRQFLAGS + bl .trace_hardirqs_on + REST_GPR(0,r1) + REST_4GPRS(3,r1) + REST_2GPRS(7,r1) + addi r9,r1,STACK_FRAME_OVERHEAD + ld r12,_MSR(r1) +#endif /* CONFIG_TRACE_IRQFLAGS */ + li r10,1 + stb r10,PACASOFTIRQEN(r13) + stb r10,PACAHARDIRQEN(r13) + std r10,SOFTE(r1) +#ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION + /* Hack for handling interrupts when soft-enabling on iSeries */ + cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ + andi. r10,r12,MSR_PR /* from kernel */ + crand 4*cr0+eq,4*cr1+eq,4*cr0+eq + bne 2f + b hardware_interrupt_entry +2: +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +#endif /* CONFIG_PPC_ISERIES */ + /* Hard enable interrupts */ #ifdef CONFIG_PPC_BOOK3E wrteei 1 #else - ld r11,PACAKMSR(r13) + mfmsr r11 ori r11,r11,MSR_EE mtmsrd r11,1 #endif /* CONFIG_PPC_BOOK3E */ - /* We do need to set SOFTE in the stack frame or the return - * from interrupt will be painful - */ - li r10,1 - std r10,SOFTE(r1) - #ifdef SHOW_SYSCALLS bl .do_show_syscall REST_GPR(0,r1) @@ -193,14 +198,16 @@ syscall_exit: andi. r10,r8,MSR_RI beq- unrecov_restore #endif - /* - * Disable interrupts so current_thread_info()->flags can't change, + + /* Disable interrupts so current_thread_info()->flags can't change, * and so that we don't get interrupted after loading SRR0/1. */ #ifdef CONFIG_PPC_BOOK3E wrteei 0 #else - ld r10,PACAKMSR(r13) + mfmsr r10 + rldicl r10,r10,48,1 + rotldi r10,r10,16 mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ @@ -312,7 +319,7 @@ syscall_exit_work: #ifdef CONFIG_PPC_BOOK3E wrteei 1 #else - ld r10,PACAKMSR(r13) + mfmsr r10 ori r10,r10,MSR_EE mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ @@ -558,8 +565,10 @@ _GLOBAL(ret_from_except_lite) #ifdef CONFIG_PPC_BOOK3E wrteei 0 #else - ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */ - mtmsrd r10,1 /* Update machine state */ + mfmsr r10 /* Get current interrupt state */ + rldicl r9,r10,48,1 /* clear MSR_EE */ + rotldi r9,r9,16 + mtmsrd r9,1 /* Update machine state */ #endif /* CONFIG_PPC_BOOK3E */ #ifdef CONFIG_PREEMPT @@ -582,74 +591,25 @@ _GLOBAL(ret_from_except_lite) ld r4,TI_FLAGS(r9) andi. r0,r4,_TIF_USER_WORK_MASK bne do_work -#endif /* !CONFIG_PREEMPT */ +#endif - .globl fast_exc_return_irq -fast_exc_return_irq: restore: - /* - * This is the main kernel exit path, we first check if we - * have to change our interrupt state. - */ +BEGIN_FW_FTR_SECTION ld r5,SOFTE(r1) - lbz r6,PACASOFTIRQEN(r13) - cmpwi cr1,r5,0 - cmpw cr0,r5,r6 - beq cr0,4f - - /* We do, handle disable first, which is easy */ - bne cr1,3f; - li r0,0 - stb r0,PACASOFTIRQEN(r13); - TRACE_DISABLE_INTS - b 4f - -3: /* - * We are about to soft-enable interrupts (we are hard disabled - * at this point). We check if there's anything that needs to - * be replayed first. - */ - lbz r0,PACAIRQHAPPENED(r13) - cmpwi cr0,r0,0 - bne- restore_check_irq_replay +FW_FTR_SECTION_ELSE + b .Liseries_check_pending_irqs +ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES) +2: + TRACE_AND_RESTORE_IRQ(r5); - /* - * Get here when nothing happened while soft-disabled, just - * soft-enable and move-on. We will hard-enable as a side - * effect of rfi - */ -restore_no_replay: - TRACE_ENABLE_INTS - li r0,1 - stb r0,PACASOFTIRQEN(r13); + /* extract EE bit and use it to restore paca->hard_enabled */ + ld r3,_MSR(r1) + rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ + stb r4,PACAHARDIRQEN(r13) - /* - * Final return path. BookE is handled in a different file - */ -4: #ifdef CONFIG_PPC_BOOK3E b .exception_return_book3e #else - /* - * Clear the reservation. If we know the CPU tracks the address of - * the reservation then we can potentially save some cycles and use - * a larx. On POWER6 and POWER7 this is significantly faster. - */ -BEGIN_FTR_SECTION - stdcx. r0,0,r1 /* to clear the reservation */ -FTR_SECTION_ELSE - ldarx r4,0,r1 -ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) - - /* - * Some code path such as load_up_fpu or altivec return directly - * here. They run entirely hard disabled and do not alter the - * interrupt state. They also don't use lwarx/stwcx. and thus - * are known not to leave dangling reservations. - */ - .globl fast_exception_return -fast_exception_return: - ld r3,_MSR(r1) ld r4,_CTR(r1) ld r0,_LINK(r1) mtctr r4 @@ -662,19 +622,29 @@ fast_exception_return: andi. r0,r3,MSR_RI beq- unrecov_restore + /* + * Clear the reservation. If we know the CPU tracks the address of + * the reservation then we can potentially save some cycles and use + * a larx. On POWER6 and POWER7 this is significantly faster. + */ +BEGIN_FTR_SECTION + stdcx. r0,0,r1 /* to clear the reservation */ +FTR_SECTION_ELSE + ldarx r4,0,r1 +ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) + /* * Clear RI before restoring r13. If we are returning to * userspace and we take an exception after restoring r13, * we end up corrupting the userspace r13 value. */ - ld r4,PACAKMSR(r13) /* Get kernel MSR without EE */ - andc r4,r4,r0 /* r0 contains MSR_RI here */ + mfmsr r4 + andc r4,r4,r0 /* r0 contains MSR_RI here */ mtmsrd r4,1 /* * r13 is our per cpu area, only restore it if we are returning to - * userspace the value stored in the stack frame may belong to - * another CPU. + * userspace */ andi. r0,r3,MSR_PR beq 1f @@ -699,55 +669,30 @@ fast_exception_return: #endif /* CONFIG_PPC_BOOK3E */ - /* - * Something did happen, check if a re-emit is needed - * (this also clears paca->irq_happened) - */ -restore_check_irq_replay: - /* XXX: We could implement a fast path here where we check - * for irq_happened being just 0x01, in which case we can - * clear it and return. That means that we would potentially - * miss a decrementer having wrapped all the way around. - * - * Still, this might be useful for things like hash_page - */ - bl .__check_irq_replay - cmpwi cr0,r3,0 - beq restore_no_replay - - /* - * We need to re-emit an interrupt. We do so by re-using our - * existing exception frame. We first change the trap value, - * but we need to ensure we preserve the low nibble of it - */ - ld r4,_TRAP(r1) - clrldi r4,r4,60 - or r4,r4,r3 - std r4,_TRAP(r1) +.Liseries_check_pending_irqs: +#ifdef CONFIG_PPC_ISERIES + ld r5,SOFTE(r1) + cmpdi 0,r5,0 + beq 2b + /* Check for pending interrupts (iSeries) */ + ld r3,PACALPPACAPTR(r13) + ld r3,LPPACAANYINT(r3) + cmpdi r3,0 + beq+ 2b /* skip do_IRQ if no interrupts */ + + li r3,0 + stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */ +#ifdef CONFIG_TRACE_IRQFLAGS + bl .trace_hardirqs_off + mfmsr r10 +#endif + ori r10,r10,MSR_EE + mtmsrd r10 /* hard-enable again */ + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_IRQ + b .ret_from_except_lite /* loop back and handle more */ +#endif - /* - * Then find the right handler and call it. Interrupts are - * still soft-disabled and we keep them that way. - */ - cmpwi cr0,r3,0x500 - bne 1f - addi r3,r1,STACK_FRAME_OVERHEAD; - bl .do_IRQ - b .ret_from_except -1: cmpwi cr0,r3,0x900 - bne 1f - addi r3,r1,STACK_FRAME_OVERHEAD; - bl .timer_interrupt - b .ret_from_except -#ifdef CONFIG_PPC_BOOK3E -1: cmpwi cr0,r3,0x280 - bne 1f - addi r3,r1,STACK_FRAME_OVERHEAD; - bl .doorbell_exception - b .ret_from_except -#endif /* CONFIG_PPC_BOOK3E */ -1: b .ret_from_except /* What else to do here ? */ - do_work: #ifdef CONFIG_PREEMPT andi. r0,r3,MSR_PR /* Returning to user mode? */ @@ -760,22 +705,31 @@ do_work: crandc eq,cr1*4+eq,eq bne restore - /* - * Here we are preempting the current task. We want to make - * sure we are soft-disabled first + /* Here we are preempting the current task. + * + * Ensure interrupts are soft-disabled. We also properly mark + * the PACA to reflect the fact that they are hard-disabled + * and trace the change */ - SOFT_DISABLE_INTS(r3,r4) + li r0,0 + stb r0,PACASOFTIRQEN(r13) + stb r0,PACAHARDIRQEN(r13) + TRACE_DISABLE_INTS + + /* Call the scheduler with soft IRQs off */ 1: bl .preempt_schedule_irq /* Hard-disable interrupts again (and update PACA) */ #ifdef CONFIG_PPC_BOOK3E wrteei 0 #else - ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */ + mfmsr r10 + rldicl r10,r10,48,1 + rotldi r10,r10,16 mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ - li r0,PACA_IRQ_HARD_DIS - stb r0,PACAIRQHAPPENED(r13) + li r0,0 + stb r0,PACAHARDIRQEN(r13) /* Re-test flags and eventually loop */ clrrdi r9,r1,THREAD_SHIFT @@ -797,12 +751,14 @@ user_work: andi. r0,r4,_TIF_NEED_RESCHED beq 1f - bl .restore_interrupts + li r5,1 + TRACE_AND_RESTORE_IRQ(r5); bl .schedule b .ret_from_except_lite 1: bl .save_nvgprs - bl .restore_interrupts + li r5,1 + TRACE_AND_RESTORE_IRQ(r5); addi r3,r1,STACK_FRAME_OVERHEAD bl .do_notify_resume b .ret_from_except diff --git a/trunk/arch/powerpc/kernel/exceptions-64e.S b/trunk/arch/powerpc/kernel/exceptions-64e.S index 7215cc2495df..429983c06f91 100644 --- a/trunk/arch/powerpc/kernel/exceptions-64e.S +++ b/trunk/arch/powerpc/kernel/exceptions-64e.S @@ -24,7 +24,6 @@ #include #include #include -#include /* XXX This will ultimately add space for a special exception save * structure used to save things like SRR0/SRR1, SPRGs, MAS, etc... @@ -78,55 +77,59 @@ #define SPRN_MC_SRR1 SPRN_MCSRR1 #define NORMAL_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, GEN, addition##_GEN(n)) + EXCEPTION_PROLOG(n, GEN, addition##_GEN) #define CRIT_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, CRIT, addition##_CRIT(n)) + EXCEPTION_PROLOG(n, CRIT, addition##_CRIT) #define DBG_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, DBG, addition##_DBG(n)) + EXCEPTION_PROLOG(n, DBG, addition##_DBG) #define MC_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, MC, addition##_MC(n)) + EXCEPTION_PROLOG(n, MC, addition##_MC) /* Variants of the "addition" argument for the prolog */ -#define PROLOG_ADDITION_NONE_GEN(n) -#define PROLOG_ADDITION_NONE_CRIT(n) -#define PROLOG_ADDITION_NONE_DBG(n) -#define PROLOG_ADDITION_NONE_MC(n) +#define PROLOG_ADDITION_NONE_GEN +#define PROLOG_ADDITION_NONE_CRIT +#define PROLOG_ADDITION_NONE_DBG +#define PROLOG_ADDITION_NONE_MC -#define PROLOG_ADDITION_MASKABLE_GEN(n) \ +#define PROLOG_ADDITION_MASKABLE_GEN \ lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ cmpwi cr0,r11,0; /* yes -> go out of line */ \ - beq masked_interrupt_book3e_##n + beq masked_interrupt_book3e; -#define PROLOG_ADDITION_2REGS_GEN(n) \ +#define PROLOG_ADDITION_2REGS_GEN \ std r14,PACA_EXGEN+EX_R14(r13); \ std r15,PACA_EXGEN+EX_R15(r13) -#define PROLOG_ADDITION_1REG_GEN(n) \ +#define PROLOG_ADDITION_1REG_GEN \ std r14,PACA_EXGEN+EX_R14(r13); -#define PROLOG_ADDITION_2REGS_CRIT(n) \ +#define PROLOG_ADDITION_2REGS_CRIT \ std r14,PACA_EXCRIT+EX_R14(r13); \ std r15,PACA_EXCRIT+EX_R15(r13) -#define PROLOG_ADDITION_2REGS_DBG(n) \ +#define PROLOG_ADDITION_2REGS_DBG \ std r14,PACA_EXDBG+EX_R14(r13); \ std r15,PACA_EXDBG+EX_R15(r13) -#define PROLOG_ADDITION_2REGS_MC(n) \ +#define PROLOG_ADDITION_2REGS_MC \ std r14,PACA_EXMC+EX_R14(r13); \ std r15,PACA_EXMC+EX_R15(r13) +#define PROLOG_ADDITION_DOORBELL_GEN \ + lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ + cmpwi cr0,r11,0; /* yes -> go out of line */ \ + beq masked_doorbell_book3e + /* Core exception code for all exceptions except TLB misses. * XXX: Needs to make SPRN_SPRG_GEN depend on exception type */ #define EXCEPTION_COMMON(n, excf, ints) \ -exc_##n##_common: \ std r0,GPR0(r1); /* save r0 in stackframe */ \ std r2,GPR2(r1); /* save r2 in stackframe */ \ SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ @@ -164,21 +167,20 @@ exc_##n##_common: \ std r0,RESULT(r1); /* clear regs->result */ \ ints; -/* Variants for the "ints" argument. This one does nothing when we want - * to keep interrupts in their original state - */ +/* Variants for the "ints" argument */ #define INTS_KEEP - -/* This second version is meant for exceptions that don't immediately - * hard-enable. We set a bit in paca->irq_happened to ensure that - * a subsequent call to arch_local_irq_restore() will properly - * hard-enable and avoid the fast-path - */ -#define INTS_DISABLE SOFT_DISABLE_INTS(r3,r4) - -/* This is called by exceptions that used INTS_KEEP (that did not touch - * irq indicators in the PACA). This will restore MSR:EE to it's previous - * value +#define INTS_DISABLE_SOFT \ + stb r0,PACASOFTIRQEN(r13); /* mark interrupts soft-disabled */ \ + TRACE_DISABLE_INTS; +#define INTS_DISABLE_HARD \ + stb r0,PACAHARDIRQEN(r13); /* and hard disabled */ +#define INTS_DISABLE_ALL \ + INTS_DISABLE_SOFT \ + INTS_DISABLE_HARD + +/* This is called by exceptions that used INTS_KEEP (that is did not clear + * neither soft nor hard IRQ indicators in the PACA. This will restore MSR:EE + * to it's previous value * * XXX In the long run, we may want to open-code it in order to separate the * load from the wrtee, thus limiting the latency caused by the dependency @@ -236,7 +238,7 @@ exc_##n##_bad_stack: \ #define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \ START_EXCEPTION(label); \ NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \ - EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE) \ + EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \ ack(r8); \ CHECK_NAPPING(); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ @@ -287,7 +289,7 @@ interrupt_end_book3e: /* Critical Input Interrupt */ START_EXCEPTION(critical_input); CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE) +// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL) // bl special_reg_save_crit // CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD @@ -298,7 +300,7 @@ interrupt_end_book3e: /* Machine Check Interrupt */ START_EXCEPTION(machine_check); CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE) +// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL) // bl special_reg_save_mc // addi r3,r1,STACK_FRAME_OVERHEAD // CHECK_NAPPING(); @@ -311,7 +313,7 @@ interrupt_end_book3e: NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS) mfspr r14,SPRN_DEAR mfspr r15,SPRN_ESR - EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_DISABLE) + EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_KEEP) b storage_fault_common /* Instruction Storage Interrupt */ @@ -319,7 +321,7 @@ interrupt_end_book3e: NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS) li r15,0 mr r14,r10 - EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_DISABLE) + EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_KEEP) b storage_fault_common /* External Input Interrupt */ @@ -337,11 +339,12 @@ interrupt_end_book3e: START_EXCEPTION(program); NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG) mfspr r14,SPRN_ESR - EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE) + EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT) std r14,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD ld r14,PACA_EXGEN+EX_R14(r13) bl .save_nvgprs + INTS_RESTORE_HARD bl .program_check_exception b .ret_from_except @@ -350,16 +353,15 @@ interrupt_end_book3e: NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE) /* we can probably do a shorter exception entry for that one... */ EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP) - ld r12,_MSR(r1) - andi. r0,r12,MSR_PR; - beq- 1f - bl .load_up_fpu - b fast_exception_return -1: INTS_DISABLE + bne 1f /* if from user, just load it up */ bl .save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD + INTS_RESTORE_HARD bl .kernel_fp_unavailable_exception - b .ret_from_except + BUG_OPCODE +1: ld r12,_MSR(r1) + bl .load_up_fpu + b fast_exception_return /* Decrementer Interrupt */ MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC) @@ -370,7 +372,7 @@ interrupt_end_book3e: /* Watchdog Timer Interrupt */ START_EXCEPTION(watchdog); CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE) +// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL) // bl special_reg_save_crit // CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD @@ -389,9 +391,10 @@ interrupt_end_book3e: /* Auxiliary Processor Unavailable Interrupt */ START_EXCEPTION(ap_unavailable); NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE) - EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_DISABLE) - bl .save_nvgprs + EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP) addi r3,r1,STACK_FRAME_OVERHEAD + bl .save_nvgprs + INTS_RESTORE_HARD bl .unknown_exception b .ret_from_except @@ -447,7 +450,7 @@ interrupt_end_book3e: mfspr r15,SPRN_SPRG_CRIT_SCRATCH mtspr SPRN_SPRG_GEN_SCRATCH,r15 mfspr r14,SPRN_DBSR - EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE) + EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE_ALL) std r14,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r14 @@ -462,7 +465,7 @@ kernel_dbg_exc: /* Debug exception as a debug interrupt*/ START_EXCEPTION(debug_debug); - DBG_EXCEPTION_PROLOG(0xd08, PROLOG_ADDITION_2REGS) + DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) /* * If there is a single step or branch-taken exception in an @@ -512,7 +515,7 @@ kernel_dbg_exc: mfspr r15,SPRN_SPRG_DBG_SCRATCH mtspr SPRN_SPRG_GEN_SCRATCH,r15 mfspr r14,SPRN_DBSR - EXCEPTION_COMMON(0xd08, PACA_EXDBG, INTS_DISABLE) + EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL) std r14,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r14 @@ -522,20 +525,21 @@ kernel_dbg_exc: bl .DebugException b .ret_from_except - START_EXCEPTION(perfmon); - NORMAL_EXCEPTION_PROLOG(0x260, PROLOG_ADDITION_NONE) - EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE) - addi r3,r1,STACK_FRAME_OVERHEAD - bl .performance_monitor_exception - b .ret_from_except_lite + MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE) /* Doorbell interrupt */ - MASKABLE_EXCEPTION(0x280, doorbell, .doorbell_exception, ACK_NONE) + START_EXCEPTION(doorbell) + NORMAL_EXCEPTION_PROLOG(0x2070, PROLOG_ADDITION_DOORBELL) + EXCEPTION_COMMON(0x2070, PACA_EXGEN, INTS_DISABLE_ALL) + CHECK_NAPPING() + addi r3,r1,STACK_FRAME_OVERHEAD + bl .doorbell_exception + b .ret_from_except_lite /* Doorbell critical Interrupt */ START_EXCEPTION(doorbell_crit); - CRIT_EXCEPTION_PROLOG(0x2a0, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x2a0, PACA_EXCRIT, INTS_DISABLE) + CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE) +// EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL) // bl special_reg_save_crit // CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD @@ -543,114 +547,36 @@ kernel_dbg_exc: // b ret_from_crit_except b . -/* Guest Doorbell */ MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE) + MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE) -/* Guest Doorbell critical Interrupt */ - START_EXCEPTION(guest_doorbell_crit); - CRIT_EXCEPTION_PROLOG(0x2e0, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x2e0, PACA_EXCRIT, INTS_DISABLE) -// bl special_reg_save_crit -// CHECK_NAPPING(); -// addi r3,r1,STACK_FRAME_OVERHEAD -// bl .guest_doorbell_critical_exception -// b ret_from_crit_except - b . - -/* Hypervisor call */ - START_EXCEPTION(hypercall); - NORMAL_EXCEPTION_PROLOG(0x310, PROLOG_ADDITION_NONE) - EXCEPTION_COMMON(0x310, PACA_EXGEN, INTS_KEEP) - addi r3,r1,STACK_FRAME_OVERHEAD - bl .save_nvgprs - INTS_RESTORE_HARD - bl .unknown_exception - b .ret_from_except - -/* Embedded Hypervisor priviledged */ - START_EXCEPTION(ehpriv); - NORMAL_EXCEPTION_PROLOG(0x320, PROLOG_ADDITION_NONE) - EXCEPTION_COMMON(0x320, PACA_EXGEN, INTS_KEEP) - addi r3,r1,STACK_FRAME_OVERHEAD - bl .save_nvgprs - INTS_RESTORE_HARD - bl .unknown_exception - b .ret_from_except /* - * An interrupt came in while soft-disabled; We mark paca->irq_happened - * accordingly and if the interrupt is level sensitive, we hard disable + * An interrupt came in while soft-disabled; clear EE in SRR1, + * clear paca->hard_enabled and return. */ - -masked_interrupt_book3e_0x500: - /* XXX When adding support for EPR, use PACA_IRQ_EE_EDGE */ - li r11,PACA_IRQ_EE - b masked_interrupt_book3e_full_mask - -masked_interrupt_book3e_0x900: - ACK_DEC(r11); - li r11,PACA_IRQ_DEC - b masked_interrupt_book3e_no_mask -masked_interrupt_book3e_0x980: - ACK_FIT(r11); - li r11,PACA_IRQ_DEC - b masked_interrupt_book3e_no_mask -masked_interrupt_book3e_0x280: -masked_interrupt_book3e_0x2c0: - li r11,PACA_IRQ_DBELL - b masked_interrupt_book3e_no_mask - -masked_interrupt_book3e_no_mask: +masked_doorbell_book3e: mtcr r10 - lbz r10,PACAIRQHAPPENED(r13) - or r10,r10,r11 - stb r10,PACAIRQHAPPENED(r13) - b 1f -masked_interrupt_book3e_full_mask: + /* Resend the doorbell to fire again when ints enabled */ + mfspr r10,SPRN_PIR + PPC_MSGSND(r10) + b masked_interrupt_book3e_common + +masked_interrupt_book3e: mtcr r10 - lbz r10,PACAIRQHAPPENED(r13) - or r10,r10,r11 - stb r10,PACAIRQHAPPENED(r13) +masked_interrupt_book3e_common: + stb r11,PACAHARDIRQEN(r13) mfspr r10,SPRN_SRR1 rldicl r11,r10,48,1 /* clear MSR_EE */ rotldi r10,r11,16 mtspr SPRN_SRR1,r10 -1: ld r10,PACA_EXGEN+EX_R10(r13); + ld r10,PACA_EXGEN+EX_R10(r13); /* restore registers */ ld r11,PACA_EXGEN+EX_R11(r13); mfspr r13,SPRN_SPRG_GEN_SCRATCH; rfi b . -/* - * Called from arch_local_irq_enable when an interrupt needs - * to be resent. r3 contains either 0x500,0x900,0x260 or 0x280 - * to indicate the kind of interrupt. MSR:EE is already off. - * We generate a stackframe like if a real interrupt had happened. - * - * Note: While MSR:EE is off, we need to make sure that _MSR - * in the generated frame has EE set to 1 or the exception - * handler will not properly re-enable them. - */ -_GLOBAL(__replay_interrupt) - /* We are going to jump to the exception common code which - * will retrieve various register values from the PACA which - * we don't give a damn about. - */ - mflr r10 - mfmsr r11 - mfcr r4 - mtspr SPRN_SPRG_GEN_SCRATCH,r13; - std r1,PACA_EXGEN+EX_R1(r13); - stw r4,PACA_EXGEN+EX_CR(r13); - ori r11,r11,MSR_EE - subi r1,r1,INT_FRAME_SIZE; - cmpwi cr0,r3,0x500 - beq exc_0x500_common - cmpwi cr0,r3,0x900 - beq exc_0x900_common - cmpwi cr0,r3,0x280 - beq exc_0x280_common - blr - /* * This is called from 0x300 and 0x400 handlers after the prologs with @@ -665,6 +591,7 @@ storage_fault_common: mr r5,r15 ld r14,PACA_EXGEN+EX_R14(r13) ld r15,PACA_EXGEN+EX_R15(r13) + INTS_RESTORE_HARD bl .do_page_fault cmpdi r3,0 bne- 1f @@ -753,8 +680,6 @@ BAD_STACK_TRAMPOLINE(0x000) BAD_STACK_TRAMPOLINE(0x100) BAD_STACK_TRAMPOLINE(0x200) BAD_STACK_TRAMPOLINE(0x260) -BAD_STACK_TRAMPOLINE(0x280) -BAD_STACK_TRAMPOLINE(0x2a0) BAD_STACK_TRAMPOLINE(0x2c0) BAD_STACK_TRAMPOLINE(0x2e0) BAD_STACK_TRAMPOLINE(0x300) @@ -772,10 +697,11 @@ BAD_STACK_TRAMPOLINE(0xa00) BAD_STACK_TRAMPOLINE(0xb00) BAD_STACK_TRAMPOLINE(0xc00) BAD_STACK_TRAMPOLINE(0xd00) -BAD_STACK_TRAMPOLINE(0xd08) BAD_STACK_TRAMPOLINE(0xe00) BAD_STACK_TRAMPOLINE(0xf00) BAD_STACK_TRAMPOLINE(0xf20) +BAD_STACK_TRAMPOLINE(0x2070) +BAD_STACK_TRAMPOLINE(0x2080) .globl bad_stack_book3e bad_stack_book3e: diff --git a/trunk/arch/powerpc/kernel/exceptions-64s.S b/trunk/arch/powerpc/kernel/exceptions-64s.S index 2d0868a4e2f0..15c5a4f6de01 100644 --- a/trunk/arch/powerpc/kernel/exceptions-64s.S +++ b/trunk/arch/powerpc/kernel/exceptions-64s.S @@ -12,7 +12,6 @@ * */ -#include #include #include @@ -20,7 +19,7 @@ * We layout physical memory as follows: * 0x0000 - 0x00ff : Secondary processor spin code * 0x0100 - 0x2fff : pSeries Interrupt prologs - * 0x3000 - 0x5fff : interrupt support common interrupt prologs + * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs * 0x6000 - 0x6fff : Initial (CPU0) segment table * 0x7000 - 0x7fff : FWNMI data area * 0x8000 - : Early init and support code @@ -357,60 +356,34 @@ do_stab_bolted_pSeries: KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40) /* - * An interrupt came in while soft-disabled. We set paca->irq_happened, - * then, if it was a decrementer interrupt, we bump the dec to max and - * and return, else we hard disable and return. This is called with - * r10 containing the value to OR to the paca field. + * An interrupt came in while soft-disabled; clear EE in SRR1, + * clear paca->hard_enabled and return. */ -#define MASKED_INTERRUPT(_H) \ -masked_##_H##interrupt: \ - std r11,PACA_EXGEN+EX_R11(r13); \ - lbz r11,PACAIRQHAPPENED(r13); \ - or r11,r11,r10; \ - stb r11,PACAIRQHAPPENED(r13); \ - andi. r10,r10,PACA_IRQ_DEC; \ - beq 1f; \ - lis r10,0x7fff; \ - ori r10,r10,0xffff; \ - mtspr SPRN_DEC,r10; \ - b 2f; \ -1: mfspr r10,SPRN_##_H##SRR1; \ - rldicl r10,r10,48,1; /* clear MSR_EE */ \ - rotldi r10,r10,16; \ - mtspr SPRN_##_H##SRR1,r10; \ -2: mtcrf 0x80,r9; \ - ld r9,PACA_EXGEN+EX_R9(r13); \ - ld r10,PACA_EXGEN+EX_R10(r13); \ - ld r11,PACA_EXGEN+EX_R11(r13); \ - GET_SCRATCH0(r13); \ - ##_H##rfid; \ +masked_interrupt: + stb r10,PACAHARDIRQEN(r13) + mtcrf 0x80,r9 + ld r9,PACA_EXGEN+EX_R9(r13) + mfspr r10,SPRN_SRR1 + rldicl r10,r10,48,1 /* clear MSR_EE */ + rotldi r10,r10,16 + mtspr SPRN_SRR1,r10 + ld r10,PACA_EXGEN+EX_R10(r13) + GET_SCRATCH0(r13) + rfid b . - - MASKED_INTERRUPT() - MASKED_INTERRUPT(H) -/* - * Called from arch_local_irq_enable when an interrupt needs - * to be resent. r3 contains 0x500 or 0x900 to indicate which - * kind of interrupt. MSR:EE is already off. We generate a - * stackframe like if a real interrupt had happened. - * - * Note: While MSR:EE is off, we need to make sure that _MSR - * in the generated frame has EE set to 1 or the exception - * handler will not properly re-enable them. - */ -_GLOBAL(__replay_interrupt) - /* We are going to jump to the exception common code which - * will retrieve various register values from the PACA which - * we don't give a damn about, so we don't bother storing them. - */ - mfmsr r12 - mflr r11 - mfcr r9 - ori r12,r12,MSR_EE - andi. r3,r3,0x0800 - bne decrementer_common - b hardware_interrupt_common +masked_Hinterrupt: + stb r10,PACAHARDIRQEN(r13) + mtcrf 0x80,r9 + ld r9,PACA_EXGEN+EX_R9(r13) + mfspr r10,SPRN_HSRR1 + rldicl r10,r10,48,1 /* clear MSR_EE */ + rotldi r10,r10,16 + mtspr SPRN_HSRR1,r10 + ld r10,PACA_EXGEN+EX_R10(r13) + GET_SCRATCH0(r13) + hrfid + b . #ifdef CONFIG_PPC_PSERIES /* @@ -485,15 +458,14 @@ machine_check_common: bl .machine_check_exception b .ret_from_except - STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) - STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) + STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt) STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception) STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) - STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception) + STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception) STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) #ifdef CONFIG_ALTIVEC STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) @@ -510,9 +482,6 @@ machine_check_common: system_call_entry: b system_call_common -ppc64_runlatch_on_trampoline: - b .__ppc64_runlatch_on - /* * Here we have detected that the kernel stack pointer is bad. * R9 contains the saved CR, r13 points to the paca, @@ -586,8 +555,6 @@ data_access_common: mfspr r10,SPRN_DSISR stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN) - DISABLE_INTS - ld r12,_MSR(r1) ld r3,PACA_EXGEN+EX_DAR(r13) lwz r4,PACA_EXGEN+EX_DSISR(r13) li r5,0x300 @@ -602,7 +569,6 @@ h_data_storage_common: stw r10,PACA_EXGEN+EX_DSISR(r13) EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN) bl .save_nvgprs - DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD bl .unknown_exception b .ret_from_except @@ -611,8 +577,6 @@ h_data_storage_common: .globl instruction_access_common instruction_access_common: EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN) - DISABLE_INTS - ld r12,_MSR(r1) ld r3,_NIP(r1) andis. r4,r12,0x5820 li r5,0x400 @@ -708,6 +672,12 @@ _GLOBAL(slb_miss_realmode) ld r10,PACA_EXSLB+EX_LR(r13) ld r3,PACA_EXSLB+EX_R3(r13) lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ +#ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION + ld r11,PACALPPACAPTR(r13) + ld r11,LPPACASRR0(r11) /* get SRR0 value */ +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +#endif /* CONFIG_PPC_ISERIES */ mtlr r10 @@ -720,6 +690,12 @@ _GLOBAL(slb_miss_realmode) mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ .machine pop +#ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +#endif /* CONFIG_PPC_ISERIES */ ld r9,PACA_EXSLB+EX_R9(r13) ld r10,PACA_EXSLB+EX_R10(r13) ld r11,PACA_EXSLB+EX_R11(r13) @@ -728,7 +704,13 @@ _GLOBAL(slb_miss_realmode) rfid b . /* prevent speculative execution */ -2: mfspr r11,SPRN_SRR0 +2: +#ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION + b unrecov_slb +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +#endif /* CONFIG_PPC_ISERIES */ + mfspr r11,SPRN_SRR0 ld r10,PACAKBASE(r13) LOAD_HANDLER(r10,unrecov_slb) mtspr SPRN_SRR0,r10 @@ -745,6 +727,20 @@ unrecov_slb: bl .unrecoverable_exception b 1b + .align 7 + .globl hardware_interrupt_common + .globl hardware_interrupt_entry +hardware_interrupt_common: + EXCEPTION_PROLOG_COMMON(0x500, PACA_EXGEN) + FINISH_NAP +hardware_interrupt_entry: + DISABLE_INTS +BEGIN_FTR_SECTION + bl .ppc64_runlatch_on +END_FTR_SECTION_IFSET(CPU_FTR_CTRL) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_IRQ + b .ret_from_except_lite #ifdef CONFIG_PPC_970_NAP power4_fixup_nap: @@ -789,8 +785,8 @@ fp_unavailable_common: EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) bne 1f /* if from user, just load it up */ bl .save_nvgprs - DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD + ENABLE_INTS bl .kernel_fp_unavailable_exception BUG_OPCODE 1: bl .load_up_fpu @@ -809,8 +805,8 @@ BEGIN_FTR_SECTION END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) #endif bl .save_nvgprs - DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD + ENABLE_INTS bl .altivec_unavailable_exception b .ret_from_except @@ -820,14 +816,13 @@ vsx_unavailable_common: EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN) #ifdef CONFIG_VSX BEGIN_FTR_SECTION - beq 1f - b .load_up_vsx + bne .load_up_vsx 1: END_FTR_SECTION_IFSET(CPU_FTR_VSX) #endif bl .save_nvgprs - DISABLE_INTS addi r3,r1,STACK_FRAME_OVERHEAD + ENABLE_INTS bl .vsx_unavailable_exception b .ret_from_except @@ -835,6 +830,66 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) .globl __end_handlers __end_handlers: +/* + * Return from an exception with minimal checks. + * The caller is assumed to have done EXCEPTION_PROLOG_COMMON. + * If interrupts have been enabled, or anything has been + * done that might have changed the scheduling status of + * any task or sent any task a signal, you should use + * ret_from_except or ret_from_except_lite instead of this. + */ +fast_exc_return_irq: /* restores irq state too */ + ld r3,SOFTE(r1) + TRACE_AND_RESTORE_IRQ(r3); + ld r12,_MSR(r1) + rldicl r4,r12,49,63 /* get MSR_EE to LSB */ + stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ + b 1f + + .globl fast_exception_return +fast_exception_return: + ld r12,_MSR(r1) +1: ld r11,_NIP(r1) + andi. r3,r12,MSR_RI /* check if RI is set */ + beq- unrecov_fer + +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + andi. r3,r12,MSR_PR + beq 2f + ACCOUNT_CPU_USER_EXIT(r3, r4) +2: +#endif + + ld r3,_CCR(r1) + ld r4,_LINK(r1) + ld r5,_CTR(r1) + ld r6,_XER(r1) + mtcr r3 + mtlr r4 + mtctr r5 + mtxer r6 + REST_GPR(0, r1) + REST_8GPRS(2, r1) + + mfmsr r10 + rldicl r10,r10,48,1 /* clear EE */ + rldicr r10,r10,16,61 /* clear RI (LE is 0 already) */ + mtmsrd r10,1 + + mtspr SPRN_SRR1,r12 + mtspr SPRN_SRR0,r11 + REST_4GPRS(10, r1) + ld r1,GPR1(r1) + rfid + b . /* prevent speculative execution */ + +unrecov_fer: + bl .save_nvgprs +1: addi r3,r1,STACK_FRAME_OVERHEAD + bl .unrecoverable_exception + b 1b + + /* * Hash table stuff */ @@ -857,6 +912,28 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */ andis. r0,r0,NMI_MASK@h /* (i.e. an irq when soft-disabled) */ bne 77f /* then don't call hash_page now */ + + /* + * On iSeries, we soft-disable interrupts here, then + * hard-enable interrupts so that the hash_page code can spin on + * the hash_table_lock without problems on a shared processor. + */ + DISABLE_INTS + + /* + * Currently, trace_hardirqs_off() will be called by DISABLE_INTS + * and will clobber volatile registers when irq tracing is enabled + * so we need to reload them. It may be possible to be smarter here + * and move the irq tracing elsewhere but let's keep it simple for + * now + */ +#ifdef CONFIG_TRACE_IRQFLAGS + ld r3,_DAR(r1) + ld r4,_DSISR(r1) + ld r5,_TRAP(r1) + ld r12,_MSR(r1) + clrrdi r5,r5,4 +#endif /* CONFIG_TRACE_IRQFLAGS */ /* * We need to set the _PAGE_USER bit if MSR_PR is set or if we are * accessing a userspace segment (even from the kernel). We assume @@ -874,25 +951,62 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) * r4 contains the required access permissions * r5 contains the trap number * - * at return r3 = 0 for success, 1 for page fault, negative for error + * at return r3 = 0 for success */ bl .hash_page /* build HPTE if possible */ cmpdi r3,0 /* see if hash_page succeeded */ - /* Success */ +BEGIN_FW_FTR_SECTION + /* + * If we had interrupts soft-enabled at the point where the + * DSI/ISI occurred, and an interrupt came in during hash_page, + * handle it now. + * We jump to ret_from_except_lite rather than fast_exception_return + * because ret_from_except_lite will check for and handle pending + * interrupts if necessary. + */ + beq 13f +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) + +BEGIN_FW_FTR_SECTION + /* + * Here we have interrupts hard-disabled, so it is sufficient + * to restore paca->{soft,hard}_enable and get out. + */ beq fast_exc_return_irq /* Return from exception on success */ +END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) + + /* For a hash failure, we don't bother re-enabling interrupts */ + ble- 12f + + /* + * hash_page couldn't handle it, set soft interrupt enable back + * to what it was before the trap. Note that .arch_local_irq_restore + * handles any interrupts pending at this point. + */ + ld r3,SOFTE(r1) + TRACE_AND_RESTORE_IRQ_PARTIAL(r3, 11f) + bl .arch_local_irq_restore + b 11f - /* Error */ - blt- 13f +/* We have a data breakpoint exception - handle it */ +handle_dabr_fault: + bl .save_nvgprs + ld r4,_DAR(r1) + ld r5,_DSISR(r1) + addi r3,r1,STACK_FRAME_OVERHEAD + bl .do_dabr + b .ret_from_except_lite /* Here we have a page fault that hash_page can't handle. */ handle_page_fault: + ENABLE_INTS 11: ld r4,_DAR(r1) ld r5,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD bl .do_page_fault cmpdi r3,0 - beq+ 12f + beq+ 13f bl .save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD @@ -900,20 +1014,12 @@ handle_page_fault: bl .bad_page_fault b .ret_from_except -/* We have a data breakpoint exception - handle it */ -handle_dabr_fault: - bl .save_nvgprs - ld r4,_DAR(r1) - ld r5,_DSISR(r1) - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_dabr -12: b .ret_from_except_lite - +13: b .ret_from_except_lite /* We have a page fault that hash_page could handle but HV refused * the PTE insertion */ -13: bl .save_nvgprs +12: bl .save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD ld r4,_DAR(r1) @@ -1035,19 +1141,51 @@ _GLOBAL(do_stab_bolted) .= 0x7000 .globl fwnmi_data_area fwnmi_data_area: +#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ + /* iSeries does not use the FWNMI stuff, so it is safe to put + * this here, even if we later allow kernels that will boot on + * both pSeries and iSeries */ +#ifdef CONFIG_PPC_ISERIES + . = LPARMAP_PHYS + .globl xLparMap +xLparMap: + .quad HvEsidsToMap /* xNumberEsids */ + .quad HvRangesToMap /* xNumberRanges */ + .quad STAB0_PAGE /* xSegmentTableOffs */ + .zero 40 /* xRsvd */ + /* xEsids (HvEsidsToMap entries of 2 quads) */ + .quad PAGE_OFFSET_ESID /* xKernelEsid */ + .quad PAGE_OFFSET_VSID /* xKernelVsid */ + .quad VMALLOC_START_ESID /* xKernelEsid */ + .quad VMALLOC_START_VSID /* xKernelVsid */ + /* xRanges (HvRangesToMap entries of 3 quads) */ + .quad HvPagesToMap /* xPages */ + .quad 0 /* xOffset */ + .quad PAGE_OFFSET_VSID << (SID_SHIFT - HW_PAGE_SHIFT) /* xVPN */ + +#endif /* CONFIG_PPC_ISERIES */ + +#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) /* pseries and powernv need to keep the whole page from * 0x7000 to 0x8000 free for use by the firmware */ . = 0x8000 #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ -/* Space for CPU0's segment table */ - .balign 4096 +/* + * Space for CPU0's segment table. + * + * On iSeries, the hypervisor must fill in at least one entry before + * we get control (with relocate on). The address is given to the hv + * as a page number (see xLparMap above), so this must be at a + * fixed address (the linker can't compute (u64)&initial_stab >> + * PAGE_SHIFT). + */ + . = STAB0_OFFSET /* 0x8000 */ .globl initial_stab initial_stab: .space 4096 - #ifdef CONFIG_PPC_POWERNV _GLOBAL(opal_mc_secondary_handler) HMT_MEDIUM diff --git a/trunk/arch/powerpc/kernel/fadump.c b/trunk/arch/powerpc/kernel/fadump.c deleted file mode 100644 index cfe7a38708c3..000000000000 --- a/trunk/arch/powerpc/kernel/fadump.c +++ /dev/null @@ -1,1315 +0,0 @@ -/* - * Firmware Assisted dump: A robust mechanism to get reliable kernel crash - * dump with assistance from firmware. This approach does not use kexec, - * instead firmware assists in booting the kdump kernel while preserving - * memory contents. The most of the code implementation has been adapted - * from phyp assisted dump implementation written by Linas Vepstas and - * Manish Ahuja - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright 2011 IBM Corporation - * Author: Mahesh Salgaonkar - */ - -#undef DEBUG -#define pr_fmt(fmt) "fadump: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -static struct fw_dump fw_dump; -static struct fadump_mem_struct fdm; -static const struct fadump_mem_struct *fdm_active; - -static DEFINE_MUTEX(fadump_mutex); -struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES]; -int crash_mem_ranges; - -/* Scan the Firmware Assisted dump configuration details. */ -int __init early_init_dt_scan_fw_dump(unsigned long node, - const char *uname, int depth, void *data) -{ - __be32 *sections; - int i, num_sections; - unsigned long size; - const int *token; - - if (depth != 1 || strcmp(uname, "rtas") != 0) - return 0; - - /* - * Check if Firmware Assisted dump is supported. if yes, check - * if dump has been initiated on last reboot. - */ - token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL); - if (!token) - return 0; - - fw_dump.fadump_supported = 1; - fw_dump.ibm_configure_kernel_dump = *token; - - /* - * The 'ibm,kernel-dump' rtas node is present only if there is - * dump data waiting for us. - */ - fdm_active = of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL); - if (fdm_active) - fw_dump.dump_active = 1; - - /* Get the sizes required to store dump data for the firmware provided - * dump sections. - * For each dump section type supported, a 32bit cell which defines - * the ID of a supported section followed by two 32 bit cells which - * gives teh size of the section in bytes. - */ - sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes", - &size); - - if (!sections) - return 0; - - num_sections = size / (3 * sizeof(u32)); - - for (i = 0; i < num_sections; i++, sections += 3) { - u32 type = (u32)of_read_number(sections, 1); - - switch (type) { - case FADUMP_CPU_STATE_DATA: - fw_dump.cpu_state_data_size = - of_read_ulong(§ions[1], 2); - break; - case FADUMP_HPTE_REGION: - fw_dump.hpte_region_size = - of_read_ulong(§ions[1], 2); - break; - } - } - return 1; -} - -int is_fadump_active(void) -{ - return fw_dump.dump_active; -} - -/* Print firmware assisted dump configurations for debugging purpose. */ -static void fadump_show_config(void) -{ - pr_debug("Support for firmware-assisted dump (fadump): %s\n", - (fw_dump.fadump_supported ? "present" : "no support")); - - if (!fw_dump.fadump_supported) - return; - - pr_debug("Fadump enabled : %s\n", - (fw_dump.fadump_enabled ? "yes" : "no")); - pr_debug("Dump Active : %s\n", - (fw_dump.dump_active ? "yes" : "no")); - pr_debug("Dump section sizes:\n"); - pr_debug(" CPU state data size: %lx\n", fw_dump.cpu_state_data_size); - pr_debug(" HPTE region size : %lx\n", fw_dump.hpte_region_size); - pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size); -} - -static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm, - unsigned long addr) -{ - if (!fdm) - return 0; - - memset(fdm, 0, sizeof(struct fadump_mem_struct)); - addr = addr & PAGE_MASK; - - fdm->header.dump_format_version = 0x00000001; - fdm->header.dump_num_sections = 3; - fdm->header.dump_status_flag = 0; - fdm->header.offset_first_dump_section = - (u32)offsetof(struct fadump_mem_struct, cpu_state_data); - - /* - * Fields for disk dump option. - * We are not using disk dump option, hence set these fields to 0. - */ - fdm->header.dd_block_size = 0; - fdm->header.dd_block_offset = 0; - fdm->header.dd_num_blocks = 0; - fdm->header.dd_offset_disk_path = 0; - - /* set 0 to disable an automatic dump-reboot. */ - fdm->header.max_time_auto = 0; - - /* Kernel dump sections */ - /* cpu state data section. */ - fdm->cpu_state_data.request_flag = FADUMP_REQUEST_FLAG; - fdm->cpu_state_data.source_data_type = FADUMP_CPU_STATE_DATA; - fdm->cpu_state_data.source_address = 0; - fdm->cpu_state_data.source_len = fw_dump.cpu_state_data_size; - fdm->cpu_state_data.destination_address = addr; - addr += fw_dump.cpu_state_data_size; - - /* hpte region section */ - fdm->hpte_region.request_flag = FADUMP_REQUEST_FLAG; - fdm->hpte_region.source_data_type = FADUMP_HPTE_REGION; - fdm->hpte_region.source_address = 0; - fdm->hpte_region.source_len = fw_dump.hpte_region_size; - fdm->hpte_region.destination_address = addr; - addr += fw_dump.hpte_region_size; - - /* RMA region section */ - fdm->rmr_region.request_flag = FADUMP_REQUEST_FLAG; - fdm->rmr_region.source_data_type = FADUMP_REAL_MODE_REGION; - fdm->rmr_region.source_address = RMA_START; - fdm->rmr_region.source_len = fw_dump.boot_memory_size; - fdm->rmr_region.destination_address = addr; - addr += fw_dump.boot_memory_size; - - return addr; -} - -/** - * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM - * - * Function to find the largest memory size we need to reserve during early - * boot process. This will be the size of the memory that is required for a - * kernel to boot successfully. - * - * This function has been taken from phyp-assisted dump feature implementation. - * - * returns larger of 256MB or 5% rounded down to multiples of 256MB. - * - * TODO: Come up with better approach to find out more accurate memory size - * that is required for a kernel to boot successfully. - * - */ -static inline unsigned long fadump_calculate_reserve_size(void) -{ - unsigned long size; - - /* - * Check if the size is specified through fadump_reserve_mem= cmdline - * option. If yes, then use that. - */ - if (fw_dump.reserve_bootvar) - return fw_dump.reserve_bootvar; - - /* divide by 20 to get 5% of value */ - size = memblock_end_of_DRAM() / 20; - - /* round it down in multiples of 256 */ - size = size & ~0x0FFFFFFFUL; - - /* Truncate to memory_limit. We don't want to over reserve the memory.*/ - if (memory_limit && size > memory_limit) - size = memory_limit; - - return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM); -} - -/* - * Calculate the total memory size required to be reserved for - * firmware-assisted dump registration. - */ -static unsigned long get_fadump_area_size(void) -{ - unsigned long size = 0; - - size += fw_dump.cpu_state_data_size; - size += fw_dump.hpte_region_size; - size += fw_dump.boot_memory_size; - size += sizeof(struct fadump_crash_info_header); - size += sizeof(struct elfhdr); /* ELF core header.*/ - size += sizeof(struct elf_phdr); /* place holder for cpu notes */ - /* Program headers for crash memory regions. */ - size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2); - - size = PAGE_ALIGN(size); - return size; -} - -int __init fadump_reserve_mem(void) -{ - unsigned long base, size, memory_boundary; - - if (!fw_dump.fadump_enabled) - return 0; - - if (!fw_dump.fadump_supported) { - printk(KERN_INFO "Firmware-assisted dump is not supported on" - " this hardware\n"); - fw_dump.fadump_enabled = 0; - return 0; - } - /* - * Initialize boot memory size - * If dump is active then we have already calculated the size during - * first kernel. - */ - if (fdm_active) - fw_dump.boot_memory_size = fdm_active->rmr_region.source_len; - else - fw_dump.boot_memory_size = fadump_calculate_reserve_size(); - - /* - * Calculate the memory boundary. - * If memory_limit is less than actual memory boundary then reserve - * the memory for fadump beyond the memory_limit and adjust the - * memory_limit accordingly, so that the running kernel can run with - * specified memory_limit. - */ - if (memory_limit && memory_limit < memblock_end_of_DRAM()) { - size = get_fadump_area_size(); - if ((memory_limit + size) < memblock_end_of_DRAM()) - memory_limit += size; - else - memory_limit = memblock_end_of_DRAM(); - printk(KERN_INFO "Adjusted memory_limit for firmware-assisted" - " dump, now %#016llx\n", - (unsigned long long)memory_limit); - } - if (memory_limit) - memory_boundary = memory_limit; - else - memory_boundary = memblock_end_of_DRAM(); - - if (fw_dump.dump_active) { - printk(KERN_INFO "Firmware-assisted dump is active.\n"); - /* - * If last boot has crashed then reserve all the memory - * above boot_memory_size so that we don't touch it until - * dump is written to disk by userspace tool. This memory - * will be released for general use once the dump is saved. - */ - base = fw_dump.boot_memory_size; - size = memory_boundary - base; - memblock_reserve(base, size); - printk(KERN_INFO "Reserved %ldMB of memory at %ldMB " - "for saving crash dump\n", - (unsigned long)(size >> 20), - (unsigned long)(base >> 20)); - - fw_dump.fadumphdr_addr = - fdm_active->rmr_region.destination_address + - fdm_active->rmr_region.source_len; - pr_debug("fadumphdr_addr = %p\n", - (void *) fw_dump.fadumphdr_addr); - } else { - /* Reserve the memory at the top of memory. */ - size = get_fadump_area_size(); - base = memory_boundary - size; - memblock_reserve(base, size); - printk(KERN_INFO "Reserved %ldMB of memory at %ldMB " - "for firmware-assisted dump\n", - (unsigned long)(size >> 20), - (unsigned long)(base >> 20)); - } - fw_dump.reserve_dump_area_start = base; - fw_dump.reserve_dump_area_size = size; - return 1; -} - -/* Look for fadump= cmdline option. */ -static int __init early_fadump_param(char *p) -{ - if (!p) - return 1; - - if (strncmp(p, "on", 2) == 0) - fw_dump.fadump_enabled = 1; - else if (strncmp(p, "off", 3) == 0) - fw_dump.fadump_enabled = 0; - - return 0; -} -early_param("fadump", early_fadump_param); - -/* Look for fadump_reserve_mem= cmdline option */ -static int __init early_fadump_reserve_mem(char *p) -{ - if (p) - fw_dump.reserve_bootvar = memparse(p, &p); - return 0; -} -early_param("fadump_reserve_mem", early_fadump_reserve_mem); - -static void register_fw_dump(struct fadump_mem_struct *fdm) -{ - int rc; - unsigned int wait_time; - - pr_debug("Registering for firmware-assisted kernel dump...\n"); - - /* TODO: Add upper time limit for the delay */ - do { - rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, - FADUMP_REGISTER, fdm, - sizeof(struct fadump_mem_struct)); - - wait_time = rtas_busy_delay_time(rc); - if (wait_time) - mdelay(wait_time); - - } while (wait_time); - - switch (rc) { - case -1: - printk(KERN_ERR "Failed to register firmware-assisted kernel" - " dump. Hardware Error(%d).\n", rc); - break; - case -3: - printk(KERN_ERR "Failed to register firmware-assisted kernel" - " dump. Parameter Error(%d).\n", rc); - break; - case -9: - printk(KERN_ERR "firmware-assisted kernel dump is already " - " registered."); - fw_dump.dump_registered = 1; - break; - case 0: - printk(KERN_INFO "firmware-assisted kernel dump registration" - " is successful\n"); - fw_dump.dump_registered = 1; - break; - } -} - -void crash_fadump(struct pt_regs *regs, const char *str) -{ - struct fadump_crash_info_header *fdh = NULL; - - if (!fw_dump.dump_registered || !fw_dump.fadumphdr_addr) - return; - - fdh = __va(fw_dump.fadumphdr_addr); - crashing_cpu = smp_processor_id(); - fdh->crashing_cpu = crashing_cpu; - crash_save_vmcoreinfo(); - - if (regs) - fdh->regs = *regs; - else - ppc_save_regs(&fdh->regs); - - fdh->cpu_online_mask = *cpu_online_mask; - - /* Call ibm,os-term rtas call to trigger firmware assisted dump */ - rtas_os_term((char *)str); -} - -#define GPR_MASK 0xffffff0000000000 -static inline int fadump_gpr_index(u64 id) -{ - int i = -1; - char str[3]; - - if ((id & GPR_MASK) == REG_ID("GPR")) { - /* get the digits at the end */ - id &= ~GPR_MASK; - id >>= 24; - str[2] = '\0'; - str[1] = id & 0xff; - str[0] = (id >> 8) & 0xff; - sscanf(str, "%d", &i); - if (i > 31) - i = -1; - } - return i; -} - -static inline void fadump_set_regval(struct pt_regs *regs, u64 reg_id, - u64 reg_val) -{ - int i; - - i = fadump_gpr_index(reg_id); - if (i >= 0) - regs->gpr[i] = (unsigned long)reg_val; - else if (reg_id == REG_ID("NIA")) - regs->nip = (unsigned long)reg_val; - else if (reg_id == REG_ID("MSR")) - regs->msr = (unsigned long)reg_val; - else if (reg_id == REG_ID("CTR")) - regs->ctr = (unsigned long)reg_val; - else if (reg_id == REG_ID("LR")) - regs->link = (unsigned long)reg_val; - else if (reg_id == REG_ID("XER")) - regs->xer = (unsigned long)reg_val; - else if (reg_id == REG_ID("CR")) - regs->ccr = (unsigned long)reg_val; - else if (reg_id == REG_ID("DAR")) - regs->dar = (unsigned long)reg_val; - else if (reg_id == REG_ID("DSISR")) - regs->dsisr = (unsigned long)reg_val; -} - -static struct fadump_reg_entry* -fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs) -{ - memset(regs, 0, sizeof(struct pt_regs)); - - while (reg_entry->reg_id != REG_ID("CPUEND")) { - fadump_set_regval(regs, reg_entry->reg_id, - reg_entry->reg_value); - reg_entry++; - } - reg_entry++; - return reg_entry; -} - -static u32 *fadump_append_elf_note(u32 *buf, char *name, unsigned type, - void *data, size_t data_len) -{ - struct elf_note note; - - note.n_namesz = strlen(name) + 1; - note.n_descsz = data_len; - note.n_type = type; - memcpy(buf, ¬e, sizeof(note)); - buf += (sizeof(note) + 3)/4; - memcpy(buf, name, note.n_namesz); - buf += (note.n_namesz + 3)/4; - memcpy(buf, data, note.n_descsz); - buf += (note.n_descsz + 3)/4; - - return buf; -} - -static void fadump_final_note(u32 *buf) -{ - struct elf_note note; - - note.n_namesz = 0; - note.n_descsz = 0; - note.n_type = 0; - memcpy(buf, ¬e, sizeof(note)); -} - -static u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs) -{ - struct elf_prstatus prstatus; - - memset(&prstatus, 0, sizeof(prstatus)); - /* - * FIXME: How do i get PID? Do I really need it? - * prstatus.pr_pid = ???? - */ - elf_core_copy_kernel_regs(&prstatus.pr_reg, regs); - buf = fadump_append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, - &prstatus, sizeof(prstatus)); - return buf; -} - -static void fadump_update_elfcore_header(char *bufp) -{ - struct elfhdr *elf; - struct elf_phdr *phdr; - - elf = (struct elfhdr *)bufp; - bufp += sizeof(struct elfhdr); - - /* First note is a place holder for cpu notes info. */ - phdr = (struct elf_phdr *)bufp; - - if (phdr->p_type == PT_NOTE) { - phdr->p_paddr = fw_dump.cpu_notes_buf; - phdr->p_offset = phdr->p_paddr; - phdr->p_filesz = fw_dump.cpu_notes_buf_size; - phdr->p_memsz = fw_dump.cpu_notes_buf_size; - } - return; -} - -static void *fadump_cpu_notes_buf_alloc(unsigned long size) -{ - void *vaddr; - struct page *page; - unsigned long order, count, i; - - order = get_order(size); - vaddr = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, order); - if (!vaddr) - return NULL; - - count = 1 << order; - page = virt_to_page(vaddr); - for (i = 0; i < count; i++) - SetPageReserved(page + i); - return vaddr; -} - -static void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size) -{ - struct page *page; - unsigned long order, count, i; - - order = get_order(size); - count = 1 << order; - page = virt_to_page(vaddr); - for (i = 0; i < count; i++) - ClearPageReserved(page + i); - __free_pages(page, order); -} - -/* - * Read CPU state dump data and convert it into ELF notes. - * The CPU dump starts with magic number "REGSAVE". NumCpusOffset should be - * used to access the data to allow for additional fields to be added without - * affecting compatibility. Each list of registers for a CPU starts with - * "CPUSTRT" and ends with "CPUEND". Each register entry is of 16 bytes, - * 8 Byte ASCII identifier and 8 Byte register value. The register entry - * with identifier "CPUSTRT" and "CPUEND" contains 4 byte cpu id as part - * of register value. For more details refer to PAPR document. - * - * Only for the crashing cpu we ignore the CPU dump data and get exact - * state from fadump crash info structure populated by first kernel at the - * time of crash. - */ -static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm) -{ - struct fadump_reg_save_area_header *reg_header; - struct fadump_reg_entry *reg_entry; - struct fadump_crash_info_header *fdh = NULL; - void *vaddr; - unsigned long addr; - u32 num_cpus, *note_buf; - struct pt_regs regs; - int i, rc = 0, cpu = 0; - - if (!fdm->cpu_state_data.bytes_dumped) - return -EINVAL; - - addr = fdm->cpu_state_data.destination_address; - vaddr = __va(addr); - - reg_header = vaddr; - if (reg_header->magic_number != REGSAVE_AREA_MAGIC) { - printk(KERN_ERR "Unable to read register save area.\n"); - return -ENOENT; - } - pr_debug("--------CPU State Data------------\n"); - pr_debug("Magic Number: %llx\n", reg_header->magic_number); - pr_debug("NumCpuOffset: %x\n", reg_header->num_cpu_offset); - - vaddr += reg_header->num_cpu_offset; - num_cpus = *((u32 *)(vaddr)); - pr_debug("NumCpus : %u\n", num_cpus); - vaddr += sizeof(u32); - reg_entry = (struct fadump_reg_entry *)vaddr; - - /* Allocate buffer to hold cpu crash notes. */ - fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t); - fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size); - note_buf = fadump_cpu_notes_buf_alloc(fw_dump.cpu_notes_buf_size); - if (!note_buf) { - printk(KERN_ERR "Failed to allocate 0x%lx bytes for " - "cpu notes buffer\n", fw_dump.cpu_notes_buf_size); - return -ENOMEM; - } - fw_dump.cpu_notes_buf = __pa(note_buf); - - pr_debug("Allocated buffer for cpu notes of size %ld at %p\n", - (num_cpus * sizeof(note_buf_t)), note_buf); - - if (fw_dump.fadumphdr_addr) - fdh = __va(fw_dump.fadumphdr_addr); - - for (i = 0; i < num_cpus; i++) { - if (reg_entry->reg_id != REG_ID("CPUSTRT")) { - printk(KERN_ERR "Unable to read CPU state data\n"); - rc = -ENOENT; - goto error_out; - } - /* Lower 4 bytes of reg_value contains logical cpu id */ - cpu = reg_entry->reg_value & FADUMP_CPU_ID_MASK; - if (!cpumask_test_cpu(cpu, &fdh->cpu_online_mask)) { - SKIP_TO_NEXT_CPU(reg_entry); - continue; - } - pr_debug("Reading register data for cpu %d...\n", cpu); - if (fdh && fdh->crashing_cpu == cpu) { - regs = fdh->regs; - note_buf = fadump_regs_to_elf_notes(note_buf, ®s); - SKIP_TO_NEXT_CPU(reg_entry); - } else { - reg_entry++; - reg_entry = fadump_read_registers(reg_entry, ®s); - note_buf = fadump_regs_to_elf_notes(note_buf, ®s); - } - } - fadump_final_note(note_buf); - - pr_debug("Updating elfcore header (%llx) with cpu notes\n", - fdh->elfcorehdr_addr); - fadump_update_elfcore_header((char *)__va(fdh->elfcorehdr_addr)); - return 0; - -error_out: - fadump_cpu_notes_buf_free((unsigned long)__va(fw_dump.cpu_notes_buf), - fw_dump.cpu_notes_buf_size); - fw_dump.cpu_notes_buf = 0; - fw_dump.cpu_notes_buf_size = 0; - return rc; - -} - -/* - * Validate and process the dump data stored by firmware before exporting - * it through '/proc/vmcore'. - */ -static int __init process_fadump(const struct fadump_mem_struct *fdm_active) -{ - struct fadump_crash_info_header *fdh; - int rc = 0; - - if (!fdm_active || !fw_dump.fadumphdr_addr) - return -EINVAL; - - /* Check if the dump data is valid. */ - if ((fdm_active->header.dump_status_flag == FADUMP_ERROR_FLAG) || - (fdm_active->cpu_state_data.error_flags != 0) || - (fdm_active->rmr_region.error_flags != 0)) { - printk(KERN_ERR "Dump taken by platform is not valid\n"); - return -EINVAL; - } - if ((fdm_active->rmr_region.bytes_dumped != - fdm_active->rmr_region.source_len) || - !fdm_active->cpu_state_data.bytes_dumped) { - printk(KERN_ERR "Dump taken by platform is incomplete\n"); - return -EINVAL; - } - - /* Validate the fadump crash info header */ - fdh = __va(fw_dump.fadumphdr_addr); - if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) { - printk(KERN_ERR "Crash info header is not valid.\n"); - return -EINVAL; - } - - rc = fadump_build_cpu_notes(fdm_active); - if (rc) - return rc; - - /* - * We are done validating dump info and elfcore header is now ready - * to be exported. set elfcorehdr_addr so that vmcore module will - * export the elfcore header through '/proc/vmcore'. - */ - elfcorehdr_addr = fdh->elfcorehdr_addr; - - return 0; -} - -static inline void fadump_add_crash_memory(unsigned long long base, - unsigned long long end) -{ - if (base == end) - return; - - pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n", - crash_mem_ranges, base, end - 1, (end - base)); - crash_memory_ranges[crash_mem_ranges].base = base; - crash_memory_ranges[crash_mem_ranges].size = end - base; - crash_mem_ranges++; -} - -static void fadump_exclude_reserved_area(unsigned long long start, - unsigned long long end) -{ - unsigned long long ra_start, ra_end; - - ra_start = fw_dump.reserve_dump_area_start; - ra_end = ra_start + fw_dump.reserve_dump_area_size; - - if ((ra_start < end) && (ra_end > start)) { - if ((start < ra_start) && (end > ra_end)) { - fadump_add_crash_memory(start, ra_start); - fadump_add_crash_memory(ra_end, end); - } else if (start < ra_start) { - fadump_add_crash_memory(start, ra_start); - } else if (ra_end < end) { - fadump_add_crash_memory(ra_end, end); - } - } else - fadump_add_crash_memory(start, end); -} - -static int fadump_init_elfcore_header(char *bufp) -{ - struct elfhdr *elf; - - elf = (struct elfhdr *) bufp; - bufp += sizeof(struct elfhdr); - memcpy(elf->e_ident, ELFMAG, SELFMAG); - elf->e_ident[EI_CLASS] = ELF_CLASS; - elf->e_ident[EI_DATA] = ELF_DATA; - elf->e_ident[EI_VERSION] = EV_CURRENT; - elf->e_ident[EI_OSABI] = ELF_OSABI; - memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); - elf->e_type = ET_CORE; - elf->e_machine = ELF_ARCH; - elf->e_version = EV_CURRENT; - elf->e_entry = 0; - elf->e_phoff = sizeof(struct elfhdr); - elf->e_shoff = 0; - elf->e_flags = ELF_CORE_EFLAGS; - elf->e_ehsize = sizeof(struct elfhdr); - elf->e_phentsize = sizeof(struct elf_phdr); - elf->e_phnum = 0; - elf->e_shentsize = 0; - elf->e_shnum = 0; - elf->e_shstrndx = 0; - - return 0; -} - -/* - * Traverse through memblock structure and setup crash memory ranges. These - * ranges will be used create PT_LOAD program headers in elfcore header. - */ -static void fadump_setup_crash_memory_ranges(void) -{ - struct memblock_region *reg; - unsigned long long start, end; - - pr_debug("Setup crash memory ranges.\n"); - crash_mem_ranges = 0; - /* - * add the first memory chunk (RMA_START through boot_memory_size) as - * a separate memory chunk. The reason is, at the time crash firmware - * will move the content of this memory chunk to different location - * specified during fadump registration. We need to create a separate - * program header for this chunk with the correct offset. - */ - fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size); - - for_each_memblock(memory, reg) { - start = (unsigned long long)reg->base; - end = start + (unsigned long long)reg->size; - if (start == RMA_START && end >= fw_dump.boot_memory_size) - start = fw_dump.boot_memory_size; - - /* add this range excluding the reserved dump area. */ - fadump_exclude_reserved_area(start, end); - } -} - -/* - * If the given physical address falls within the boot memory region then - * return the relocated address that points to the dump region reserved - * for saving initial boot memory contents. - */ -static inline unsigned long fadump_relocate(unsigned long paddr) -{ - if (paddr > RMA_START && paddr < fw_dump.boot_memory_size) - return fdm.rmr_region.destination_address + paddr; - else - return paddr; -} - -static int fadump_create_elfcore_headers(char *bufp) -{ - struct elfhdr *elf; - struct elf_phdr *phdr; - int i; - - fadump_init_elfcore_header(bufp); - elf = (struct elfhdr *)bufp; - bufp += sizeof(struct elfhdr); - - /* - * setup ELF PT_NOTE, place holder for cpu notes info. The notes info - * will be populated during second kernel boot after crash. Hence - * this PT_NOTE will always be the first elf note. - * - * NOTE: Any new ELF note addition should be placed after this note. - */ - phdr = (struct elf_phdr *)bufp; - bufp += sizeof(struct elf_phdr); - phdr->p_type = PT_NOTE; - phdr->p_flags = 0; - phdr->p_vaddr = 0; - phdr->p_align = 0; - - phdr->p_offset = 0; - phdr->p_paddr = 0; - phdr->p_filesz = 0; - phdr->p_memsz = 0; - - (elf->e_phnum)++; - - /* setup ELF PT_NOTE for vmcoreinfo */ - phdr = (struct elf_phdr *)bufp; - bufp += sizeof(struct elf_phdr); - phdr->p_type = PT_NOTE; - phdr->p_flags = 0; - phdr->p_vaddr = 0; - phdr->p_align = 0; - - phdr->p_paddr = fadump_relocate(paddr_vmcoreinfo_note()); - phdr->p_offset = phdr->p_paddr; - phdr->p_memsz = vmcoreinfo_max_size; - phdr->p_filesz = vmcoreinfo_max_size; - - /* Increment number of program headers. */ - (elf->e_phnum)++; - - /* setup PT_LOAD sections. */ - - for (i = 0; i < crash_mem_ranges; i++) { - unsigned long long mbase, msize; - mbase = crash_memory_ranges[i].base; - msize = crash_memory_ranges[i].size; - - if (!msize) - continue; - - phdr = (struct elf_phdr *)bufp; - bufp += sizeof(struct elf_phdr); - phdr->p_type = PT_LOAD; - phdr->p_flags = PF_R|PF_W|PF_X; - phdr->p_offset = mbase; - - if (mbase == RMA_START) { - /* - * The entire RMA region will be moved by firmware - * to the specified destination_address. Hence set - * the correct offset. - */ - phdr->p_offset = fdm.rmr_region.destination_address; - } - - phdr->p_paddr = mbase; - phdr->p_vaddr = (unsigned long)__va(mbase); - phdr->p_filesz = msize; - phdr->p_memsz = msize; - phdr->p_align = 0; - - /* Increment number of program headers. */ - (elf->e_phnum)++; - } - return 0; -} - -static unsigned long init_fadump_header(unsigned long addr) -{ - struct fadump_crash_info_header *fdh; - - if (!addr) - return 0; - - fw_dump.fadumphdr_addr = addr; - fdh = __va(addr); - addr += sizeof(struct fadump_crash_info_header); - - memset(fdh, 0, sizeof(struct fadump_crash_info_header)); - fdh->magic_number = FADUMP_CRASH_INFO_MAGIC; - fdh->elfcorehdr_addr = addr; - /* We will set the crashing cpu id in crash_fadump() during crash. */ - fdh->crashing_cpu = CPU_UNKNOWN; - - return addr; -} - -static void register_fadump(void) -{ - unsigned long addr; - void *vaddr; - - /* - * If no memory is reserved then we can not register for firmware- - * assisted dump. - */ - if (!fw_dump.reserve_dump_area_size) - return; - - fadump_setup_crash_memory_ranges(); - - addr = fdm.rmr_region.destination_address + fdm.rmr_region.source_len; - /* Initialize fadump crash info header. */ - addr = init_fadump_header(addr); - vaddr = __va(addr); - - pr_debug("Creating ELF core headers at %#016lx\n", addr); - fadump_create_elfcore_headers(vaddr); - - /* register the future kernel dump with firmware. */ - register_fw_dump(&fdm); -} - -static int fadump_unregister_dump(struct fadump_mem_struct *fdm) -{ - int rc = 0; - unsigned int wait_time; - - pr_debug("Un-register firmware-assisted dump\n"); - - /* TODO: Add upper time limit for the delay */ - do { - rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, - FADUMP_UNREGISTER, fdm, - sizeof(struct fadump_mem_struct)); - - wait_time = rtas_busy_delay_time(rc); - if (wait_time) - mdelay(wait_time); - } while (wait_time); - - if (rc) { - printk(KERN_ERR "Failed to un-register firmware-assisted dump." - " unexpected error(%d).\n", rc); - return rc; - } - fw_dump.dump_registered = 0; - return 0; -} - -static int fadump_invalidate_dump(struct fadump_mem_struct *fdm) -{ - int rc = 0; - unsigned int wait_time; - - pr_debug("Invalidating firmware-assisted dump registration\n"); - - /* TODO: Add upper time limit for the delay */ - do { - rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, - FADUMP_INVALIDATE, fdm, - sizeof(struct fadump_mem_struct)); - - wait_time = rtas_busy_delay_time(rc); - if (wait_time) - mdelay(wait_time); - } while (wait_time); - - if (rc) { - printk(KERN_ERR "Failed to invalidate firmware-assisted dump " - "rgistration. unexpected error(%d).\n", rc); - return rc; - } - fw_dump.dump_active = 0; - fdm_active = NULL; - return 0; -} - -void fadump_cleanup(void) -{ - /* Invalidate the registration only if dump is active. */ - if (fw_dump.dump_active) { - init_fadump_mem_struct(&fdm, - fdm_active->cpu_state_data.destination_address); - fadump_invalidate_dump(&fdm); - } -} - -/* - * Release the memory that was reserved in early boot to preserve the memory - * contents. The released memory will be available for general use. - */ -static void fadump_release_memory(unsigned long begin, unsigned long end) -{ - unsigned long addr; - unsigned long ra_start, ra_end; - - ra_start = fw_dump.reserve_dump_area_start; - ra_end = ra_start + fw_dump.reserve_dump_area_size; - - for (addr = begin; addr < end; addr += PAGE_SIZE) { - /* - * exclude the dump reserve area. Will reuse it for next - * fadump registration. - */ - if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start)) - continue; - - ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT)); - init_page_count(pfn_to_page(addr >> PAGE_SHIFT)); - free_page((unsigned long)__va(addr)); - totalram_pages++; - } -} - -static void fadump_invalidate_release_mem(void) -{ - unsigned long reserved_area_start, reserved_area_end; - unsigned long destination_address; - - mutex_lock(&fadump_mutex); - if (!fw_dump.dump_active) { - mutex_unlock(&fadump_mutex); - return; - } - - destination_address = fdm_active->cpu_state_data.destination_address; - fadump_cleanup(); - mutex_unlock(&fadump_mutex); - - /* - * Save the current reserved memory bounds we will require them - * later for releasing the memory for general use. - */ - reserved_area_start = fw_dump.reserve_dump_area_start; - reserved_area_end = reserved_area_start + - fw_dump.reserve_dump_area_size; - /* - * Setup reserve_dump_area_start and its size so that we can - * reuse this reserved memory for Re-registration. - */ - fw_dump.reserve_dump_area_start = destination_address; - fw_dump.reserve_dump_area_size = get_fadump_area_size(); - - fadump_release_memory(reserved_area_start, reserved_area_end); - if (fw_dump.cpu_notes_buf) { - fadump_cpu_notes_buf_free( - (unsigned long)__va(fw_dump.cpu_notes_buf), - fw_dump.cpu_notes_buf_size); - fw_dump.cpu_notes_buf = 0; - fw_dump.cpu_notes_buf_size = 0; - } - /* Initialize the kernel dump memory structure for FAD registration. */ - init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start); -} - -static ssize_t fadump_release_memory_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - if (!fw_dump.dump_active) - return -EPERM; - - if (buf[0] == '1') { - /* - * Take away the '/proc/vmcore'. We are releasing the dump - * memory, hence it will not be valid anymore. - */ - vmcore_cleanup(); - fadump_invalidate_release_mem(); - - } else - return -EINVAL; - return count; -} - -static ssize_t fadump_enabled_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - return sprintf(buf, "%d\n", fw_dump.fadump_enabled); -} - -static ssize_t fadump_register_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - return sprintf(buf, "%d\n", fw_dump.dump_registered); -} - -static ssize_t fadump_register_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - int ret = 0; - - if (!fw_dump.fadump_enabled || fdm_active) - return -EPERM; - - mutex_lock(&fadump_mutex); - - switch (buf[0]) { - case '0': - if (fw_dump.dump_registered == 0) { - ret = -EINVAL; - goto unlock_out; - } - /* Un-register Firmware-assisted dump */ - fadump_unregister_dump(&fdm); - break; - case '1': - if (fw_dump.dump_registered == 1) { - ret = -EINVAL; - goto unlock_out; - } - /* Register Firmware-assisted dump */ - register_fadump(); - break; - default: - ret = -EINVAL; - break; - } - -unlock_out: - mutex_unlock(&fadump_mutex); - return ret < 0 ? ret : count; -} - -static int fadump_region_show(struct seq_file *m, void *private) -{ - const struct fadump_mem_struct *fdm_ptr; - - if (!fw_dump.fadump_enabled) - return 0; - - mutex_lock(&fadump_mutex); - if (fdm_active) - fdm_ptr = fdm_active; - else { - mutex_unlock(&fadump_mutex); - fdm_ptr = &fdm; - } - - seq_printf(m, - "CPU : [%#016llx-%#016llx] %#llx bytes, " - "Dumped: %#llx\n", - fdm_ptr->cpu_state_data.destination_address, - fdm_ptr->cpu_state_data.destination_address + - fdm_ptr->cpu_state_data.source_len - 1, - fdm_ptr->cpu_state_data.source_len, - fdm_ptr->cpu_state_data.bytes_dumped); - seq_printf(m, - "HPTE: [%#016llx-%#016llx] %#llx bytes, " - "Dumped: %#llx\n", - fdm_ptr->hpte_region.destination_address, - fdm_ptr->hpte_region.destination_address + - fdm_ptr->hpte_region.source_len - 1, - fdm_ptr->hpte_region.source_len, - fdm_ptr->hpte_region.bytes_dumped); - seq_printf(m, - "DUMP: [%#016llx-%#016llx] %#llx bytes, " - "Dumped: %#llx\n", - fdm_ptr->rmr_region.destination_address, - fdm_ptr->rmr_region.destination_address + - fdm_ptr->rmr_region.source_len - 1, - fdm_ptr->rmr_region.source_len, - fdm_ptr->rmr_region.bytes_dumped); - - if (!fdm_active || - (fw_dump.reserve_dump_area_start == - fdm_ptr->cpu_state_data.destination_address)) - goto out; - - /* Dump is active. Show reserved memory region. */ - seq_printf(m, - " : [%#016llx-%#016llx] %#llx bytes, " - "Dumped: %#llx\n", - (unsigned long long)fw_dump.reserve_dump_area_start, - fdm_ptr->cpu_state_data.destination_address - 1, - fdm_ptr->cpu_state_data.destination_address - - fw_dump.reserve_dump_area_start, - fdm_ptr->cpu_state_data.destination_address - - fw_dump.reserve_dump_area_start); -out: - if (fdm_active) - mutex_unlock(&fadump_mutex); - return 0; -} - -static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem, - 0200, NULL, - fadump_release_memory_store); -static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled, - 0444, fadump_enabled_show, - NULL); -static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered, - 0644, fadump_register_show, - fadump_register_store); - -static int fadump_region_open(struct inode *inode, struct file *file) -{ - return single_open(file, fadump_region_show, inode->i_private); -} - -static const struct file_operations fadump_region_fops = { - .open = fadump_region_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void fadump_init_files(void) -{ - struct dentry *debugfs_file; - int rc = 0; - - rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr); - if (rc) - printk(KERN_ERR "fadump: unable to create sysfs file" - " fadump_enabled (%d)\n", rc); - - rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr); - if (rc) - printk(KERN_ERR "fadump: unable to create sysfs file" - " fadump_registered (%d)\n", rc); - - debugfs_file = debugfs_create_file("fadump_region", 0444, - powerpc_debugfs_root, NULL, - &fadump_region_fops); - if (!debugfs_file) - printk(KERN_ERR "fadump: unable to create debugfs file" - " fadump_region\n"); - - if (fw_dump.dump_active) { - rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr); - if (rc) - printk(KERN_ERR "fadump: unable to create sysfs file" - " fadump_release_mem (%d)\n", rc); - } - return; -} - -/* - * Prepare for firmware-assisted dump. - */ -int __init setup_fadump(void) -{ - if (!fw_dump.fadump_enabled) - return 0; - - if (!fw_dump.fadump_supported) { - printk(KERN_ERR "Firmware-assisted dump is not supported on" - " this hardware\n"); - return 0; - } - - fadump_show_config(); - /* - * If dump data is available then see if it is valid and prepare for - * saving it to the disk. - */ - if (fw_dump.dump_active) { - /* - * if dump process fails then invalidate the registration - * and release memory before proceeding for re-registration. - */ - if (process_fadump(fdm_active) < 0) - fadump_invalidate_release_mem(); - } - /* Initialize the kernel dump memory structure for FAD registration. */ - else if (fw_dump.reserve_dump_area_size) - init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start); - fadump_init_files(); - - return 1; -} -subsys_initcall(setup_fadump); diff --git a/trunk/arch/powerpc/kernel/head_32.S b/trunk/arch/powerpc/kernel/head_32.S index dc0488b6f6e1..0654dba2c1f1 100644 --- a/trunk/arch/powerpc/kernel/head_32.S +++ b/trunk/arch/powerpc/kernel/head_32.S @@ -395,7 +395,7 @@ DataAccess: bl hash_page 1: lwz r5,_DSISR(r11) /* get DSISR value */ mfspr r4,SPRN_DAR - EXC_XFER_LITE(0x300, handle_page_fault) + EXC_XFER_EE_LITE(0x300, handle_page_fault) /* Instruction access exception. */ @@ -410,7 +410,7 @@ InstructionAccess: bl hash_page 1: mr r4,r12 mr r5,r9 - EXC_XFER_LITE(0x400, handle_page_fault) + EXC_XFER_EE_LITE(0x400, handle_page_fault) /* External interrupt */ EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) diff --git a/trunk/arch/powerpc/kernel/head_40x.S b/trunk/arch/powerpc/kernel/head_40x.S index 4989661b710b..872a6af83bad 100644 --- a/trunk/arch/powerpc/kernel/head_40x.S +++ b/trunk/arch/powerpc/kernel/head_40x.S @@ -394,7 +394,7 @@ label: NORMAL_EXCEPTION_PROLOG mr r4,r12 /* Pass SRR0 as arg2 */ li r5,0 /* Pass zero as arg3 */ - EXC_XFER_LITE(0x400, handle_page_fault) + EXC_XFER_EE_LITE(0x400, handle_page_fault) /* 0x0500 - External Interrupt Exception */ EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) @@ -747,7 +747,7 @@ DataAccess: mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ stw r5,_ESR(r11) mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ - EXC_XFER_LITE(0x300, handle_page_fault) + EXC_XFER_EE_LITE(0x300, handle_page_fault) /* Other PowerPC processors, namely those derived from the 6xx-series * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. diff --git a/trunk/arch/powerpc/kernel/head_64.S b/trunk/arch/powerpc/kernel/head_64.S index 58bddee8e1e8..06c7251c1bf7 100644 --- a/trunk/arch/powerpc/kernel/head_64.S +++ b/trunk/arch/powerpc/kernel/head_64.S @@ -32,13 +32,13 @@ #include #include #include +#include #include #include #include #include #include #include -#include /* The physical memory is laid out such that the secondary processor * spin code sits at 0x0000...0x00ff. On server, the vectors follow @@ -57,6 +57,10 @@ * entry in r9 for debugging purposes * 2. Secondary processors enter at 0x60 with PIR in gpr3 * + * For iSeries: + * 1. The MMU is on (as it always is for iSeries) + * 2. The kernel is entered at system_reset_iSeries + * * For Book3E processors: * 1. The MMU is on running in AS0 in a state defined in ePAPR * 2. The kernel is entered at __start @@ -89,6 +93,15 @@ __secondary_hold_spinloop: __secondary_hold_acknowledge: .llong 0x0 +#ifdef CONFIG_PPC_ISERIES + /* + * At offset 0x20, there is a pointer to iSeries LPAR data. + * This is required by the hypervisor + */ + . = 0x20 + .llong hvReleaseData-KERNELBASE +#endif /* CONFIG_PPC_ISERIES */ + #ifdef CONFIG_RELOCATABLE /* This flag is set to 1 by a loader if the kernel should run * at the loaded address instead of the linked address. This @@ -551,8 +564,7 @@ _GLOBAL(pmac_secondary_start) */ li r0,0 stb r0,PACASOFTIRQEN(r13) - li r0,PACA_IRQ_HARD_DIS - stb r0,PACAIRQHAPPENED(r13) + stb r0,PACAHARDIRQEN(r13) /* Create a temp kernel stack for use before relocation is on. */ ld r1,PACAEMERGSP(r13) @@ -570,7 +582,7 @@ _GLOBAL(pmac_secondary_start) * 1. Processor number * 2. Segment table pointer (virtual address) * On entry the following are set: - * r1 = stack pointer (real addr of temp stack) + * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries * r24 = cpu# (in Linux terms) * r13 = paca virtual address * SPRG_PACA = paca virtual address @@ -583,7 +595,7 @@ __secondary_start: /* Set thread priority to MEDIUM */ HMT_MEDIUM - /* Initialize the kernel stack */ + /* Initialize the kernel stack. Just a repeat for iSeries. */ LOAD_REG_ADDR(r3, current_set) sldi r28,r24,3 /* get current_set[cpu#] */ ldx r14,r3,r28 @@ -603,16 +615,20 @@ __secondary_start: li r7,0 mtlr r7 - /* Mark interrupts soft and hard disabled (they might be enabled - * in the PACA when doing hotplug) - */ - stb r7,PACASOFTIRQEN(r13) - li r0,PACA_IRQ_HARD_DIS - stb r0,PACAIRQHAPPENED(r13) - /* enable MMU and jump to start_secondary */ LOAD_REG_ADDR(r3, .start_secondary_prolog) LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) +#ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION + ori r4,r4,MSR_EE + li r8,1 + stb r8,PACAHARDIRQEN(r13) +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +#endif +BEGIN_FW_FTR_SECTION + stb r7,PACAHARDIRQEN(r13) +END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) + stb r7,PACASOFTIRQEN(r13) mtspr SPRN_SRR0,r3 mtspr SPRN_SRR1,r4 @@ -755,18 +771,22 @@ _INIT_GLOBAL(start_here_common) /* Load the TOC (virtual address) */ ld r2,PACATOC(r13) - /* Do more system initializations in virtual mode */ bl .setup_system - /* Mark interrupts soft and hard disabled (they might be enabled - * in the PACA when doing hotplug) - */ - li r0,0 - stb r0,PACASOFTIRQEN(r13) - li r0,PACA_IRQ_HARD_DIS - stb r0,PACAIRQHAPPENED(r13) + /* Load up the kernel context */ +5: + li r5,0 + stb r5,PACASOFTIRQEN(r13) /* Soft Disabled */ +#ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION + mfmsr r5 + ori r5,r5,MSR_EE /* Hard Enabled on iSeries*/ + mtmsrd r5 + li r5,1 +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +#endif + stb r5,PACAHARDIRQEN(r13) /* Hard Disabled on others */ - /* Generic kernel entry */ bl .start_kernel /* Not reached */ diff --git a/trunk/arch/powerpc/kernel/head_8xx.S b/trunk/arch/powerpc/kernel/head_8xx.S index b2a5860accfb..b68cb173ba2c 100644 --- a/trunk/arch/powerpc/kernel/head_8xx.S +++ b/trunk/arch/powerpc/kernel/head_8xx.S @@ -220,7 +220,7 @@ DataAccess: mfspr r4,SPRN_DAR li r10,0x00f0 mtspr SPRN_DAR,r10 /* Tag DAR, to be used in DTLB Error */ - EXC_XFER_LITE(0x300, handle_page_fault) + EXC_XFER_EE_LITE(0x300, handle_page_fault) /* Instruction access exception. * This is "never generated" by the MPC8xx. We jump to it for other @@ -231,7 +231,7 @@ InstructionAccess: EXCEPTION_PROLOG mr r4,r12 mr r5,r9 - EXC_XFER_LITE(0x400, handle_page_fault) + EXC_XFER_EE_LITE(0x400, handle_page_fault) /* External interrupt */ EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) diff --git a/trunk/arch/powerpc/kernel/head_booke.h b/trunk/arch/powerpc/kernel/head_booke.h index 0e4175388f47..fc921bf62e15 100644 --- a/trunk/arch/powerpc/kernel/head_booke.h +++ b/trunk/arch/powerpc/kernel/head_booke.h @@ -359,7 +359,7 @@ mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \ stw r5,_ESR(r11); \ mfspr r4,SPRN_DEAR; /* Grab the DEAR */ \ - EXC_XFER_LITE(0x0300, handle_page_fault) + EXC_XFER_EE_LITE(0x0300, handle_page_fault) #define INSTRUCTION_STORAGE_EXCEPTION \ START_EXCEPTION(InstructionStorage) \ @@ -368,7 +368,7 @@ stw r5,_ESR(r11); \ mr r4,r12; /* Pass SRR0 as arg2 */ \ li r5,0; /* Pass zero as arg3 */ \ - EXC_XFER_LITE(0x0400, handle_page_fault) + EXC_XFER_EE_LITE(0x0400, handle_page_fault) #define ALIGNMENT_EXCEPTION \ START_EXCEPTION(Alignment) \ diff --git a/trunk/arch/powerpc/kernel/head_fsl_booke.S b/trunk/arch/powerpc/kernel/head_fsl_booke.S index 28e62598d0e8..d5d78c4ceef6 100644 --- a/trunk/arch/powerpc/kernel/head_fsl_booke.S +++ b/trunk/arch/powerpc/kernel/head_fsl_booke.S @@ -319,7 +319,7 @@ interrupt_base: mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ andis. r10,r5,(ESR_ILK|ESR_DLK)@h bne 1f - EXC_XFER_LITE(0x0300, handle_page_fault) + EXC_XFER_EE_LITE(0x0300, handle_page_fault) 1: addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_EE_LITE(0x0300, CacheLockingException) diff --git a/trunk/arch/powerpc/kernel/idle.c b/trunk/arch/powerpc/kernel/idle.c index e8e821146f38..c97fc60c790c 100644 --- a/trunk/arch/powerpc/kernel/idle.c +++ b/trunk/arch/powerpc/kernel/idle.c @@ -84,11 +84,7 @@ void cpu_idle(void) start_critical_timings(); - /* Some power_save functions return with - * interrupts enabled, some don't. - */ - if (irqs_disabled()) - local_irq_enable(); + local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); } else { diff --git a/trunk/arch/powerpc/kernel/idle_book3e.S b/trunk/arch/powerpc/kernel/idle_book3e.S index ff007b59448d..16c002d6bdf1 100644 --- a/trunk/arch/powerpc/kernel/idle_book3e.S +++ b/trunk/arch/powerpc/kernel/idle_book3e.S @@ -29,30 +29,43 @@ _GLOBAL(book3e_idle) wrteei 0 /* Now check if an interrupt came in while we were soft disabled - * since we may otherwise lose it (doorbells etc...). + * since we may otherwise lose it (doorbells etc...). We know + * that since PACAHARDIRQEN will have been cleared in that case. */ - lbz r3,PACAIRQHAPPENED(r13) + lbz r3,PACAHARDIRQEN(r13) cmpwi cr0,r3,0 - bnelr + beqlr - /* Now we are going to mark ourselves as soft and hard enabled in + /* Now we are going to mark ourselves as soft and hard enables in * order to be able to take interrupts while asleep. We inform lockdep * of that. We don't actually turn interrupts on just yet tho. */ #ifdef CONFIG_TRACE_IRQFLAGS stdu r1,-128(r1) bl .trace_hardirqs_on - addi r1,r1,128 #endif li r0,1 stb r0,PACASOFTIRQEN(r13) + stb r0,PACAHARDIRQEN(r13) /* Interrupts will make use return to LR, so get something we want * in there */ bl 1f - /* And return (interrupts are on) */ + /* Hard disable interrupts again */ + wrteei 0 + + /* Mark them off again in the PACA as well */ + li r0,0 + stb r0,PACASOFTIRQEN(r13) + stb r0,PACAHARDIRQEN(r13) + + /* Tell lockdep about it */ +#ifdef CONFIG_TRACE_IRQFLAGS + bl .trace_hardirqs_off + addi r1,r1,128 +#endif ld r0,16(r1) mtlr r0 blr diff --git a/trunk/arch/powerpc/kernel/idle_power4.S b/trunk/arch/powerpc/kernel/idle_power4.S index 2c71b0fc9f91..ba3195478600 100644 --- a/trunk/arch/powerpc/kernel/idle_power4.S +++ b/trunk/arch/powerpc/kernel/idle_power4.S @@ -14,7 +14,6 @@ #include #include #include -#include #undef DEBUG @@ -30,31 +29,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) cmpwi 0,r4,0 beqlr - /* Hard disable interrupts */ + /* Go to NAP now */ mfmsr r7 rldicl r0,r7,48,1 rotldi r0,r0,16 - mtmsrd r0,1 - - /* Check if something happened while soft-disabled */ - lbz r0,PACAIRQHAPPENED(r13) - cmpwi cr0,r0,0 - bnelr - - /* Soft-enable interrupts */ -#ifdef CONFIG_TRACE_IRQFLAGS - mflr r0 - std r0,16(r1) - stdu r1,-128(r1) - bl .trace_hardirqs_on - addi r1,r1,128 - ld r0,16(r1) - mtlr r0 - mfmsr r7 -#endif /* CONFIG_TRACE_IRQFLAGS */ - + mtmsrd r0,1 /* hard-disable interrupts */ li r0,1 stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ + stb r0,PACAHARDIRQEN(r13) BEGIN_FTR_SECTION DSSALL sync diff --git a/trunk/arch/powerpc/kernel/idle_power7.S b/trunk/arch/powerpc/kernel/idle_power7.S index 0cdc9a392839..fcdff198da4b 100644 --- a/trunk/arch/powerpc/kernel/idle_power7.S +++ b/trunk/arch/powerpc/kernel/idle_power7.S @@ -1,5 +1,5 @@ /* - * This file contains the power_save function for Power7 CPUs. + * This file contains the power_save function for 970-family CPUs. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,7 +15,6 @@ #include #include #include -#include #undef DEBUG @@ -52,25 +51,9 @@ _GLOBAL(power7_idle) rldicl r9,r9,48,1 rotldi r9,r9,16 mtmsrd r9,1 /* hard-disable interrupts */ - - /* Check if something happened while soft-disabled */ - lbz r0,PACAIRQHAPPENED(r13) - cmpwi cr0,r0,0 - beq 1f - addi r1,r1,INT_FRAME_SIZE - ld r0,16(r1) - mtlr r0 - blr - -1: /* We mark irqs hard disabled as this is the state we'll - * be in when returning and we need to tell arch_local_irq_restore() - * about it - */ - li r0,PACA_IRQ_HARD_DIS - stb r0,PACAIRQHAPPENED(r13) - - /* We haven't lost state ... yet */ li r0,0 + stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ + stb r0,PACAHARDIRQEN(r13) stb r0,PACA_NAPSTATELOST(r13) /* Continue saving state */ diff --git a/trunk/arch/powerpc/kernel/iommu.c b/trunk/arch/powerpc/kernel/iommu.c index 359f078571c7..0cfcf98aafca 100644 --- a/trunk/arch/powerpc/kernel/iommu.c +++ b/trunk/arch/powerpc/kernel/iommu.c @@ -39,7 +39,6 @@ #include #include #include -#include #define DBG(...) @@ -446,12 +445,7 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, static void iommu_table_clear(struct iommu_table *tbl) { - /* - * In case of firmware assisted dump system goes through clean - * reboot process at the time of system crash. Hence it's safe to - * clear the TCE entries if firmware assisted dump is active. - */ - if (!is_kdump_kernel() || is_fadump_active()) { + if (!is_kdump_kernel()) { /* Clear the table in case firmware left allocations in it */ ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); return; diff --git a/trunk/arch/powerpc/kernel/irq.c b/trunk/arch/powerpc/kernel/irq.c index a3d128e94cff..bdfb3eee3e6f 100644 --- a/trunk/arch/powerpc/kernel/irq.c +++ b/trunk/arch/powerpc/kernel/irq.c @@ -93,16 +93,20 @@ extern int tau_interrupts(int); #ifdef CONFIG_PPC64 +#ifndef CONFIG_SPARSE_IRQ +EXPORT_SYMBOL(irq_desc); +#endif + int distribute_irqs = 1; -static inline notrace unsigned long get_irq_happened(void) +static inline notrace unsigned long get_hard_enabled(void) { - unsigned long happened; + unsigned long enabled; __asm__ __volatile__("lbz %0,%1(13)" - : "=r" (happened) : "i" (offsetof(struct paca_struct, irq_happened))); + : "=r" (enabled) : "i" (offsetof(struct paca_struct, hard_enabled))); - return happened; + return enabled; } static inline notrace void set_soft_enabled(unsigned long enable) @@ -111,162 +115,88 @@ static inline notrace void set_soft_enabled(unsigned long enable) : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); } -static inline notrace int decrementer_check_overflow(void) +static inline notrace void decrementer_check_overflow(void) { - u64 now = get_tb_or_rtc(); - u64 *next_tb = &__get_cpu_var(decrementers_next_tb); - + u64 now = get_tb_or_rtc(); + u64 *next_tb; + + preempt_disable(); + next_tb = &__get_cpu_var(decrementers_next_tb); + if (now >= *next_tb) set_dec(1); - return now >= *next_tb; + preempt_enable(); } -/* This is called whenever we are re-enabling interrupts - * and returns either 0 (nothing to do) or 500/900 if there's - * either an EE or a DEC to generate. - * - * This is called in two contexts: From arch_local_irq_restore() - * before soft-enabling interrupts, and from the exception exit - * path when returning from an interrupt from a soft-disabled to - * a soft enabled context. In both case we have interrupts hard - * disabled. - * - * We take care of only clearing the bits we handled in the - * PACA irq_happened field since we can only re-emit one at a - * time and we don't want to "lose" one. - */ -notrace unsigned int __check_irq_replay(void) +notrace void arch_local_irq_restore(unsigned long en) { /* - * We use local_paca rather than get_paca() to avoid all - * the debug_smp_processor_id() business in this low level - * function - */ - unsigned char happened = local_paca->irq_happened; - - /* Clear bit 0 which we wouldn't clear otherwise */ - local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS; - - /* - * Force the delivery of pending soft-disabled interrupts on PS3. - * Any HV call will have this side effect. + * get_paca()->soft_enabled = en; + * Is it ever valid to use local_irq_restore(0) when soft_enabled is 1? + * That was allowed before, and in such a case we do need to take care + * that gcc will set soft_enabled directly via r13, not choose to use + * an intermediate register, lest we're preempted to a different cpu. */ - if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { - u64 tmp, tmp2; - lv1_get_version_info(&tmp, &tmp2); - } - - /* - * We may have missed a decrementer interrupt. We check the - * decrementer itself rather than the paca irq_happened field - * in case we also had a rollover while hard disabled - */ - local_paca->irq_happened &= ~PACA_IRQ_DEC; - if (decrementer_check_overflow()) - return 0x900; - - /* Finally check if an external interrupt happened */ - local_paca->irq_happened &= ~PACA_IRQ_EE; - if (happened & PACA_IRQ_EE) - return 0x500; - -#ifdef CONFIG_PPC_BOOK3E - /* Finally check if an EPR external interrupt happened - * this bit is typically set if we need to handle another - * "edge" interrupt from within the MPIC "EPR" handler - */ - local_paca->irq_happened &= ~PACA_IRQ_EE_EDGE; - if (happened & PACA_IRQ_EE_EDGE) - return 0x500; - - local_paca->irq_happened &= ~PACA_IRQ_DBELL; - if (happened & PACA_IRQ_DBELL) - return 0x280; -#endif /* CONFIG_PPC_BOOK3E */ - - /* There should be nothing left ! */ - BUG_ON(local_paca->irq_happened != 0); - - return 0; -} - -notrace void arch_local_irq_restore(unsigned long en) -{ - unsigned char irq_happened; - unsigned int replay; - - /* Write the new soft-enabled value */ set_soft_enabled(en); if (!en) return; + +#ifdef CONFIG_PPC_STD_MMU_64 + if (firmware_has_feature(FW_FEATURE_ISERIES)) { + /* + * Do we need to disable preemption here? Not really: in the + * unlikely event that we're preempted to a different cpu in + * between getting r13, loading its lppaca_ptr, and loading + * its any_int, we might call iseries_handle_interrupts without + * an interrupt pending on the new cpu, but that's no disaster, + * is it? And the business of preempting us off the old cpu + * would itself involve a local_irq_restore which handles the + * interrupt to that cpu. + * + * But use "local_paca->lppaca_ptr" instead of "get_lppaca()" + * to avoid any preemption checking added into get_paca(). + */ + if (local_paca->lppaca_ptr->int_dword.any_int) + iseries_handle_interrupts(); + } +#endif /* CONFIG_PPC_STD_MMU_64 */ + /* - * From this point onward, we can take interrupts, preempt, - * etc... unless we got hard-disabled. We check if an event - * happened. If none happened, we know we can just return. - * - * We may have preempted before the check below, in which case - * we are checking the "new" CPU instead of the old one. This - * is only a problem if an event happened on the "old" CPU. - * - * External interrupt events on non-iseries will have caused - * interrupts to be hard-disabled, so there is no problem, we - * cannot have preempted. + * if (get_paca()->hard_enabled) return; + * But again we need to take care that gcc gets hard_enabled directly + * via r13, not choose to use an intermediate register, lest we're + * preempted to a different cpu in between the two instructions. */ - irq_happened = get_irq_happened(); - if (!irq_happened) + if (get_hard_enabled()) return; /* - * We need to hard disable to get a trusted value from - * __check_irq_replay(). We also need to soft-disable - * again to avoid warnings in there due to the use of - * per-cpu variables. - * - * We know that if the value in irq_happened is exactly 0x01 - * then we are already hard disabled (there are other less - * common cases that we'll ignore for now), so we skip the - * (expensive) mtmsrd. + * Need to hard-enable interrupts here. Since currently disabled, + * no need to take further asm precautions against preemption; but + * use local_paca instead of get_paca() to avoid preemption checking. */ - if (unlikely(irq_happened != PACA_IRQ_HARD_DIS)) - __hard_irq_disable(); - set_soft_enabled(0); + local_paca->hard_enabled = en; /* - * Check if anything needs to be re-emitted. We haven't - * soft-enabled yet to avoid warnings in decrementer_check_overflow - * accessing per-cpu variables + * Trigger the decrementer if we have a pending event. Some processors + * only trigger on edge transitions of the sign bit. We might also + * have disabled interrupts long enough that the decrementer wrapped + * to positive. */ - replay = __check_irq_replay(); - - /* We can soft-enable now */ - set_soft_enabled(1); + decrementer_check_overflow(); /* - * And replay if we have to. This will return with interrupts - * hard-enabled. + * Force the delivery of pending soft-disabled interrupts on PS3. + * Any HV call will have this side effect. */ - if (replay) { - __replay_interrupt(replay); - return; + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { + u64 tmp, tmp2; + lv1_get_version_info(&tmp, &tmp2); } - /* Finally, let's ensure we are hard enabled */ __hard_irq_enable(); } EXPORT_SYMBOL(arch_local_irq_restore); - -/* - * This is specifically called by assembly code to re-enable interrupts - * if they are currently disabled. This is typically called before - * schedule() or do_signal() when returning to userspace. We do it - * in C to avoid the burden of dealing with lockdep etc... - */ -void restore_interrupts(void) -{ - if (irqs_disabled()) - local_irq_enable(); -} - #endif /* CONFIG_PPC64 */ int arch_show_interrupts(struct seq_file *p, int prec) @@ -434,17 +364,8 @@ void do_IRQ(struct pt_regs *regs) check_stack_overflow(); - /* - * Query the platform PIC for the interrupt & ack it. - * - * This will typically lower the interrupt line to the CPU - */ irq = ppc_md.get_irq(); - /* We can hard enable interrupts now */ - may_hard_irq_enable(); - - /* And finally process it */ if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) handle_one_irq(irq); else if (irq != NO_IRQ_IGNORE) @@ -453,6 +374,15 @@ void do_IRQ(struct pt_regs *regs) irq_exit(); set_irq_regs(old_regs); +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES) && + get_lppaca()->int_dword.fields.decr_int) { + get_lppaca()->int_dword.fields.decr_int = 0; + /* Signal a fake decrementer interrupt */ + timer_interrupt(regs); + } +#endif + trace_irq_exit(regs); } diff --git a/trunk/arch/powerpc/kernel/isa-bridge.c b/trunk/arch/powerpc/kernel/isa-bridge.c index d45ec58703ce..479752901ec6 100644 --- a/trunk/arch/powerpc/kernel/isa-bridge.c +++ b/trunk/arch/powerpc/kernel/isa-bridge.c @@ -29,6 +29,7 @@ #include #include #include +#include unsigned long isa_io_base; /* NULL if no ISA bus */ EXPORT_SYMBOL(isa_io_base); @@ -260,6 +261,8 @@ static struct notifier_block isa_bridge_notifier = { */ static int __init isa_bridge_init(void) { + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return 0; bus_register_notifier(&pci_bus_type, &isa_bridge_notifier); return 0; } diff --git a/trunk/arch/powerpc/kernel/lparcfg.c b/trunk/arch/powerpc/kernel/lparcfg.c index ac12bd80ad95..578f35f18723 100644 --- a/trunk/arch/powerpc/kernel/lparcfg.c +++ b/trunk/arch/powerpc/kernel/lparcfg.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -54,14 +55,80 @@ static unsigned long get_purr(void) int cpu; for_each_possible_cpu(cpu) { - struct cpu_usage *cu; + if (firmware_has_feature(FW_FEATURE_ISERIES)) + sum_purr += lppaca_of(cpu).emulated_time_base; + else { + struct cpu_usage *cu; - cu = &per_cpu(cpu_usage_array, cpu); - sum_purr += cu->current_tb; + cu = &per_cpu(cpu_usage_array, cpu); + sum_purr += cu->current_tb; + } } return sum_purr; } +#ifdef CONFIG_PPC_ISERIES + +/* + * Methods used to fetch LPAR data when running on an iSeries platform. + */ +static int iseries_lparcfg_data(struct seq_file *m, void *v) +{ + unsigned long pool_id; + int shared, entitled_capacity, max_entitled_capacity; + int processors, max_processors; + unsigned long purr = get_purr(); + + shared = (int)(local_paca->lppaca_ptr->shared_proc); + + seq_printf(m, "system_active_processors=%d\n", + (int)HvLpConfig_getSystemPhysicalProcessors()); + + seq_printf(m, "system_potential_processors=%d\n", + (int)HvLpConfig_getSystemPhysicalProcessors()); + + processors = (int)HvLpConfig_getPhysicalProcessors(); + seq_printf(m, "partition_active_processors=%d\n", processors); + + max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); + seq_printf(m, "partition_potential_processors=%d\n", max_processors); + + if (shared) { + entitled_capacity = HvLpConfig_getSharedProcUnits(); + max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits(); + } else { + entitled_capacity = processors * 100; + max_entitled_capacity = max_processors * 100; + } + seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity); + + seq_printf(m, "partition_max_entitled_capacity=%d\n", + max_entitled_capacity); + + if (shared) { + pool_id = HvLpConfig_getSharedPoolIndex(); + seq_printf(m, "pool=%d\n", (int)pool_id); + seq_printf(m, "pool_capacity=%d\n", + (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) * + 100)); + seq_printf(m, "purr=%ld\n", purr); + } + + seq_printf(m, "shared_processor_mode=%d\n", shared); + + return 0; +} + +#else /* CONFIG_PPC_ISERIES */ + +static int iseries_lparcfg_data(struct seq_file *m, void *v) +{ + return 0; +} + +#endif /* CONFIG_PPC_ISERIES */ + +#ifdef CONFIG_PPC_PSERIES /* * Methods used to fetch LPAR data when running on a pSeries platform. */ @@ -581,7 +648,8 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, u8 new_weight, *new_weight_ptr = &new_weight; ssize_t retval; - if (!firmware_has_feature(FW_FEATURE_SPLPAR)) + if (!firmware_has_feature(FW_FEATURE_SPLPAR) || + firmware_has_feature(FW_FEATURE_ISERIES)) return -EINVAL; if (count > kbuf_sz) @@ -641,6 +709,21 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, return retval; } +#else /* CONFIG_PPC_PSERIES */ + +static int pseries_lparcfg_data(struct seq_file *m, void *v) +{ + return 0; +} + +static ssize_t lparcfg_write(struct file *file, const char __user * buf, + size_t count, loff_t * off) +{ + return -EINVAL; +} + +#endif /* CONFIG_PPC_PSERIES */ + static int lparcfg_data(struct seq_file *m, void *v) { struct device_node *rootdn; @@ -655,11 +738,19 @@ static int lparcfg_data(struct seq_file *m, void *v) rootdn = of_find_node_by_path("/"); if (rootdn) { tmp = of_get_property(rootdn, "model", NULL); - if (tmp) + if (tmp) { model = tmp; + /* Skip "IBM," - see platforms/iseries/dt.c */ + if (firmware_has_feature(FW_FEATURE_ISERIES)) + model += 4; + } tmp = of_get_property(rootdn, "system-id", NULL); - if (tmp) + if (tmp) { system_id = tmp; + /* Skip "IBM," - see platforms/iseries/dt.c */ + if (firmware_has_feature(FW_FEATURE_ISERIES)) + system_id += 4; + } lp_index_ptr = of_get_property(rootdn, "ibm,partition-no", NULL); if (lp_index_ptr) @@ -670,6 +761,8 @@ static int lparcfg_data(struct seq_file *m, void *v) seq_printf(m, "system_type=%s\n", model); seq_printf(m, "partition_id=%d\n", (int)lp_index); + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return iseries_lparcfg_data(m, v); return pseries_lparcfg_data(m, v); } @@ -693,7 +786,8 @@ static int __init lparcfg_init(void) umode_t mode = S_IRUSR | S_IRGRP | S_IROTH; /* Allow writing if we have FW_FEATURE_SPLPAR */ - if (firmware_has_feature(FW_FEATURE_SPLPAR)) + if (firmware_has_feature(FW_FEATURE_SPLPAR) && + !firmware_has_feature(FW_FEATURE_ISERIES)) mode |= S_IWUSR; ent = proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops); diff --git a/trunk/arch/powerpc/kernel/misc.S b/trunk/arch/powerpc/kernel/misc.S index ba16874fe294..b69463ec2010 100644 --- a/trunk/arch/powerpc/kernel/misc.S +++ b/trunk/arch/powerpc/kernel/misc.S @@ -5,6 +5,7 @@ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) * and Paul Mackerras. * + * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) * * setjmp/longjmp code by Paul Mackerras. diff --git a/trunk/arch/powerpc/perf/mpc7450-pmu.c b/trunk/arch/powerpc/kernel/mpc7450-pmu.c similarity index 100% rename from trunk/arch/powerpc/perf/mpc7450-pmu.c rename to trunk/arch/powerpc/kernel/mpc7450-pmu.c diff --git a/trunk/arch/powerpc/kernel/of_platform.c b/trunk/arch/powerpc/kernel/of_platform.c index 2049f2d00ffe..e1612dfb4a93 100644 --- a/trunk/arch/powerpc/kernel/of_platform.c +++ b/trunk/arch/powerpc/kernel/of_platform.c @@ -21,13 +21,12 @@ #include #include #include -#include #include #include #include #include -#include +#include #ifdef CONFIG_PPC_OF_PLATFORM_PCI @@ -67,9 +66,6 @@ static int __devinit of_pci_phb_probe(struct platform_device *dev) /* Init pci_dn data structures */ pci_devs_phb_init_dynamic(phb); - /* Create EEH devices for the PHB */ - eeh_dev_phb_init_dynamic(phb); - /* Register devices with EEH */ #ifdef CONFIG_EEH if (dev->dev.of_node->child) diff --git a/trunk/arch/powerpc/kernel/paca.c b/trunk/arch/powerpc/kernel/paca.c index 0bb1f98613ba..41456ff55e14 100644 --- a/trunk/arch/powerpc/kernel/paca.c +++ b/trunk/arch/powerpc/kernel/paca.c @@ -11,10 +11,13 @@ #include #include +#include #include #include #include #include +#include +#include #include /* This symbol is provided by the linker - let it fill in the paca @@ -27,8 +30,8 @@ extern unsigned long __toc_start; * The structure which the hypervisor knows about - this structure * should not cross a page boundary. The vpa_init/register_vpa call * is now known to fail if the lppaca structure crosses a page - * boundary. The lppaca is also used on POWER5 pSeries boxes. - * The lppaca is 640 bytes long, and cannot readily + * boundary. The lppaca is also used on legacy iSeries and POWER5 + * pSeries boxes. The lppaca is 640 bytes long, and cannot readily * change since the hypervisor knows its layout, so a 1kB alignment * will suffice to ensure that it doesn't cross a page boundary. */ @@ -180,9 +183,12 @@ void __init allocate_pacas(void) /* * We can't take SLB misses on the paca, and we want to access them * in real mode, so allocate them within the RMA and also within - * the first segment. + * the first segment. On iSeries they must be within the area mapped + * by the HV, which is HvPagesToMap * HVPAGESIZE bytes. */ limit = min(0x10000000ULL, ppc64_rma_size); + if (firmware_has_feature(FW_FEATURE_ISERIES)) + limit = min(limit, HvPagesToMap * HVPAGESIZE); paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids); diff --git a/trunk/arch/powerpc/kernel/pci-common.c b/trunk/arch/powerpc/kernel/pci-common.c index d0373bcb7c9d..cce98d76e905 100644 --- a/trunk/arch/powerpc/kernel/pci-common.c +++ b/trunk/arch/powerpc/kernel/pci-common.c @@ -38,6 +38,7 @@ #include #include #include +#include #include static DEFINE_SPINLOCK(hose_spinlock); @@ -218,6 +219,20 @@ static int pci_read_irq_line(struct pci_dev *pci_dev) struct of_irq oirq; unsigned int virq; + /* The current device-tree that iSeries generates from the HV + * PCI informations doesn't contain proper interrupt routing, + * and all the fallback would do is print out crap, so we + * don't attempt to resolve the interrupts here at all, some + * iSeries specific fixup does it. + * + * In the long run, we will hopefully fix the generated device-tree + * instead. + */ +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return -1; +#endif + pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev)); #ifdef DEBUG diff --git a/trunk/arch/powerpc/perf/callchain.c b/trunk/arch/powerpc/kernel/perf_callchain.c similarity index 99% rename from trunk/arch/powerpc/perf/callchain.c rename to trunk/arch/powerpc/kernel/perf_callchain.c index e8a18d1cc7c9..564c1d8bdb5c 100644 --- a/trunk/arch/powerpc/perf/callchain.c +++ b/trunk/arch/powerpc/kernel/perf_callchain.c @@ -20,7 +20,7 @@ #include #include #ifdef CONFIG_PPC64 -#include "../kernel/ppc32.h" +#include "ppc32.h" #endif diff --git a/trunk/arch/powerpc/perf/core-book3s.c b/trunk/arch/powerpc/kernel/perf_event.c similarity index 100% rename from trunk/arch/powerpc/perf/core-book3s.c rename to trunk/arch/powerpc/kernel/perf_event.c diff --git a/trunk/arch/powerpc/perf/core-fsl-emb.c b/trunk/arch/powerpc/kernel/perf_event_fsl_emb.c similarity index 100% rename from trunk/arch/powerpc/perf/core-fsl-emb.c rename to trunk/arch/powerpc/kernel/perf_event_fsl_emb.c diff --git a/trunk/arch/powerpc/perf/power4-pmu.c b/trunk/arch/powerpc/kernel/power4-pmu.c similarity index 100% rename from trunk/arch/powerpc/perf/power4-pmu.c rename to trunk/arch/powerpc/kernel/power4-pmu.c diff --git a/trunk/arch/powerpc/perf/power5+-pmu.c b/trunk/arch/powerpc/kernel/power5+-pmu.c similarity index 100% rename from trunk/arch/powerpc/perf/power5+-pmu.c rename to trunk/arch/powerpc/kernel/power5+-pmu.c diff --git a/trunk/arch/powerpc/perf/power5-pmu.c b/trunk/arch/powerpc/kernel/power5-pmu.c similarity index 100% rename from trunk/arch/powerpc/perf/power5-pmu.c rename to trunk/arch/powerpc/kernel/power5-pmu.c diff --git a/trunk/arch/powerpc/perf/power6-pmu.c b/trunk/arch/powerpc/kernel/power6-pmu.c similarity index 99% rename from trunk/arch/powerpc/perf/power6-pmu.c rename to trunk/arch/powerpc/kernel/power6-pmu.c index 31128e086fed..0bbc901e7efc 100644 --- a/trunk/arch/powerpc/perf/power6-pmu.c +++ b/trunk/arch/powerpc/kernel/power6-pmu.c @@ -131,7 +131,7 @@ static u32 marked_bus_events[16] = { 0x00000022, /* BFP set 2: byte 0 bits 1, 5 */ 0, 0 }; - + /* * Returns 1 if event counts things relating to marked instructions * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not. diff --git a/trunk/arch/powerpc/perf/power7-pmu.c b/trunk/arch/powerpc/kernel/power7-pmu.c similarity index 100% rename from trunk/arch/powerpc/perf/power7-pmu.c rename to trunk/arch/powerpc/kernel/power7-pmu.c diff --git a/trunk/arch/powerpc/perf/ppc970-pmu.c b/trunk/arch/powerpc/kernel/ppc970-pmu.c similarity index 99% rename from trunk/arch/powerpc/perf/ppc970-pmu.c rename to trunk/arch/powerpc/kernel/ppc970-pmu.c index 111eb25bb0b6..8c2190206964 100644 --- a/trunk/arch/powerpc/perf/ppc970-pmu.c +++ b/trunk/arch/powerpc/kernel/ppc970-pmu.c @@ -252,7 +252,7 @@ static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[]) alt[1] = event ^ 0x1000; return 2; } - + return 1; } diff --git a/trunk/arch/powerpc/kernel/process.c b/trunk/arch/powerpc/kernel/process.c index e40707032ac3..d817ab018486 100644 --- a/trunk/arch/powerpc/kernel/process.c +++ b/trunk/arch/powerpc/kernel/process.c @@ -647,9 +647,6 @@ void show_regs(struct pt_regs * regs) printk("MSR: "REG" ", regs->msr); printbits(regs->msr, msr_bits); printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer); -#ifdef CONFIG_PPC64 - printk("SOFTE: %ld\n", regs->softe); -#endif trap = TRAP(regs); if ((regs->trap != 0xc00) && cpu_has_feature(CPU_FTR_CFAR)) printk("CFAR: "REG"\n", regs->orig_gpr3); @@ -1223,32 +1220,34 @@ void dump_stack(void) EXPORT_SYMBOL(dump_stack); #ifdef CONFIG_PPC64 -/* Called with hard IRQs off */ -void __ppc64_runlatch_on(void) +void ppc64_runlatch_on(void) { - struct thread_info *ti = current_thread_info(); unsigned long ctrl; - ctrl = mfspr(SPRN_CTRLF); - ctrl |= CTRL_RUNLATCH; - mtspr(SPRN_CTRLT, ctrl); + if (cpu_has_feature(CPU_FTR_CTRL) && !test_thread_flag(TIF_RUNLATCH)) { + HMT_medium(); + + ctrl = mfspr(SPRN_CTRLF); + ctrl |= CTRL_RUNLATCH; + mtspr(SPRN_CTRLT, ctrl); - ti->local_flags |= TLF_RUNLATCH; + set_thread_flag(TIF_RUNLATCH); + } } -/* Called with hard IRQs off */ void __ppc64_runlatch_off(void) { - struct thread_info *ti = current_thread_info(); unsigned long ctrl; - ti->local_flags &= ~TLF_RUNLATCH; + HMT_medium(); + + clear_thread_flag(TIF_RUNLATCH); ctrl = mfspr(SPRN_CTRLF); ctrl &= ~CTRL_RUNLATCH; mtspr(SPRN_CTRLT, ctrl); } -#endif /* CONFIG_PPC64 */ +#endif #if THREAD_SHIFT < PAGE_SHIFT diff --git a/trunk/arch/powerpc/kernel/prom.c b/trunk/arch/powerpc/kernel/prom.c index 89e850af3dd6..abe405dab34d 100644 --- a/trunk/arch/powerpc/kernel/prom.c +++ b/trunk/arch/powerpc/kernel/prom.c @@ -52,9 +52,9 @@ #include #include #include +#include #include #include -#include #include @@ -615,6 +615,86 @@ static void __init early_reserve_mem(void) } } +#ifdef CONFIG_PHYP_DUMP +/** + * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg + * + * Function to find the largest size we need to reserve + * during early boot process. + * + * It either looks for boot param and returns that OR + * returns larger of 256 or 5% rounded down to multiples of 256MB. + * + */ +static inline unsigned long phyp_dump_calculate_reserve_size(void) +{ + unsigned long tmp; + + if (phyp_dump_info->reserve_bootvar) + return phyp_dump_info->reserve_bootvar; + + /* divide by 20 to get 5% of value */ + tmp = memblock_end_of_DRAM(); + do_div(tmp, 20); + + /* round it down in multiples of 256 */ + tmp = tmp & ~0x0FFFFFFFUL; + + return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END); +} + +/** + * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory + * + * This routine may reserve memory regions in the kernel only + * if the system is supported and a dump was taken in last + * boot instance or if the hardware is supported and the + * scratch area needs to be setup. In other instances it returns + * without reserving anything. The memory in case of dump being + * active is freed when the dump is collected (by userland tools). + */ +static void __init phyp_dump_reserve_mem(void) +{ + unsigned long base, size; + unsigned long variable_reserve_size; + + if (!phyp_dump_info->phyp_dump_configured) { + printk(KERN_ERR "Phyp-dump not supported on this hardware\n"); + return; + } + + if (!phyp_dump_info->phyp_dump_at_boot) { + printk(KERN_INFO "Phyp-dump disabled at boot time\n"); + return; + } + + variable_reserve_size = phyp_dump_calculate_reserve_size(); + + if (phyp_dump_info->phyp_dump_is_active) { + /* Reserve *everything* above RMR.Area freed by userland tools*/ + base = variable_reserve_size; + size = memblock_end_of_DRAM() - base; + + /* XXX crashed_ram_end is wrong, since it may be beyond + * the memory_limit, it will need to be adjusted. */ + memblock_reserve(base, size); + + phyp_dump_info->init_reserve_start = base; + phyp_dump_info->init_reserve_size = size; + } else { + size = phyp_dump_info->cpu_state_size + + phyp_dump_info->hpte_region_size + + variable_reserve_size; + base = memblock_end_of_DRAM() - size; + memblock_reserve(base, size); + phyp_dump_info->init_reserve_start = base; + phyp_dump_info->init_reserve_size = size; + } +} +#else +static inline void __init phyp_dump_reserve_mem(void) {} +#endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */ + void __init early_init_devtree(void *params) { phys_addr_t limit; @@ -634,9 +714,9 @@ void __init early_init_devtree(void *params) of_scan_flat_dt(early_init_dt_scan_opal, NULL); #endif -#ifdef CONFIG_FA_DUMP - /* scan tree to see if dump is active during last boot */ - of_scan_flat_dt(early_init_dt_scan_fw_dump, NULL); +#ifdef CONFIG_PHYP_DUMP + /* scan tree to see if dump occurred during last boot */ + of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); #endif /* Pre-initialize the cmd_line with the content of boot_commmand_line, @@ -670,15 +750,9 @@ void __init early_init_devtree(void *params) if (PHYSICAL_START > MEMORY_START) memblock_reserve(MEMORY_START, 0x8000); reserve_kdump_trampoline(); -#ifdef CONFIG_FA_DUMP - /* - * If we fail to reserve memory for firmware-assisted dump then - * fallback to kexec based kdump. - */ - if (fadump_reserve_mem() == 0) -#endif - reserve_crashkernel(); + reserve_crashkernel(); early_reserve_mem(); + phyp_dump_reserve_mem(); /* * Ensure that total memory size is page-aligned, because otherwise diff --git a/trunk/arch/powerpc/kernel/prom_init.c b/trunk/arch/powerpc/kernel/prom_init.c index e2d599048142..eca626ea3f23 100644 --- a/trunk/arch/powerpc/kernel/prom_init.c +++ b/trunk/arch/powerpc/kernel/prom_init.c @@ -47,6 +47,14 @@ #include +/* + * Properties whose value is longer than this get excluded from our + * copy of the device tree. This value does need to be big enough to + * ensure that we don't lose things like the interrupt-map property + * on a PCI-PCI bridge. + */ +#define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) + /* * Eventually bump that one up */ @@ -2265,6 +2273,13 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, /* sanity checks */ if (l == PROM_ERROR) continue; + if (l > MAX_PROPERTY_LENGTH) { + prom_printf("WARNING: ignoring large property "); + /* It seems OF doesn't null-terminate the path :-( */ + prom_printf("[%s] ", path); + prom_printf("%s length 0x%x\n", RELOC(pname), l); + continue; + } /* push property head */ dt_push_token(OF_DT_PROP, mem_start, mem_end); diff --git a/trunk/arch/powerpc/kernel/rtas_pci.c b/trunk/arch/powerpc/kernel/rtas_pci.c index 517bd86bc3f0..6cd8f0196b6d 100644 --- a/trunk/arch/powerpc/kernel/rtas_pci.c +++ b/trunk/arch/powerpc/kernel/rtas_pci.c @@ -275,9 +275,6 @@ void __init find_and_init_phbs(void) of_node_put(root); pci_devs_phb_init(); - /* Create EEH devices for all PHBs */ - eeh_dev_phb_init(); - /* * pci_probe_only and pci_assign_all_buses can be set via properties * in chosen. diff --git a/trunk/arch/powerpc/kernel/setup-common.c b/trunk/arch/powerpc/kernel/setup-common.c index b0ebdeab9494..77bb77da05c1 100644 --- a/trunk/arch/powerpc/kernel/setup-common.c +++ b/trunk/arch/powerpc/kernel/setup-common.c @@ -61,7 +61,6 @@ #include #include #include -#include #include "setup.h" @@ -110,14 +109,6 @@ EXPORT_SYMBOL(ppc_do_canonicalize_irqs); /* also used by kexec */ void machine_shutdown(void) { -#ifdef CONFIG_FA_DUMP - /* - * if fadump is active, cleanup the fadump registration before we - * shutdown. - */ - fadump_cleanup(); -#endif - if (ppc_md.machine_shutdown) ppc_md.machine_shutdown(); } @@ -648,11 +639,6 @@ EXPORT_SYMBOL(check_legacy_ioport); static int ppc_panic_event(struct notifier_block *this, unsigned long event, void *ptr) { - /* - * If firmware-assisted dump has been registered then trigger - * firmware-assisted dump and let firmware handle everything else. - */ - crash_fadump(NULL, ptr); ppc_md.panic(ptr); /* May not return */ return NOTIFY_DONE; } diff --git a/trunk/arch/powerpc/kernel/signal.c b/trunk/arch/powerpc/kernel/signal.c index 7006b7f4267a..ac6e437b1021 100644 --- a/trunk/arch/powerpc/kernel/signal.c +++ b/trunk/arch/powerpc/kernel/signal.c @@ -57,7 +57,10 @@ void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, void restore_sigmask(sigset_t *set) { sigdelsetmask(set, ~_BLOCKABLE); - set_current_blocked(set); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = *set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); } static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, @@ -166,7 +169,13 @@ static int do_signal(struct pt_regs *regs) regs->trap = 0; if (ret) { - block_sigmask(&ka, signr); + spin_lock_irq(¤t->sighand->siglock); + sigorsets(¤t->blocked, ¤t->blocked, + &ka.sa.sa_mask); + if (!(ka.sa.sa_flags & SA_NODEFER)) + sigaddset(¤t->blocked, signr); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); /* * A signal was successfully delivered; the saved sigmask is in diff --git a/trunk/arch/powerpc/kernel/signal_32.c b/trunk/arch/powerpc/kernel/signal_32.c index e061ef5dd449..836a5a19eb2c 100644 --- a/trunk/arch/powerpc/kernel/signal_32.c +++ b/trunk/arch/powerpc/kernel/signal_32.c @@ -242,13 +242,12 @@ static inline int restore_general_regs(struct pt_regs *regs, */ long sys_sigsuspend(old_sigset_t mask) { - sigset_t blocked; - - current->saved_sigmask = current->blocked; - mask &= _BLOCKABLE; - siginitset(&blocked, mask); - set_current_blocked(&blocked); + spin_lock_irq(¤t->sighand->siglock); + current->saved_sigmask = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; schedule(); diff --git a/trunk/arch/powerpc/kernel/sysfs.c b/trunk/arch/powerpc/kernel/sysfs.c index 0c683d376b1c..883e74c0d1b3 100644 --- a/trunk/arch/powerpc/kernel/sysfs.c +++ b/trunk/arch/powerpc/kernel/sysfs.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -340,7 +341,8 @@ static void __cpuinit register_cpu_online(unsigned int cpu) int i, nattrs; #ifdef CONFIG_PPC64 - if (cpu_has_feature(CPU_FTR_SMT)) + if (!firmware_has_feature(FW_FEATURE_ISERIES) && + cpu_has_feature(CPU_FTR_SMT)) device_create_file(s, &dev_attr_smt_snooze_delay); #endif @@ -412,7 +414,8 @@ static void unregister_cpu_online(unsigned int cpu) BUG_ON(!c->hotpluggable); #ifdef CONFIG_PPC64 - if (cpu_has_feature(CPU_FTR_SMT)) + if (!firmware_has_feature(FW_FEATURE_ISERIES) && + cpu_has_feature(CPU_FTR_SMT)) device_remove_file(s, &dev_attr_smt_snooze_delay); #endif diff --git a/trunk/arch/powerpc/kernel/time.c b/trunk/arch/powerpc/kernel/time.c index 2c42cd72d0f5..567dd7c3ac2a 100644 --- a/trunk/arch/powerpc/kernel/time.c +++ b/trunk/arch/powerpc/kernel/time.c @@ -17,7 +17,8 @@ * * TODO (not necessarily in this file): * - improve precision and reproducibility of timebase frequency - * measurement at boot time. + * measurement at boot time. (for iSeries, we calibrate the timebase + * against the Titan chip's clock.) * - for astronomical applications: add a new function to get * non ambiguous timestamps even around leap seconds. This needs * a new timestamp format and a good name. @@ -69,6 +70,10 @@ #include #include #include +#ifdef CONFIG_PPC_ISERIES +#include +#include +#endif /* powerpc clocksource/clockevent code */ @@ -112,6 +117,14 @@ static struct clock_event_device decrementer_clockevent = { DEFINE_PER_CPU(u64, decrementers_next_tb); static DEFINE_PER_CPU(struct clock_event_device, decrementers); +#ifdef CONFIG_PPC_ISERIES +static unsigned long __initdata iSeries_recal_titan; +static signed long __initdata iSeries_recal_tb; + +/* Forward declaration is only needed for iSereis compiles */ +static void __init clocksource_init(void); +#endif + #define XSEC_PER_SEC (1024*1024) #ifdef CONFIG_PPC64 @@ -246,6 +259,7 @@ void accumulate_stolen_time(void) u64 sst, ust; u8 save_soft_enabled = local_paca->soft_enabled; + u8 save_hard_enabled = local_paca->hard_enabled; /* We are called early in the exception entry, before * soft/hard_enabled are sync'ed to the expected state @@ -254,6 +268,7 @@ void accumulate_stolen_time(void) * complain */ local_paca->soft_enabled = 0; + local_paca->hard_enabled = 0; sst = scan_dispatch_log(local_paca->starttime_user); ust = scan_dispatch_log(local_paca->starttime); @@ -262,6 +277,7 @@ void accumulate_stolen_time(void) local_paca->stolen_time += ust + sst; local_paca->soft_enabled = save_soft_enabled; + local_paca->hard_enabled = save_hard_enabled; } static inline u64 calculate_stolen_time(u64 stop_tb) @@ -410,6 +426,74 @@ unsigned long profile_pc(struct pt_regs *regs) EXPORT_SYMBOL(profile_pc); #endif +#ifdef CONFIG_PPC_ISERIES + +/* + * This function recalibrates the timebase based on the 49-bit time-of-day + * value in the Titan chip. The Titan is much more accurate than the value + * returned by the service processor for the timebase frequency. + */ + +static int __init iSeries_tb_recal(void) +{ + unsigned long titan, tb; + + /* Make sure we only run on iSeries */ + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + + tb = get_tb(); + titan = HvCallXm_loadTod(); + if ( iSeries_recal_titan ) { + unsigned long tb_ticks = tb - iSeries_recal_tb; + unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12; + unsigned long new_tb_ticks_per_sec = (tb_ticks * USEC_PER_SEC)/titan_usec; + unsigned long new_tb_ticks_per_jiffy = + DIV_ROUND_CLOSEST(new_tb_ticks_per_sec, HZ); + long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy; + char sign = '+'; + /* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */ + new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ; + + if ( tick_diff < 0 ) { + tick_diff = -tick_diff; + sign = '-'; + } + if ( tick_diff ) { + if ( tick_diff < tb_ticks_per_jiffy/25 ) { + printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n", + new_tb_ticks_per_jiffy, sign, tick_diff ); + tb_ticks_per_jiffy = new_tb_ticks_per_jiffy; + tb_ticks_per_sec = new_tb_ticks_per_sec; + calc_cputime_factors(); + vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; + setup_cputime_one_jiffy(); + } + else { + printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" + " new tb_ticks_per_jiffy = %lu\n" + " old tb_ticks_per_jiffy = %lu\n", + new_tb_ticks_per_jiffy, tb_ticks_per_jiffy ); + } + } + } + iSeries_recal_titan = titan; + iSeries_recal_tb = tb; + + /* Called here as now we know accurate values for the timebase */ + clocksource_init(); + return 0; +} +late_initcall(iSeries_tb_recal); + +/* Called from platform early init */ +void __init iSeries_time_init_early(void) +{ + iSeries_recal_tb = get_tb(); + iSeries_recal_titan = HvCallXm_loadTod(); +} +#endif /* CONFIG_PPC_ISERIES */ + #ifdef CONFIG_IRQ_WORK /* @@ -465,6 +549,16 @@ void arch_irq_work_raise(void) #endif /* CONFIG_IRQ_WORK */ +/* + * For iSeries shared processors, we have to let the hypervisor + * set the hardware decrementer. We set a virtual decrementer + * in the lppaca and call the hypervisor if the virtual + * decrementer is less than the current value in the hardware + * decrementer. (almost always the new decrementer value will + * be greater than the current hardware decementer so the hypervisor + * call will not be needed) + */ + /* * timer_interrupt - gets called when the decrementer overflows, * with interrupts disabled. @@ -486,11 +580,6 @@ void timer_interrupt(struct pt_regs * regs) if (!cpu_online(smp_processor_id())) return; - /* Conditionally hard-enable interrupts now that the DEC has been - * bumped to its maximum value - */ - may_hard_irq_enable(); - trace_timer_interrupt_entry(regs); __get_cpu_var(irq_stat).timer_irqs++; @@ -508,10 +597,20 @@ void timer_interrupt(struct pt_regs * regs) irq_work_run(); } +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES)) + get_lppaca()->int_dword.fields.decr_int = 0; +#endif + *next_tb = ~(u64)0; if (evt->event_handler) evt->event_handler(evt); +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending()) + process_hvlpevents(); +#endif + #ifdef CONFIG_PPC64 /* collect purr register values often, for accurate calculations */ if (firmware_has_feature(FW_FEATURE_SPLPAR)) { @@ -883,8 +982,9 @@ void __init time_init(void) */ start_cpu_decrementer(); - /* Register the clocksource */ - clocksource_init(); + /* Register the clocksource, if we're not running on iSeries */ + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + clocksource_init(); init_decrementer_clockevent(); } diff --git a/trunk/arch/powerpc/kernel/traps.c b/trunk/arch/powerpc/kernel/traps.c index a750409ccc4e..c091527efd89 100644 --- a/trunk/arch/powerpc/kernel/traps.c +++ b/trunk/arch/powerpc/kernel/traps.c @@ -57,7 +57,6 @@ #include #include #include -#include #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) int (*__debugger)(struct pt_regs *regs) __read_mostly; @@ -146,8 +145,6 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, arch_spin_unlock(&die_lock); raw_local_irq_restore(flags); - crash_fadump(regs, "die oops"); - /* * A system reset (0x100) is a request to dump, so we always send * it through the crashdump code. @@ -247,9 +244,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) addr, regs->nip, regs->link, code); } - if (!arch_irq_disabled_regs(regs)) - local_irq_enable(); - memset(&info, 0, sizeof(info)); info.si_signo = signr; info.si_code = code; diff --git a/trunk/arch/powerpc/kernel/vio.c b/trunk/arch/powerpc/kernel/vio.c index bca3fc427b45..8b086299ba25 100644 --- a/trunk/arch/powerpc/kernel/vio.c +++ b/trunk/arch/powerpc/kernel/vio.c @@ -34,6 +34,11 @@ #include #include #include +#include +#include +#include +#include +#include static struct bus_type vio_bus_type; @@ -1037,6 +1042,7 @@ static void vio_cmo_sysfs_init(void) vio_bus_type.bus_attrs = vio_cmo_bus_attrs; } #else /* CONFIG_PPC_SMLPAR */ +/* Dummy functions for iSeries platform */ int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; } void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {} static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; } @@ -1054,6 +1060,9 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) struct iommu_table *tbl; unsigned long offset, size; + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return vio_build_iommu_table_iseries(dev); + dma_window = of_get_property(dev->dev.of_node, "ibm,my-dma-window", NULL); if (!dma_window) @@ -1186,7 +1195,8 @@ static void __devinit vio_dev_release(struct device *dev) { struct iommu_table *tbl = get_iommu_table_base(dev); - if (tbl) + /* iSeries uses a common table for all vio devices */ + if (!firmware_has_feature(FW_FEATURE_ISERIES) && tbl) iommu_free_table(tbl, dev->of_node ? dev->of_node->full_name : dev_name(dev)); of_node_put(dev->of_node); @@ -1234,6 +1244,12 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) viodev->name = of_node->name; viodev->type = of_node->type; viodev->unit_address = *unit_address; + if (firmware_has_feature(FW_FEATURE_ISERIES)) { + unit_address = of_get_property(of_node, + "linux,unit_address", NULL); + if (unit_address != NULL) + viodev->unit_address = *unit_address; + } viodev->dev.of_node = of_node_get(of_node); if (firmware_has_feature(FW_FEATURE_CMO)) diff --git a/trunk/arch/powerpc/kernel/vmlinux.lds.S b/trunk/arch/powerpc/kernel/vmlinux.lds.S index 65d1c08cf09e..710a54005dfb 100644 --- a/trunk/arch/powerpc/kernel/vmlinux.lds.S +++ b/trunk/arch/powerpc/kernel/vmlinux.lds.S @@ -109,6 +109,11 @@ SECTIONS __ptov_table_begin = .; *(.ptov_fixup); __ptov_table_end = .; +#ifdef CONFIG_PPC_ISERIES + __dt_strings_start = .; + *(.dt_strings); + __dt_strings_end = .; +#endif } .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { diff --git a/trunk/arch/powerpc/kvm/book3s_hv.c b/trunk/arch/powerpc/kvm/book3s_hv.c index a7267167a550..336983da9e72 100644 --- a/trunk/arch/powerpc/kvm/book3s_hv.c +++ b/trunk/arch/powerpc/kvm/book3s_hv.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include diff --git a/trunk/arch/powerpc/lib/locks.c b/trunk/arch/powerpc/lib/locks.c index bb7cfecf2788..a6ebba56fdd4 100644 --- a/trunk/arch/powerpc/lib/locks.c +++ b/trunk/arch/powerpc/lib/locks.c @@ -19,9 +19,11 @@ #include /* waiting for a spinlock... */ -#if defined(CONFIG_PPC_SPLPAR) +#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) #include +#include #include +#include void __spin_yield(arch_spinlock_t *lock) { @@ -38,8 +40,14 @@ void __spin_yield(arch_spinlock_t *lock) rmb(); if (lock->slock != lock_value) return; /* something has changed */ - plpar_hcall_norets(H_CONFER, - get_hard_smp_processor_id(holder_cpu), yield_count); + if (firmware_has_feature(FW_FEATURE_ISERIES)) + HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, + ((u64)holder_cpu << 32) | yield_count); +#ifdef CONFIG_PPC_SPLPAR + else + plpar_hcall_norets(H_CONFER, + get_hard_smp_processor_id(holder_cpu), yield_count); +#endif } /* @@ -63,8 +71,14 @@ void __rw_yield(arch_rwlock_t *rw) rmb(); if (rw->lock != lock_value) return; /* something has changed */ - plpar_hcall_norets(H_CONFER, - get_hard_smp_processor_id(holder_cpu), yield_count); + if (firmware_has_feature(FW_FEATURE_ISERIES)) + HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, + ((u64)holder_cpu << 32) | yield_count); +#ifdef CONFIG_PPC_SPLPAR + else + plpar_hcall_norets(H_CONFER, + get_hard_smp_processor_id(holder_cpu), yield_count); +#endif } #endif diff --git a/trunk/arch/powerpc/mm/fault.c b/trunk/arch/powerpc/mm/fault.c index 19f2f9498b27..2f0d1b032a89 100644 --- a/trunk/arch/powerpc/mm/fault.c +++ b/trunk/arch/powerpc/mm/fault.c @@ -105,82 +105,6 @@ static int store_updates_sp(struct pt_regs *regs) } return 0; } -/* - * do_page_fault error handling helpers - */ - -#define MM_FAULT_RETURN 0 -#define MM_FAULT_CONTINUE -1 -#define MM_FAULT_ERR(sig) (sig) - -static int out_of_memory(struct pt_regs *regs) -{ - /* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ - up_read(¤t->mm->mmap_sem); - if (!user_mode(regs)) - return MM_FAULT_ERR(SIGKILL); - pagefault_out_of_memory(); - return MM_FAULT_RETURN; -} - -static int do_sigbus(struct pt_regs *regs, unsigned long address) -{ - siginfo_t info; - - up_read(¤t->mm->mmap_sem); - - if (user_mode(regs)) { - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_ADRERR; - info.si_addr = (void __user *)address; - force_sig_info(SIGBUS, &info, current); - return MM_FAULT_RETURN; - } - return MM_FAULT_ERR(SIGBUS); -} - -static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault) -{ - /* - * Pagefault was interrupted by SIGKILL. We have no reason to - * continue the pagefault. - */ - if (fatal_signal_pending(current)) { - /* - * If we have retry set, the mmap semaphore will have - * alrady been released in __lock_page_or_retry(). Else - * we release it now. - */ - if (!(fault & VM_FAULT_RETRY)) - up_read(¤t->mm->mmap_sem); - /* Coming from kernel, we need to deal with uaccess fixups */ - if (user_mode(regs)) - return MM_FAULT_RETURN; - return MM_FAULT_ERR(SIGKILL); - } - - /* No fault: be happy */ - if (!(fault & VM_FAULT_ERROR)) - return MM_FAULT_CONTINUE; - - /* Out of memory */ - if (fault & VM_FAULT_OOM) - return out_of_memory(regs); - - /* Bus error. x86 handles HWPOISON here, we'll add this if/when - * we support the feature in HW - */ - if (fault & VM_FAULT_SIGBUS) - return do_sigbus(regs, addr); - - /* We don't understand the fault code, this is fatal */ - BUG(); - return MM_FAULT_CONTINUE; -} /* * For 600- and 800-family processors, the error_code parameter is DSISR @@ -200,12 +124,11 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, { struct vm_area_struct * vma; struct mm_struct *mm = current->mm; - unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; + siginfo_t info; int code = SEGV_MAPERR; - int is_write = 0; + int is_write = 0, ret; int trap = TRAP(regs); int is_exec = trap == 0x400; - int fault; #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) /* @@ -222,9 +145,6 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, is_write = error_code & ESR_DST; #endif /* CONFIG_4xx || CONFIG_BOOKE */ - if (is_write) - flags |= FAULT_FLAG_WRITE; - #ifdef CONFIG_PPC_ICSWX /* * we need to do this early because this "data storage @@ -232,11 +152,13 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, * look at it */ if (error_code & ICSWX_DSI_UCT) { - int rc = acop_handle_fault(regs, address, error_code); - if (rc) - return rc; + int ret; + + ret = acop_handle_fault(regs, address, error_code); + if (ret) + return ret; } -#endif /* CONFIG_PPC_ICSWX */ +#endif if (notify_page_fault(regs)) return 0; @@ -257,10 +179,6 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, } #endif - /* We restore the interrupt state now */ - if (!arch_irq_disabled_regs(regs)) - local_irq_enable(); - if (in_atomic() || mm == NULL) { if (!user_mode(regs)) return SIGSEGV; @@ -294,15 +212,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, if (!user_mode(regs) && !search_exception_tables(regs->nip)) goto bad_area_nosemaphore; -retry: down_read(&mm->mmap_sem); - } else { - /* - * The above down_read_trylock() might have succeeded in - * which case we'll have missed the might_sleep() from - * down_read(): - */ - might_sleep(); } vma = find_vma(mm, address); @@ -417,43 +327,30 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, * make sure we exit gracefully rather than endlessly redo * the fault. */ - fault = handle_mm_fault(mm, vma, address, flags); - if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) { - int rc = mm_fault_error(regs, address, fault); - if (rc >= MM_FAULT_RETURN) - return rc; + ret = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); + if (unlikely(ret & VM_FAULT_ERROR)) { + if (ret & VM_FAULT_OOM) + goto out_of_memory; + else if (ret & VM_FAULT_SIGBUS) + goto do_sigbus; + BUG(); } - - /* - * Major/minor page fault accounting is only done on the - * initial attempt. If we go through a retry, it is extremely - * likely that the page will be found in page cache at that point. - */ - if (flags & FAULT_FLAG_ALLOW_RETRY) { - if (fault & VM_FAULT_MAJOR) { - current->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, - regs, address); + if (ret & VM_FAULT_MAJOR) { + current->maj_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, + regs, address); #ifdef CONFIG_PPC_SMLPAR - if (firmware_has_feature(FW_FEATURE_CMO)) { - preempt_disable(); - get_lppaca()->page_ins += (1 << PAGE_FACTOR); - preempt_enable(); - } -#endif /* CONFIG_PPC_SMLPAR */ - } else { - current->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, - regs, address); - } - if (fault & VM_FAULT_RETRY) { - /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk - * of starvation. */ - flags &= ~FAULT_FLAG_ALLOW_RETRY; - goto retry; + if (firmware_has_feature(FW_FEATURE_CMO)) { + preempt_disable(); + get_lppaca()->page_ins += (1 << PAGE_FACTOR); + preempt_enable(); } +#endif + } else { + current->min_flt++; + perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, + regs, address); } - up_read(&mm->mmap_sem); return 0; @@ -474,6 +371,28 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, return SIGSEGV; +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +out_of_memory: + up_read(&mm->mmap_sem); + if (!user_mode(regs)) + return SIGKILL; + pagefault_out_of_memory(); + return 0; + +do_sigbus: + up_read(&mm->mmap_sem); + if (user_mode(regs)) { + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void __user *)address; + force_sig_info(SIGBUS, &info, current); + return 0; + } + return SIGBUS; } /* diff --git a/trunk/arch/powerpc/mm/fsl_booke_mmu.c b/trunk/arch/powerpc/mm/fsl_booke_mmu.c index 07ba45b0f07c..66a6fd38e9cd 100644 --- a/trunk/arch/powerpc/mm/fsl_booke_mmu.c +++ b/trunk/arch/powerpc/mm/fsl_booke_mmu.c @@ -149,19 +149,12 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys, unsigned long calc_cam_sz(unsigned long ram, unsigned long virt, phys_addr_t phys) { - unsigned int camsize = __ilog2(ram); - unsigned int align = __ffs(virt | phys); - unsigned long max_cam; - - if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) { - /* Convert (4^max) kB to (2^max) bytes */ - max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10; - camsize &= ~1U; - align &= ~1U; - } else { - /* Convert (2^max) kB to (2^max) bytes */ - max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10; - } + unsigned int camsize = __ilog2(ram) & ~1U; + unsigned int align = __ffs(virt | phys) & ~1U; + unsigned long max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf; + + /* Convert (4^max) kB to (2^max) bytes */ + max_cam = max_cam * 2 + 10; if (camsize > align) camsize = align; diff --git a/trunk/arch/powerpc/mm/hash_utils_64.c b/trunk/arch/powerpc/mm/hash_utils_64.c index 3e8c37a4e395..2d282186cb45 100644 --- a/trunk/arch/powerpc/mm/hash_utils_64.c +++ b/trunk/arch/powerpc/mm/hash_utils_64.c @@ -55,8 +55,6 @@ #include #include #include -#include -#include #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -627,16 +625,6 @@ static void __init htab_initialize(void) /* Using a hypervisor which owns the htab */ htab_address = NULL; _SDR1 = 0; -#ifdef CONFIG_FA_DUMP - /* - * If firmware assisted dump is active firmware preserves - * the contents of htab along with entire partition memory. - * Clear the htab if firmware assisted dump is active so - * that we dont end up using old mappings. - */ - if (is_fadump_active() && ppc_md.hpte_clear_all) - ppc_md.hpte_clear_all(); -#endif } else { /* Find storage for the HPT. Must be contiguous in * the absolute address space. On cell we want it to be @@ -757,9 +745,12 @@ void __init early_init_mmu(void) */ htab_initialize(); - /* Initialize stab / SLB management */ + /* Initialize stab / SLB management except on iSeries + */ if (mmu_has_feature(MMU_FTR_SLB)) slb_initialize(); + else if (!firmware_has_feature(FW_FEATURE_ISERIES)) + stab_initialize(get_paca()->stab_real); } #ifdef CONFIG_SMP @@ -770,7 +761,8 @@ void __cpuinit early_init_mmu_secondary(void) mtspr(SPRN_SDR1, _SDR1); /* Initialize STAB/SLB. We use a virtual address as it works - * in real mode on pSeries. + * in real mode on pSeries and we want a virtual address on + * iSeries anyway */ if (mmu_has_feature(MMU_FTR_SLB)) slb_initialize(); diff --git a/trunk/arch/powerpc/mm/icswx.c b/trunk/arch/powerpc/mm/icswx.c index 8cdbd8634a58..5d9a59eaad93 100644 --- a/trunk/arch/powerpc/mm/icswx.c +++ b/trunk/arch/powerpc/mm/icswx.c @@ -163,7 +163,7 @@ EXPORT_SYMBOL_GPL(drop_cop); static int acop_use_cop(int ct) { - /* There is no alternate policy, yet */ + /* todo */ return -1; } @@ -227,30 +227,11 @@ int acop_handle_fault(struct pt_regs *regs, unsigned long address, ct = (ccw >> 16) & 0x3f; } - /* - * We could be here because another thread has enabled acop - * but the ACOP register has yet to be updated. - * - * This should have been taken care of by the IPI to sync all - * the threads (see smp_call_function(sync_cop, mm, 1)), but - * that could take forever if there are a significant amount - * of threads. - * - * Given the number of threads on some of these systems, - * perhaps this is the best way to sync ACOP rather than whack - * every thread with an IPI. - */ - if ((acop_copro_type_bit(ct) & current->active_mm->context.acop) != 0) { - sync_cop(current->active_mm); - return 0; - } - - /* check for alternate policy */ if (!acop_use_cop(ct)) return 0; /* at this point the CT is unknown to the system */ - pr_warn("%s[%d]: Coprocessor %d is unavailable\n", + pr_warn("%s[%d]: Coprocessor %d is unavailable", current->comm, current->pid, ct); /* get inst if we don't already have it */ diff --git a/trunk/arch/powerpc/mm/icswx.h b/trunk/arch/powerpc/mm/icswx.h index 6dedc08e62c8..42176bd0884c 100644 --- a/trunk/arch/powerpc/mm/icswx.h +++ b/trunk/arch/powerpc/mm/icswx.h @@ -59,10 +59,4 @@ extern void free_cop_pid(int free_pid); extern int acop_handle_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code); - -static inline u64 acop_copro_type_bit(unsigned int type) -{ - return 1ULL << (63 - type); -} - #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */ diff --git a/trunk/arch/powerpc/mm/pgtable_32.c b/trunk/arch/powerpc/mm/pgtable_32.c index 0907f92ce309..51f87956f8f8 100644 --- a/trunk/arch/powerpc/mm/pgtable_32.c +++ b/trunk/arch/powerpc/mm/pgtable_32.c @@ -207,7 +207,7 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags, */ if (mem_init_done && (p < virt_to_phys(high_memory)) && !(__allow_ioremap_reserved && memblock_is_region_reserved(p, size))) { - printk("__ioremap(): phys addr 0x%llx is RAM lr %pf\n", + printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n", (unsigned long long)p, __builtin_return_address(0)); return NULL; } diff --git a/trunk/arch/powerpc/mm/slb.c b/trunk/arch/powerpc/mm/slb.c index a538c80db2df..e22276cb67a4 100644 --- a/trunk/arch/powerpc/mm/slb.c +++ b/trunk/arch/powerpc/mm/slb.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -306,6 +307,11 @@ void slb_initialize(void) get_paca()->stab_rr = SLB_NUM_BOLTED; + /* On iSeries the bolted entries have already been set up by + * the hypervisor from the lparMap data in head.S */ + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return; + lflags = SLB_VSID_KERNEL | linear_llp; vflags = SLB_VSID_KERNEL | vmalloc_llp; diff --git a/trunk/arch/powerpc/mm/slb_low.S b/trunk/arch/powerpc/mm/slb_low.S index b9ee79ce2200..ef653dc95b65 100644 --- a/trunk/arch/powerpc/mm/slb_low.S +++ b/trunk/arch/powerpc/mm/slb_low.S @@ -217,6 +217,21 @@ slb_finish_load: * free slot first but that took too long. Unfortunately we * dont have any LRU information to help us choose a slot. */ +#ifdef CONFIG_PPC_ISERIES +BEGIN_FW_FTR_SECTION + /* + * On iSeries, the "bolted" stack segment can be cast out on + * shared processor switch so we need to check for a miss on + * it and restore it to the right slot. + */ + ld r9,PACAKSAVE(r13) + clrrdi r9,r9,28 + clrrdi r3,r3,28 + li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */ + cmpld r9,r3 + beq 3f +END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) +#endif /* CONFIG_PPC_ISERIES */ 7: ld r10,PACASTABRR(r13) addi r10,r10,1 @@ -267,6 +282,7 @@ _GLOBAL(slb_compare_rr_to_size) /* * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. + * We assume legacy iSeries will never have 1T segments. * * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9 */ diff --git a/trunk/arch/powerpc/mm/stab.c b/trunk/arch/powerpc/mm/stab.c index 9106ebb118f5..41e31642a86a 100644 --- a/trunk/arch/powerpc/mm/stab.c +++ b/trunk/arch/powerpc/mm/stab.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include struct stab_entry { unsigned long esid_data; @@ -283,5 +285,12 @@ void stab_initialize(unsigned long stab) /* Set ASR */ stabreal = get_paca()->stab_real | 0x1ul; +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES)) { + HvCall1(HvCallBaseSetASR, stabreal); + return; + } +#endif /* CONFIG_PPC_ISERIES */ + mtspr(SPRN_ASR, stabreal); } diff --git a/trunk/arch/powerpc/oprofile/common.c b/trunk/arch/powerpc/oprofile/common.c index 6f01624f317f..d65e68f3cb25 100644 --- a/trunk/arch/powerpc/oprofile/common.c +++ b/trunk/arch/powerpc/oprofile/common.c @@ -195,6 +195,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) if (!cur_cpu_spec->oprofile_cpu_type) return -ENODEV; + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + switch (cur_cpu_spec->oprofile_type) { #ifdef CONFIG_PPC_BOOK3S_64 #ifdef CONFIG_OPROFILE_CELL diff --git a/trunk/arch/powerpc/perf/Makefile b/trunk/arch/powerpc/perf/Makefile deleted file mode 100644 index af3fac23768c..000000000000 --- a/trunk/arch/powerpc/perf/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror - -obj-$(CONFIG_PERF_EVENTS) += callchain.o - -obj-$(CONFIG_PPC_PERF_CTRS) += core-book3s.o -obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \ - power5+-pmu.o power6-pmu.o power7-pmu.o -obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o - -obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o -obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o - -obj-$(CONFIG_PPC64) += $(obj64-y) -obj-$(CONFIG_PPC32) += $(obj32-y) diff --git a/trunk/arch/powerpc/platforms/44x/Kconfig b/trunk/arch/powerpc/platforms/44x/Kconfig index 2e4e64abfab4..fcf6bf2ceee9 100644 --- a/trunk/arch/powerpc/platforms/44x/Kconfig +++ b/trunk/arch/powerpc/platforms/44x/Kconfig @@ -23,7 +23,6 @@ config BLUESTONE default n select PPC44x_SIMPLE select APM821xx - select PPC4xx_PCI_EXPRESS select IBM_EMAC_RGMII help This option enables support for the APM APM821xx Evaluation board. diff --git a/trunk/arch/powerpc/platforms/44x/currituck.c b/trunk/arch/powerpc/platforms/44x/currituck.c index 583e67fee37e..3f6229b5dee0 100644 --- a/trunk/arch/powerpc/platforms/44x/currituck.c +++ b/trunk/arch/powerpc/platforms/44x/currituck.c @@ -83,7 +83,7 @@ static void __init ppc47x_init_irq(void) * device-tree, just pass 0 to all arguments */ struct mpic *mpic = - mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC "); + mpic_alloc(np, 0, 0, 0, 0, " MPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); ppc_md.get_irq = mpic_get_irq; diff --git a/trunk/arch/powerpc/platforms/44x/iss4xx.c b/trunk/arch/powerpc/platforms/44x/iss4xx.c index a28a8629727e..5b8cdbb82f80 100644 --- a/trunk/arch/powerpc/platforms/44x/iss4xx.c +++ b/trunk/arch/powerpc/platforms/44x/iss4xx.c @@ -71,7 +71,8 @@ static void __init iss4xx_init_irq(void) /* The MPIC driver will get everything it needs from the * device-tree, just pass 0 to all arguments */ - struct mpic *mpic = mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC "); + struct mpic *mpic = mpic_alloc(np, 0, 0, 0, 0, + " MPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); ppc_md.get_irq = mpic_get_irq; diff --git a/trunk/arch/powerpc/platforms/44x/ppc44x_simple.c b/trunk/arch/powerpc/platforms/44x/ppc44x_simple.c index 3ffb915446e3..8d2202763415 100644 --- a/trunk/arch/powerpc/platforms/44x/ppc44x_simple.c +++ b/trunk/arch/powerpc/platforms/44x/ppc44x_simple.c @@ -52,7 +52,7 @@ machine_device_initcall(ppc44x_simple, ppc44x_device_probe); static char *board[] __initdata = { "amcc,arches", "amcc,bamboo", - "apm,bluestone", + "amcc,bluestone", "amcc,glacier", "ibm,ebony", "amcc,eiger", diff --git a/trunk/arch/powerpc/platforms/52xx/mpc5200_simple.c b/trunk/arch/powerpc/platforms/52xx/mpc5200_simple.c index c0aa04068d69..846b789fb195 100644 --- a/trunk/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/trunk/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -50,7 +50,6 @@ static void __init mpc5200_simple_setup_arch(void) /* list of the supported boards */ static const char *board[] __initdata = { - "anonymous,a4m072", "anon,charon", "intercontrol,digsy-mtc", "manroland,mucmc52", diff --git a/trunk/arch/powerpc/platforms/52xx/mpc52xx_common.c b/trunk/arch/powerpc/platforms/52xx/mpc52xx_common.c index d7e94f49532a..369fd5457a3f 100644 --- a/trunk/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/trunk/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -98,11 +98,13 @@ struct mpc52xx_gpio_wkup __iomem *wkup_gpio; * of the localplus bus to the of_platform * bus. */ -void __init mpc52xx_declare_of_platform_devices(void) +void __init +mpc52xx_declare_of_platform_devices(void) { - /* Find all the 'platform' devices and register them. */ - if (of_platform_populate(NULL, mpc52xx_bus_ids, NULL, NULL)) - pr_err(__FILE__ ": Error while populating devices from DT\n"); + /* Find every child of the SOC node and add it to of_platform */ + if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL)) + printk(KERN_ERR __FILE__ ": " + "Error while probing of_platform bus\n"); } /* diff --git a/trunk/arch/powerpc/platforms/85xx/Kconfig b/trunk/arch/powerpc/platforms/85xx/Kconfig index f000d81c4e31..d7946be298b6 100644 --- a/trunk/arch/powerpc/platforms/85xx/Kconfig +++ b/trunk/arch/powerpc/platforms/85xx/Kconfig @@ -6,7 +6,6 @@ menuconfig FSL_SOC_BOOKE select MPIC select PPC_PCI_CHOICE select FSL_PCI if PCI - select SERIAL_8250_EXTENDED if SERIAL_8250 select SERIAL_8250_SHARE_IRQ if SERIAL_8250 default y @@ -14,15 +13,6 @@ if FSL_SOC_BOOKE if PPC32 -config FSL_85XX_CACHE_SRAM - bool - select PPC_LIB_RHEAP - help - When selected, this option enables cache-sram support - for memory allocation on P1/P2 QorIQ platforms. - cache-sram-size and cache-sram-offset kernel boot - parameters should be passed when this option is enabled. - config MPC8540_ADS bool "Freescale MPC8540 ADS" select DEFAULT_UIMAGE @@ -40,7 +30,6 @@ config MPC85xx_CDS bool "Freescale MPC85xx CDS" select DEFAULT_UIMAGE select PPC_I8259 - select HAS_RAPIDIO help This option enables support for the MPC85xx CDS board @@ -91,6 +80,7 @@ config P1010_RDB config P1022_DS bool "Freescale P1022 DS" select DEFAULT_UIMAGE + select PHYS_64BIT # The DTS has 36-bit addresses select SWIOTLB help This option enables support for the Freescale P1022DS reference board. @@ -181,21 +171,6 @@ config SBC8560 help This option enables support for the Wind River SBC8560 board -config GE_IMP3A - bool "GE Intelligent Platforms IMP3A" - select DEFAULT_UIMAGE - select SWIOTLB - select MMIO_NVRAM - select GENERIC_GPIO - select ARCH_REQUIRE_GPIOLIB - select GE_FPGA - help - This option enables support for the GE Intelligent Platforms IMP3A - board. - - This board is a 3U CompactPCI Single Board Computer with a Freescale - P2020 processor. - config P2041_RDB bool "Freescale P2041 RDB" select DEFAULT_UIMAGE diff --git a/trunk/arch/powerpc/platforms/85xx/Makefile b/trunk/arch/powerpc/platforms/85xx/Makefile index 2125d4ca068a..9cb2d4320dcc 100644 --- a/trunk/arch/powerpc/platforms/85xx/Makefile +++ b/trunk/arch/powerpc/platforms/85xx/Makefile @@ -27,4 +27,3 @@ obj-$(CONFIG_SBC8548) += sbc8548.o obj-$(CONFIG_SOCRATES) += socrates.o socrates_fpga_pic.o obj-$(CONFIG_KSI8560) += ksi8560.o obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o -obj-$(CONFIG_GE_IMP3A) += ge_imp3a.o diff --git a/trunk/arch/powerpc/platforms/85xx/corenet_ds.c b/trunk/arch/powerpc/platforms/85xx/corenet_ds.c index df69e99e511c..07e3e6c47371 100644 --- a/trunk/arch/powerpc/platforms/85xx/corenet_ds.c +++ b/trunk/arch/powerpc/platforms/85xx/corenet_ds.c @@ -36,8 +36,8 @@ void __init corenet_ds_pic_init(void) { struct mpic *mpic; - unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU | - MPIC_NO_RESET; + unsigned int flags = MPIC_BIG_ENDIAN | + MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU; if (ppc_md.get_irq == mpic_get_coreint_irq) flags |= MPIC_ENABLE_COREINT; diff --git a/trunk/arch/powerpc/platforms/85xx/ge_imp3a.c b/trunk/arch/powerpc/platforms/85xx/ge_imp3a.c deleted file mode 100644 index d50056f424f6..000000000000 --- a/trunk/arch/powerpc/platforms/85xx/ge_imp3a.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * GE IMP3A Board Setup - * - * Author Martyn Welch - * - * Copyright 2010 GE Intelligent Platforms Embedded Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Based on: mpc85xx_ds.c (MPC85xx DS Board Setup) - * Copyright 2007 Freescale Semiconductor Inc. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "smp.h" - -#include "mpc85xx.h" -#include - -void __iomem *imp3a_regs; - -void __init ge_imp3a_pic_init(void) -{ - struct mpic *mpic; - struct device_node *np; - struct device_node *cascade_node = NULL; - unsigned long root = of_get_flat_dt_root(); - - if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { - mpic = mpic_alloc(NULL, 0, - MPIC_NO_RESET | - MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, - 0, 256, " OpenPIC "); - } else { - mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, - 0, 256, " OpenPIC "); - } - - BUG_ON(mpic == NULL); - mpic_init(mpic); - /* - * There is a simple interrupt handler in the main FPGA, this needs - * to be cascaded into the MPIC - */ - for_each_node_by_type(np, "interrupt-controller") - if (of_device_is_compatible(np, "gef,fpga-pic-1.00")) { - cascade_node = np; - break; - } - - if (cascade_node == NULL) { - printk(KERN_WARNING "IMP3A: No FPGA PIC\n"); - return; - } - - gef_pic_init(cascade_node); - of_node_put(cascade_node); -} - -#ifdef CONFIG_PCI -static int primary_phb_addr; -#endif /* CONFIG_PCI */ - -/* - * Setup the architecture - */ -static void __init ge_imp3a_setup_arch(void) -{ - struct device_node *regs; -#ifdef CONFIG_PCI - struct device_node *np; - struct pci_controller *hose; -#endif - dma_addr_t max = 0xffffffff; - - if (ppc_md.progress) - ppc_md.progress("ge_imp3a_setup_arch()", 0); - -#ifdef CONFIG_PCI - for_each_node_by_type(np, "pci") { - if (of_device_is_compatible(np, "fsl,mpc8540-pci") || - of_device_is_compatible(np, "fsl,mpc8548-pcie") || - of_device_is_compatible(np, "fsl,p2020-pcie")) { - struct resource rsrc; - of_address_to_resource(np, 0, &rsrc); - if ((rsrc.start & 0xfffff) == primary_phb_addr) - fsl_add_bridge(np, 1); - else - fsl_add_bridge(np, 0); - - hose = pci_find_hose_for_OF_device(np); - max = min(max, hose->dma_window_base_cur + - hose->dma_window_size); - } - } -#endif - - mpc85xx_smp_init(); - -#ifdef CONFIG_SWIOTLB - if (memblock_end_of_DRAM() > max) { - ppc_swiotlb_enable = 1; - set_pci_dma_ops(&swiotlb_dma_ops); - ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; - } -#endif - - /* Remap basic board registers */ - regs = of_find_compatible_node(NULL, NULL, "ge,imp3a-fpga-regs"); - if (regs) { - imp3a_regs = of_iomap(regs, 0); - if (imp3a_regs == NULL) - printk(KERN_WARNING "Unable to map board registers\n"); - of_node_put(regs); - } - -#if defined(CONFIG_MMIO_NVRAM) - mmio_nvram_init(); -#endif - - printk(KERN_INFO "GE Intelligent Platforms IMP3A 3U cPCI SBC\n"); -} - -/* Return the PCB revision */ -static unsigned int ge_imp3a_get_pcb_rev(void) -{ - unsigned int reg; - - reg = ioread16(imp3a_regs); - return (reg >> 8) & 0xff; -} - -/* Return the board (software) revision */ -static unsigned int ge_imp3a_get_board_rev(void) -{ - unsigned int reg; - - reg = ioread16(imp3a_regs + 0x2); - return reg & 0xff; -} - -/* Return the FPGA revision */ -static unsigned int ge_imp3a_get_fpga_rev(void) -{ - unsigned int reg; - - reg = ioread16(imp3a_regs + 0x2); - return (reg >> 8) & 0xff; -} - -/* Return compactPCI Geographical Address */ -static unsigned int ge_imp3a_get_cpci_geo_addr(void) -{ - unsigned int reg; - - reg = ioread16(imp3a_regs + 0x6); - return (reg & 0x0f00) >> 8; -} - -/* Return compactPCI System Controller Status */ -static unsigned int ge_imp3a_get_cpci_is_syscon(void) -{ - unsigned int reg; - - reg = ioread16(imp3a_regs + 0x6); - return reg & (1 << 12); -} - -static void ge_imp3a_show_cpuinfo(struct seq_file *m) -{ - seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n"); - - seq_printf(m, "Revision\t: %u%c\n", ge_imp3a_get_pcb_rev(), - ('A' + ge_imp3a_get_board_rev() - 1)); - - seq_printf(m, "FPGA Revision\t: %u\n", ge_imp3a_get_fpga_rev()); - - seq_printf(m, "cPCI geo. addr\t: %u\n", ge_imp3a_get_cpci_geo_addr()); - - seq_printf(m, "cPCI syscon\t: %s\n", - ge_imp3a_get_cpci_is_syscon() ? "yes" : "no"); -} - -/* - * Called very early, device-tree isn't unflattened - */ -static int __init ge_imp3a_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - if (of_flat_dt_is_compatible(root, "ge,IMP3A")) { -#ifdef CONFIG_PCI - primary_phb_addr = 0x9000; -#endif - return 1; - } - - return 0; -} - -machine_device_initcall(ge_imp3a, mpc85xx_common_publish_devices); - -machine_arch_initcall(ge_imp3a, swiotlb_setup_bus_notifier); - -define_machine(ge_imp3a) { - .name = "GE_IMP3A", - .probe = ge_imp3a_probe, - .setup_arch = ge_imp3a_setup_arch, - .init_IRQ = ge_imp3a_pic_init, - .show_cpuinfo = ge_imp3a_show_cpuinfo, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, -#endif - .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; diff --git a/trunk/arch/powerpc/platforms/85xx/ksi8560.c b/trunk/arch/powerpc/platforms/85xx/ksi8560.c index 60120e55da41..20f75d7819c6 100644 --- a/trunk/arch/powerpc/platforms/85xx/ksi8560.c +++ b/trunk/arch/powerpc/platforms/85xx/ksi8560.c @@ -57,7 +57,8 @@ static void machine_restart(char *cmd) static void __init ksi8560_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/85xx/mpc8536_ds.c b/trunk/arch/powerpc/platforms/85xx/mpc8536_ds.c index f58872688d8f..cf266826682e 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -36,7 +36,9 @@ void __init mpc8536_ds_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_ads.c index d19f675cb369..3bebb5173bfc 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -50,7 +50,8 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, static void __init mpc85xx_ads_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c index ab5f0bf19454..40f03da616a9 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -3,7 +3,7 @@ * * Maintained by Kumar Gala (see MAINTAINERS for contact information) * - * Copyright 2005, 2011-2012 Freescale Semiconductor Inc. + * Copyright 2005 Freescale Semiconductor Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -48,24 +48,17 @@ #include "mpc85xx.h" -/* - * The CDS board contains an FPGA/CPLD called "Cadmus", which collects - * various logic and performs system control functions. - * Here is the FPGA/CPLD register map. - */ -struct cadmus_reg { - u8 cm_ver; /* Board version */ - u8 cm_csr; /* General control/status */ - u8 cm_rst; /* Reset control */ - u8 cm_hsclk; /* High speed clock */ - u8 cm_hsxclk; /* High speed clock extended */ - u8 cm_led; /* LED data */ - u8 cm_pci; /* PCI control/status */ - u8 cm_dma; /* DMA control */ - u8 res[248]; /* Total 256 bytes */ -}; +/* CADMUS info */ +/* xxx - galak, move into device tree */ +#define CADMUS_BASE (0xf8004000) +#define CADMUS_SIZE (256) +#define CM_VER (0) +#define CM_CSR (1) +#define CM_RST (2) -static struct cadmus_reg *cadmus; + +static int cds_pci_slot = 2; +static volatile u8 *cadmus; #ifdef CONFIG_PCI @@ -165,33 +158,6 @@ DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge); DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge); DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge); -#define PCI_DEVICE_ID_IDT_TSI310 0x01a7 - -/* - * Fix Tsi310 PCI-X bridge resource. - * Force the bridge to open a window from 0x0000-0x1fff in PCI I/O space. - * This allows legacy I/O(i8259, etc) on the VIA southbridge to be accessed. - */ -void mpc85xx_cds_fixup_bus(struct pci_bus *bus) -{ - struct pci_dev *dev = bus->self; - struct resource *res = bus->resource[0]; - - if (dev != NULL && - dev->vendor == PCI_VENDOR_ID_IBM && - dev->device == PCI_DEVICE_ID_IDT_TSI310) { - if (res) { - res->start = 0; - res->end = 0x1fff; - res->flags = IORESOURCE_IO; - pr_info("mpc85xx_cds: PCI bridge resource fixup applied\n"); - pr_info("mpc85xx_cds: %pR\n", res); - } - } - - fsl_pcibios_fixup_bus(bus); -} - #ifdef CONFIG_PPC_I8259 static void mpc85xx_8259_cascade_handler(unsigned int irq, struct irq_desc *desc) @@ -222,7 +188,8 @@ static struct irqaction mpc85xxcds_8259_irqaction = { static void __init mpc85xx_cds_pic_init(void) { struct mpic *mpic; - mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, + mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); @@ -282,30 +249,20 @@ machine_device_initcall(mpc85xx_cds, mpc85xx_cds_8259_attach); */ static void __init mpc85xx_cds_setup_arch(void) { +#ifdef CONFIG_PCI struct device_node *np; - int cds_pci_slot; +#endif if (ppc_md.progress) ppc_md.progress("mpc85xx_cds_setup_arch()", 0); - np = of_find_compatible_node(NULL, NULL, "fsl,mpc8548cds-fpga"); - if (!np) { - pr_err("Could not find FPGA node.\n"); - return; - } - - cadmus = of_iomap(np, 0); - of_node_put(np); - if (!cadmus) { - pr_err("Fail to map FPGA area.\n"); - return; - } + cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE); + cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1; if (ppc_md.progress) { char buf[40]; - cds_pci_slot = ((in_8(&cadmus->cm_csr) >> 6) & 0x3) + 1; snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n", - in_8(&cadmus->cm_ver), cds_pci_slot); + cadmus[CM_VER], cds_pci_slot); ppc_md.progress(buf, 0); } @@ -335,8 +292,7 @@ static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) svid = mfspr(SPRN_SVR); seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); - seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", - in_8(&cadmus->cm_ver)); + seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", cadmus[CM_VER]); seq_printf(m, "PVR\t\t: 0x%x\n", pvid); seq_printf(m, "SVR\t\t: 0x%x\n", svid); @@ -367,7 +323,7 @@ define_machine(mpc85xx_cds) { .get_irq = mpic_get_irq, #ifdef CONFIG_PCI .restart = mpc85xx_cds_restart, - .pcibios_fixup_bus = mpc85xx_cds_fixup_bus, + .pcibios_fixup_bus = fsl_pcibios_fixup_bus, #else .restart = fsl_rstcr_restart, #endif diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 6e23e3e34bd9..eefbb91e1d61 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_ds.c @@ -72,13 +72,13 @@ void __init mpc85xx_ds_pic_init(void) if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { mpic = mpic_alloc(NULL, 0, - MPIC_NO_RESET | - MPIC_BIG_ENDIAN | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } else { mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | + MPIC_WANTS_RESET | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c index f33662b46b8d..1d15a0cd2c82 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -1,6 +1,5 @@ /* - * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc. - * All rights reserved. + * Copyright (C) Freescale Semicondutor, Inc. 2006-2010. All rights reserved. * * Author: Andy Fleming * @@ -52,7 +51,6 @@ #include #include #include -#include #include "smp.h" #include "mpc85xx.h" @@ -270,27 +268,34 @@ static void __init mpc85xx_mds_qe_init(void) mpc85xx_mds_reset_ucc_phys(); if (machine_is(p1021_mds)) { - - struct ccsr_guts_85xx __iomem *guts; +#define MPC85xx_PMUXCR_OFFSET 0x60 +#define MPC85xx_PMUXCR_QE0 0x00008000 +#define MPC85xx_PMUXCR_QE3 0x00001000 +#define MPC85xx_PMUXCR_QE9 0x00000040 +#define MPC85xx_PMUXCR_QE12 0x00000008 + static __be32 __iomem *pmuxcr; np = of_find_node_by_name(NULL, "global-utilities"); + if (np) { - guts = of_iomap(np, 0); - if (!guts) - pr_err("mpc85xx-rdb: could not map global utilities register\n"); - else{ + pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET; + + if (!pmuxcr) + printk(KERN_EMERG "Error: Alternate function" + " signal multiplex control register not" + " mapped!\n"); + else /* P1021 has pins muxed for QE and other functions. To * enable QE UEC mode, we need to set bit QE0 for UCC1 * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 * and QE12 for QE MII management signals in PMUXCR * register. */ - setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | - MPC85xx_PMUXCR_QE(3) | - MPC85xx_PMUXCR_QE(9) | - MPC85xx_PMUXCR_QE(12)); - iounmap(guts); - } + setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 | + MPC85xx_PMUXCR_QE3 | + MPC85xx_PMUXCR_QE9 | + MPC85xx_PMUXCR_QE12); + of_node_put(np); } @@ -429,8 +434,9 @@ machine_arch_initcall(p1021_mds, swiotlb_setup_bus_notifier); static void __init mpc85xx_mds_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | + MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); diff --git a/trunk/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/trunk/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index db214cd4c822..ccf520e890be 100644 --- a/trunk/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/trunk/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -1,7 +1,7 @@ /* * MPC85xx RDB Board Setup * - * Copyright 2009,2012 Freescale Semiconductor Inc. + * Copyright 2009 Freescale Semiconductor Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -26,9 +26,6 @@ #include #include #include -#include -#include -#include #include #include @@ -50,36 +47,21 @@ void __init mpc85xx_rdb_pic_init(void) struct mpic *mpic; unsigned long root = of_get_flat_dt_root(); -#ifdef CONFIG_QUICC_ENGINE - struct device_node *np; -#endif - if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP")) { - mpic = mpic_alloc(NULL, 0, MPIC_NO_RESET | - MPIC_BIG_ENDIAN | + mpic = mpic_alloc(NULL, 0, + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } else { mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | + MPIC_WANTS_RESET | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } BUG_ON(mpic == NULL); mpic_init(mpic); - -#ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); - if (np) { - qe_ic_init(np, 0, qe_ic_cascade_low_mpic, - qe_ic_cascade_high_mpic); - of_node_put(np); - - } else - pr_err("%s: Could not find qe-ic node\n", __func__); -#endif - } /* @@ -87,7 +69,7 @@ void __init mpc85xx_rdb_pic_init(void) */ static void __init mpc85xx_rdb_setup_arch(void) { -#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE) +#ifdef CONFIG_PCI struct device_node *np; #endif @@ -103,73 +85,11 @@ static void __init mpc85xx_rdb_setup_arch(void) #endif mpc85xx_smp_init(); - -#ifdef CONFIG_QUICC_ENGINE - np = of_find_compatible_node(NULL, NULL, "fsl,qe"); - if (!np) { - pr_err("%s: Could not find Quicc Engine node\n", __func__); - goto qe_fail; - } - - qe_reset(); - of_node_put(np); - - np = of_find_node_by_name(NULL, "par_io"); - if (np) { - struct device_node *ucc; - - par_io_init(np); - of_node_put(np); - - for_each_node_by_name(ucc, "ucc") - par_io_of_config(ucc); - - } -#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE) - if (machine_is(p1025_rdb)) { - - struct ccsr_guts_85xx __iomem *guts; - - np = of_find_node_by_name(NULL, "global-utilities"); - if (np) { - guts = of_iomap(np, 0); - if (!guts) { - - pr_err("mpc85xx-rdb: could not map global utilities register\n"); - - } else { - /* P1025 has pins muxed for QE and other functions. To - * enable QE UEC mode, we need to set bit QE0 for UCC1 - * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 - * and QE12 for QE MII management singals in PMUXCR - * register. - */ - setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | - MPC85xx_PMUXCR_QE(3) | - MPC85xx_PMUXCR_QE(9) | - MPC85xx_PMUXCR_QE(12)); - iounmap(guts); - } - of_node_put(np); - } - - } -#endif - -qe_fail: -#endif /* CONFIG_QUICC_ENGINE */ - printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n"); } machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices); -machine_device_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices); -machine_device_initcall(p1020_mbg_pc, mpc85xx_common_publish_devices); machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices); -machine_device_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices); -machine_device_initcall(p1020_utm_pc, mpc85xx_common_publish_devices); -machine_device_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices); -machine_device_initcall(p1025_rdb, mpc85xx_common_publish_devices); /* * Called very early, device-tree isn't unflattened @@ -192,52 +112,6 @@ static int __init p1020_rdb_probe(void) return 0; } -static int __init p1020_rdb_pc_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "fsl,P1020RDB-PC"); -} - -static int __init p1021_rdb_pc_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - if (of_flat_dt_is_compatible(root, "fsl,P1021RDB-PC")) - return 1; - return 0; -} - -static int __init p2020_rdb_pc_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - if (of_flat_dt_is_compatible(root, "fsl,P2020RDB-PC")) - return 1; - return 0; -} - -static int __init p1025_rdb_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "fsl,P1025RDB"); -} - -static int __init p1020_mbg_pc_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "fsl,P1020MBG-PC"); -} - -static int __init p1020_utm_pc_probe(void) -{ - unsigned long root = of_get_flat_dt_root(); - - return of_flat_dt_is_compatible(root, "fsl,P1020UTM-PC"); -} - define_machine(p2020_rdb) { .name = "P2020 RDB", .probe = p2020_rdb_probe, @@ -265,87 +139,3 @@ define_machine(p1020_rdb) { .calibrate_decr = generic_calibrate_decr, .progress = udbg_progress, }; - -define_machine(p1021_rdb_pc) { - .name = "P1021 RDB-PC", - .probe = p1021_rdb_pc_probe, - .setup_arch = mpc85xx_rdb_setup_arch, - .init_IRQ = mpc85xx_rdb_pic_init, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, -#endif - .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; - -define_machine(p2020_rdb_pc) { - .name = "P2020RDB-PC", - .probe = p2020_rdb_pc_probe, - .setup_arch = mpc85xx_rdb_setup_arch, - .init_IRQ = mpc85xx_rdb_pic_init, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, -#endif - .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; - -define_machine(p1025_rdb) { - .name = "P1025 RDB", - .probe = p1025_rdb_probe, - .setup_arch = mpc85xx_rdb_setup_arch, - .init_IRQ = mpc85xx_rdb_pic_init, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, -#endif - .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; - -define_machine(p1020_mbg_pc) { - .name = "P1020 MBG-PC", - .probe = p1020_mbg_pc_probe, - .setup_arch = mpc85xx_rdb_setup_arch, - .init_IRQ = mpc85xx_rdb_pic_init, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, -#endif - .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; - -define_machine(p1020_utm_pc) { - .name = "P1020 UTM-PC", - .probe = p1020_utm_pc_probe, - .setup_arch = mpc85xx_rdb_setup_arch, - .init_IRQ = mpc85xx_rdb_pic_init, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, -#endif - .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; - -define_machine(p1020_rdb_pc) { - .name = "P1020RDB-PC", - .probe = p1020_rdb_pc_probe, - .setup_arch = mpc85xx_rdb_setup_arch, - .init_IRQ = mpc85xx_rdb_pic_init, -#ifdef CONFIG_PCI - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, -#endif - .get_irq = mpic_get_irq, - .restart = fsl_rstcr_restart, - .calibrate_decr = generic_calibrate_decr, - .progress = udbg_progress, -}; diff --git a/trunk/arch/powerpc/platforms/85xx/p1010rdb.c b/trunk/arch/powerpc/platforms/85xx/p1010rdb.c index d8bd6563d9ca..538bc3f57e9d 100644 --- a/trunk/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/trunk/arch/powerpc/platforms/85xx/p1010rdb.c @@ -32,8 +32,9 @@ void __init p1010_rdb_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | + MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); diff --git a/trunk/arch/powerpc/platforms/85xx/p1022_ds.c b/trunk/arch/powerpc/platforms/85xx/p1022_ds.c index 0fe88e39945e..b0984ada3f83 100644 --- a/trunk/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/trunk/arch/powerpc/platforms/85xx/p1022_ds.c @@ -33,10 +33,6 @@ #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) -#define PMUXCR_ELBCDIU_MASK 0xc0000000 -#define PMUXCR_ELBCDIU_NOR16 0x80000000 -#define PMUXCR_ELBCDIU_DIU 0x40000000 - /* * Board-specific initialization of the DIU. This code should probably be * executed when the DIU is opened, rather than in arch code, but the DIU @@ -54,22 +50,11 @@ #define CLKDVDR_PXCLK_MASK 0x00FF0000 /* Some ngPIXIS register definitions */ -#define PX_CTL 3 -#define PX_BRDCFG0 8 -#define PX_BRDCFG1 9 - -#define PX_BRDCFG0_ELBC_SPI_MASK 0xc0 -#define PX_BRDCFG0_ELBC_SPI_ELBC 0x00 -#define PX_BRDCFG0_ELBC_SPI_NULL 0xc0 -#define PX_BRDCFG0_ELBC_DIU 0x02 - #define PX_BRDCFG1_DVIEN 0x80 #define PX_BRDCFG1_DFPEN 0x40 #define PX_BRDCFG1_BACKLIGHT 0x20 #define PX_BRDCFG1_DDCEN 0x10 -#define PX_CTL_ALTACC 0x80 - /* * DIU Area Descriptor * @@ -148,117 +133,44 @@ static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port, */ static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) { - struct device_node *guts_node; - struct device_node *indirect_node = NULL; - struct ccsr_guts_85xx __iomem *guts; - u8 __iomem *lbc_lcs0_ba = NULL; - u8 __iomem *lbc_lcs1_ba = NULL; - u8 b; - - /* Map the global utilities registers. */ - guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); - if (!guts_node) { - pr_err("p1022ds: missing global utilties device node\n"); + struct device_node *np; + void __iomem *pixis; + u8 __iomem *brdcfg1; + + np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); + if (!np) + /* older device trees used "fsl,p1022ds-pixis" */ + np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis"); + if (!np) { + pr_err("p1022ds: missing ngPIXIS node\n"); return; } - guts = of_iomap(guts_node, 0); - if (!guts) { - pr_err("p1022ds: could not map global utilties device\n"); - goto exit; - } - - indirect_node = of_find_compatible_node(NULL, NULL, - "fsl,p1022ds-indirect-pixis"); - if (!indirect_node) { - pr_err("p1022ds: missing pixis indirect mode node\n"); - goto exit; - } - - lbc_lcs0_ba = of_iomap(indirect_node, 0); - if (!lbc_lcs0_ba) { - pr_err("p1022ds: could not map localbus chip select 0\n"); - goto exit; - } - - lbc_lcs1_ba = of_iomap(indirect_node, 1); - if (!lbc_lcs1_ba) { - pr_err("p1022ds: could not map localbus chip select 1\n"); - goto exit; - } - - /* Make sure we're in indirect mode first. */ - if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != - PMUXCR_ELBCDIU_DIU) { - struct device_node *pixis_node; - void __iomem *pixis; - - pixis_node = - of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); - if (!pixis_node) { - pr_err("p1022ds: missing pixis node\n"); - goto exit; - } - - pixis = of_iomap(pixis_node, 0); - of_node_put(pixis_node); - if (!pixis) { - pr_err("p1022ds: could not map pixis registers\n"); - goto exit; - } - - /* Enable indirect PIXIS mode. */ - setbits8(pixis + PX_CTL, PX_CTL_ALTACC); - iounmap(pixis); - - /* Switch the board mux to the DIU */ - out_8(lbc_lcs0_ba, PX_BRDCFG0); /* BRDCFG0 */ - b = in_8(lbc_lcs1_ba); - b |= PX_BRDCFG0_ELBC_DIU; - out_8(lbc_lcs1_ba, b); - - /* Set the chip mux to DIU mode. */ - clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK, - PMUXCR_ELBCDIU_DIU); - in_be32(&guts->pmuxcr); + pixis = of_iomap(np, 0); + if (!pixis) { + pr_err("p1022ds: could not map ngPIXIS registers\n"); + return; } - + brdcfg1 = pixis + 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */ switch (port) { case FSL_DIU_PORT_DVI: + printk(KERN_INFO "%s:%u\n", __func__, __LINE__); /* Enable the DVI port, disable the DFP and the backlight */ - out_8(lbc_lcs0_ba, PX_BRDCFG1); - b = in_8(lbc_lcs1_ba); - b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); - b |= PX_BRDCFG1_DVIEN; - out_8(lbc_lcs1_ba, b); + clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT, + PX_BRDCFG1_DVIEN); break; case FSL_DIU_PORT_LVDS: - /* - * LVDS also needs backlight enabled, otherwise the display - * will be blank. - */ + printk(KERN_INFO "%s:%u\n", __func__, __LINE__); /* Enable the DFP port, disable the DVI and the backlight */ - out_8(lbc_lcs0_ba, PX_BRDCFG1); - b = in_8(lbc_lcs1_ba); - b &= ~PX_BRDCFG1_DVIEN; - b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT; - out_8(lbc_lcs1_ba, b); + clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT, + PX_BRDCFG1_DFPEN); break; default: pr_err("p1022ds: unsupported monitor port %i\n", port); } -exit: - if (lbc_lcs1_ba) - iounmap(lbc_lcs1_ba); - if (lbc_lcs0_ba) - iounmap(lbc_lcs0_ba); - if (guts) - iounmap(guts); - - of_node_put(indirect_node); - of_node_put(guts_node); + iounmap(pixis); } /** @@ -330,56 +242,15 @@ p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) void __init p1022_ds_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); } -#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) - -/* - * Disables a node in the device tree. - * - * This function is called before kmalloc() is available, so the 'new' object - * should be allocated in the global area. The easiest way is to do that is - * to allocate one static local variable for each call to this function. - */ -static void __init disable_one_node(struct device_node *np, struct property *new) -{ - struct property *old; - - old = of_find_property(np, new->name, NULL); - if (old) - prom_update_property(np, new, old); - else - prom_add_property(np, new); -} - -/* TRUE if there is a "video=fslfb" command-line parameter. */ -static bool fslfb; - -/* - * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to - * true if we find it. - * - * We need to use early_param() instead of __setup() because the normal - * __setup() gets called to late. However, early_param() gets called very - * early, before the device tree is unflattened, so all we can do now is set a - * global variable. Later on, p1022_ds_setup_arch() will use that variable - * to determine if we need to update the device tree. - */ -static int __init early_video_setup(char *options) -{ - fslfb = (strncmp(options, "fslfb:", 6) == 0); - - return 0; -} -early_param("video", early_video_setup); - -#endif - /* * Setup the architecture */ @@ -417,34 +288,6 @@ static void __init p1022_ds_setup_arch(void) diu_ops.set_monitor_port = p1022ds_set_monitor_port; diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; - - /* - * Disable the NOR flash node if there is video=fslfb... command-line - * parameter. When the DIU is active, NOR flash is unavailable, so we - * have to disable the node before the MTD driver loads. - */ - if (fslfb) { - struct device_node *np = - of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); - - if (np) { - np = of_find_compatible_node(np, NULL, "cfi-flash"); - if (np) { - static struct property nor_status = { - .name = "status", - .value = "disabled", - .length = sizeof("disabled"), - }; - - pr_info("p1022ds: disabling %s node", - np->full_name); - disable_one_node(np, &nor_status); - of_node_put(np); - } - } - - } - #endif mpc85xx_smp_init(); diff --git a/trunk/arch/powerpc/platforms/85xx/p1023_rds.c b/trunk/arch/powerpc/platforms/85xx/p1023_rds.c index 6b07398e4369..d951e7027bb6 100644 --- a/trunk/arch/powerpc/platforms/85xx/p1023_rds.c +++ b/trunk/arch/powerpc/platforms/85xx/p1023_rds.c @@ -93,8 +93,9 @@ machine_device_initcall(p1023_rds, mpc85xx_common_publish_devices); static void __init mpc85xx_rds_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | + MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); diff --git a/trunk/arch/powerpc/platforms/85xx/sbc8548.c b/trunk/arch/powerpc/platforms/85xx/sbc8548.c index 1677b8a22677..184a50784617 100644 --- a/trunk/arch/powerpc/platforms/85xx/sbc8548.c +++ b/trunk/arch/powerpc/platforms/85xx/sbc8548.c @@ -54,7 +54,8 @@ static int sbc_rev; static void __init sbc8548_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/85xx/sbc8560.c b/trunk/arch/powerpc/platforms/85xx/sbc8560.c index 3c3bbcc27566..940752e93051 100644 --- a/trunk/arch/powerpc/platforms/85xx/sbc8560.c +++ b/trunk/arch/powerpc/platforms/85xx/sbc8560.c @@ -41,7 +41,8 @@ static void __init sbc8560_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/85xx/socrates.c b/trunk/arch/powerpc/platforms/85xx/socrates.c index b71919217756..18f635906b27 100644 --- a/trunk/arch/powerpc/platforms/85xx/socrates.c +++ b/trunk/arch/powerpc/platforms/85xx/socrates.c @@ -48,7 +48,8 @@ static void __init socrates_pic_init(void) { struct device_node *np; - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/85xx/stx_gp3.c b/trunk/arch/powerpc/platforms/85xx/stx_gp3.c index 27ca3a7b04ab..e9e5234b4e76 100644 --- a/trunk/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/trunk/arch/powerpc/platforms/85xx/stx_gp3.c @@ -48,7 +48,8 @@ static void __init stx_gp3_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/85xx/tqm85xx.c b/trunk/arch/powerpc/platforms/85xx/tqm85xx.c index d7504cefe016..bf7c89fb75bb 100644 --- a/trunk/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/trunk/arch/powerpc/platforms/85xx/tqm85xx.c @@ -47,7 +47,7 @@ static void __init tqm85xx_pic_init(void) { struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/trunk/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 503c21596c63..3a69f8b77de6 100644 --- a/trunk/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/trunk/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -43,7 +43,9 @@ void __init xes_mpc85xx_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | + MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/86xx/Kconfig b/trunk/arch/powerpc/platforms/86xx/Kconfig index 7a6279e38213..8d6599d54ea6 100644 --- a/trunk/arch/powerpc/platforms/86xx/Kconfig +++ b/trunk/arch/powerpc/platforms/86xx/Kconfig @@ -39,7 +39,6 @@ config GEF_PPC9A select MMIO_NVRAM select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB - select GE_FPGA help This option enables support for the GE PPC9A. @@ -49,7 +48,6 @@ config GEF_SBC310 select MMIO_NVRAM select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB - select GE_FPGA help This option enables support for the GE SBC310. @@ -59,7 +57,6 @@ config GEF_SBC610 select MMIO_NVRAM select GENERIC_GPIO select ARCH_REQUIRE_GPIOLIB - select GE_FPGA select HAS_RAPIDIO help This option enables support for the GE SBC610. diff --git a/trunk/arch/powerpc/platforms/86xx/Makefile b/trunk/arch/powerpc/platforms/86xx/Makefile index ede815d6489d..4b0d7b1aa005 100644 --- a/trunk/arch/powerpc/platforms/86xx/Makefile +++ b/trunk/arch/powerpc/platforms/86xx/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o obj-$(CONFIG_SBC8641D) += sbc8641d.o obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o -obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o -obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o -obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o +gef-gpio-$(CONFIG_GPIOLIB) += gef_gpio.o +obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o gef_pic.o $(gef-gpio-y) +obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o gef_pic.o $(gef-gpio-y) +obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o gef_pic.o $(gef-gpio-y) diff --git a/trunk/drivers/gpio/gpio-ge.c b/trunk/arch/powerpc/platforms/86xx/gef_gpio.c similarity index 83% rename from trunk/drivers/gpio/gpio-ge.c rename to trunk/arch/powerpc/platforms/86xx/gef_gpio.c index 7b95a4a8318c..2a703365e664 100644 --- a/trunk/drivers/gpio/gpio-ge.c +++ b/trunk/arch/powerpc/platforms/86xx/gef_gpio.c @@ -14,7 +14,7 @@ * * Configuration of output modes (totem-pole/open-drain) * Interrupt configuration - interrupts are always generated the FPGA relies on - * the I/O interrupt controllers mask to stop them propergating + * the I/O interrupt controllers mask to stop them propergating */ #include @@ -162,34 +162,6 @@ static int __init gef_gpio_init(void) } } - for_each_compatible_node(np, NULL, "ge,imp3a-gpio") { - - pr_debug("%s: Initialising GE GPIO\n", np->full_name); - - /* Allocate chip structure */ - gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); - if (!gef_gpio_chip) { - pr_err("%s: Unable to allocate structure\n", - np->full_name); - continue; - } - - /* Setup pointers to chip functions */ - gef_gpio_chip->gc.of_gpio_n_cells = 2; - gef_gpio_chip->gc.ngpio = 16; - gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; - gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; - gef_gpio_chip->gc.get = gef_gpio_get; - gef_gpio_chip->gc.set = gef_gpio_set; - - /* This function adds a memory mapped GPIO chip */ - retval = of_mm_gpiochip_add(np, gef_gpio_chip); - if (retval) { - kfree(gef_gpio_chip); - pr_err("%s: Unable to add GPIO\n", np->full_name); - } - } - return 0; }; arch_initcall(gef_gpio_init); diff --git a/trunk/arch/powerpc/sysdev/ge/ge_pic.c b/trunk/arch/powerpc/platforms/86xx/gef_pic.c similarity index 99% rename from trunk/arch/powerpc/sysdev/ge/ge_pic.c rename to trunk/arch/powerpc/platforms/86xx/gef_pic.c index 2bcb78bb3a15..af3fd697de82 100644 --- a/trunk/arch/powerpc/sysdev/ge/ge_pic.c +++ b/trunk/arch/powerpc/platforms/86xx/gef_pic.c @@ -22,7 +22,7 @@ #include #include -#include "ge_pic.h" +#include "gef_pic.h" #define DEBUG #undef DEBUG diff --git a/trunk/arch/powerpc/sysdev/ge/ge_pic.h b/trunk/arch/powerpc/platforms/86xx/gef_pic.h similarity index 100% rename from trunk/arch/powerpc/sysdev/ge/ge_pic.h rename to trunk/arch/powerpc/platforms/86xx/gef_pic.h diff --git a/trunk/arch/powerpc/platforms/86xx/gef_ppc9a.c b/trunk/arch/powerpc/platforms/86xx/gef_ppc9a.c index ed58b6cfd60c..60ce07e39100 100644 --- a/trunk/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/trunk/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -37,9 +37,9 @@ #include #include -#include #include "mpc86xx.h" +#include "gef_pic.h" #undef DEBUG diff --git a/trunk/arch/powerpc/platforms/86xx/gef_sbc310.c b/trunk/arch/powerpc/platforms/86xx/gef_sbc310.c index 710db69bd523..3ecee25bf3ed 100644 --- a/trunk/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/trunk/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -37,9 +37,9 @@ #include #include -#include #include "mpc86xx.h" +#include "gef_pic.h" #undef DEBUG diff --git a/trunk/arch/powerpc/platforms/86xx/gef_sbc610.c b/trunk/arch/powerpc/platforms/86xx/gef_sbc610.c index 4a13d2f4ac20..5090d608d9ee 100644 --- a/trunk/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/trunk/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -37,9 +37,9 @@ #include #include -#include #include "mpc86xx.h" +#include "gef_pic.h" #undef DEBUG diff --git a/trunk/arch/powerpc/platforms/86xx/pic.c b/trunk/arch/powerpc/platforms/86xx/pic.c index 22cc3571ae19..52bbfa031531 100644 --- a/trunk/arch/powerpc/platforms/86xx/pic.c +++ b/trunk/arch/powerpc/platforms/86xx/pic.c @@ -37,8 +37,9 @@ void __init mpc86xx_init_irq(void) int cascade_irq; #endif - struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | - MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, + MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | + MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, 0, 256, " MPIC "); BUG_ON(mpic == NULL); diff --git a/trunk/arch/powerpc/platforms/Kconfig b/trunk/arch/powerpc/platforms/Kconfig index a35ca44ade66..0cfb46d54b8c 100644 --- a/trunk/arch/powerpc/platforms/Kconfig +++ b/trunk/arch/powerpc/platforms/Kconfig @@ -2,6 +2,7 @@ menu "Platform support" source "arch/powerpc/platforms/powernv/Kconfig" source "arch/powerpc/platforms/pseries/Kconfig" +source "arch/powerpc/platforms/iseries/Kconfig" source "arch/powerpc/platforms/chrp/Kconfig" source "arch/powerpc/platforms/512x/Kconfig" source "arch/powerpc/platforms/52xx/Kconfig" @@ -86,14 +87,6 @@ config MPIC_WEIRD bool default n -config MPIC_MSGR - bool "MPIC message register support" - depends on MPIC - default n - help - Enables support for the MPIC message registers. These - registers are used for inter-processor communication. - config PPC_I8259 bool default n @@ -145,7 +138,7 @@ config MPIC_BROKEN_REGREAD of the register contents in software. config IBMVIO - depends on PPC_PSERIES + depends on PPC_PSERIES || PPC_ISERIES bool default y diff --git a/trunk/arch/powerpc/platforms/Makefile b/trunk/arch/powerpc/platforms/Makefile index 879b4a448498..2635a22bade2 100644 --- a/trunk/arch/powerpc/platforms/Makefile +++ b/trunk/arch/powerpc/platforms/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_FSL_SOC_BOOKE) += 85xx/ obj-$(CONFIG_PPC_86xx) += 86xx/ obj-$(CONFIG_PPC_POWERNV) += powernv/ obj-$(CONFIG_PPC_PSERIES) += pseries/ +obj-$(CONFIG_PPC_ISERIES) += iseries/ obj-$(CONFIG_PPC_MAPLE) += maple/ obj-$(CONFIG_PPC_PASEMI) += pasemi/ obj-$(CONFIG_PPC_CELL) += cell/ diff --git a/trunk/arch/powerpc/platforms/cell/setup.c b/trunk/arch/powerpc/platforms/cell/setup.c index fa3e294fd343..62002a7edfed 100644 --- a/trunk/arch/powerpc/platforms/cell/setup.c +++ b/trunk/arch/powerpc/platforms/cell/setup.c @@ -197,8 +197,7 @@ static void __init mpic_init_IRQ(void) /* The MPIC driver will get everything it needs from the * device-tree, just pass 0 to all arguments */ - mpic = mpic_alloc(dn, 0, MPIC_SECONDARY | MPIC_NO_RESET, - 0, 0, " MPIC "); + mpic = mpic_alloc(dn, 0, MPIC_SECONDARY, 0, 0, " MPIC "); if (mpic == NULL) continue; mpic_init(mpic); diff --git a/trunk/arch/powerpc/platforms/cell/spufs/inode.c b/trunk/arch/powerpc/platforms/cell/spufs/inode.c index 1d75c92ea8fb..d4a094ca96f3 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/inode.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/inode.c @@ -646,7 +646,6 @@ long spufs_create(struct path *path, struct dentry *dentry, out: mutex_unlock(&path->dentry->d_inode->i_mutex); - dput(dentry); return ret; } @@ -758,9 +757,9 @@ spufs_create_root(struct super_block *sb, void *data) goto out_iput; ret = -ENOMEM; - sb->s_root = d_make_root(inode); + sb->s_root = d_alloc_root(inode); if (!sb->s_root) - goto out; + goto out_iput; return 0; out_iput: @@ -829,19 +828,19 @@ static int __init spufs_init(void) ret = spu_sched_init(); if (ret) goto out_cache; - ret = register_spu_syscalls(&spufs_calls); + ret = register_filesystem(&spufs_type); if (ret) goto out_sched; - ret = register_filesystem(&spufs_type); + ret = register_spu_syscalls(&spufs_calls); if (ret) - goto out_syscalls; + goto out_fs; spufs_init_isolated_loader(); return 0; -out_syscalls: - unregister_spu_syscalls(&spufs_calls); +out_fs: + unregister_filesystem(&spufs_type); out_sched: spu_sched_exit(); out_cache: diff --git a/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c b/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c index 5665dcc382c7..8591bb62d7fc 100644 --- a/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/trunk/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -70,6 +70,8 @@ static long do_spu_create(const char __user *pathname, unsigned int flags, ret = PTR_ERR(dentry); if (!IS_ERR(dentry)) { ret = spufs_create(&path, dentry, flags, mode, neighbor); + mutex_unlock(&path.dentry->d_inode->i_mutex); + dput(dentry); path_put(&path); } diff --git a/trunk/arch/powerpc/platforms/chrp/setup.c b/trunk/arch/powerpc/platforms/chrp/setup.c index c665d7de6c99..f1f17bb2c33c 100644 --- a/trunk/arch/powerpc/platforms/chrp/setup.c +++ b/trunk/arch/powerpc/platforms/chrp/setup.c @@ -435,8 +435,7 @@ static void __init chrp_find_openpic(void) if (len > 1) isu_size = iranges[3]; - chrp_mpic = mpic_alloc(np, opaddr, MPIC_NO_RESET, - isu_size, 0, " MPIC "); + chrp_mpic = mpic_alloc(np, opaddr, 0, isu_size, 0, " MPIC "); if (chrp_mpic == NULL) { printk(KERN_ERR "Failed to allocate MPIC structure\n"); goto bail; diff --git a/trunk/arch/powerpc/platforms/embedded6xx/holly.c b/trunk/arch/powerpc/platforms/embedded6xx/holly.c index ab51b21b4bd7..9cfcf20c0560 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/holly.c +++ b/trunk/arch/powerpc/platforms/embedded6xx/holly.c @@ -154,9 +154,11 @@ static void __init holly_init_IRQ(void) struct device_node *cascade_node = NULL; #endif - mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + mpic = mpic_alloc(NULL, 0, + MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, - 24, 0, + 24, + NR_IRQS-4, /* num_sources used */ "Tsi108_PIC"); BUG_ON(mpic == NULL); diff --git a/trunk/arch/powerpc/platforms/embedded6xx/linkstation.c b/trunk/arch/powerpc/platforms/embedded6xx/linkstation.c index 455e7c087422..bcfad92c9cec 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/trunk/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -82,7 +82,8 @@ static void __init linkstation_init_IRQ(void) { struct mpic *mpic; - mpic = mpic_alloc(NULL, 0, 0, 4, 0, " EPIC "); + mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, + 4, 32, " EPIC "); BUG_ON(mpic == NULL); /* PCI IRQs */ diff --git a/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index 74ccce36baed..f3350d786f5b 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/trunk/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -108,9 +108,11 @@ static void __init mpc7448_hpc2_init_IRQ(void) struct device_node *cascade_node = NULL; #endif - mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + mpic = mpic_alloc(NULL, 0, + MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, - 24, 0, + 24, + NR_IRQS-4, /* num_sources used */ "Tsi108_PIC"); BUG_ON(mpic == NULL); diff --git a/trunk/arch/powerpc/platforms/embedded6xx/storcenter.c b/trunk/arch/powerpc/platforms/embedded6xx/storcenter.c index e0ed3c71d69b..afa638834965 100644 --- a/trunk/arch/powerpc/platforms/embedded6xx/storcenter.c +++ b/trunk/arch/powerpc/platforms/embedded6xx/storcenter.c @@ -84,7 +84,8 @@ static void __init storcenter_init_IRQ(void) { struct mpic *mpic; - mpic = mpic_alloc(NULL, 0, 0, 16, 0, " OpenPIC "); + mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, + 16, 32, " OpenPIC "); BUG_ON(mpic == NULL); /* diff --git a/trunk/arch/powerpc/platforms/iseries/Kconfig b/trunk/arch/powerpc/platforms/iseries/Kconfig new file mode 100644 index 000000000000..63835e09e5cc --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/Kconfig @@ -0,0 +1,39 @@ +config PPC_ISERIES + bool "IBM Legacy iSeries" + depends on PPC64 && PPC_BOOK3S + select OF_DYNAMIC + select PPC_SMP_MUXED_IPI + select PPC_INDIRECT_PIO + select PPC_INDIRECT_MMIO + select PPC_PCI_CHOICE if EXPERT + +menu "iSeries device drivers" + depends on PPC_ISERIES + +config VIODASD + tristate "iSeries Virtual I/O disk support" + depends on BLOCK + select VIOPATH + help + If you are running on an iSeries system and you want to use + virtual disks created and managed by OS/400, say Y. + +config VIOCD + tristate "iSeries Virtual I/O CD support" + depends on BLOCK + select VIOPATH + help + If you are running Linux on an IBM iSeries system and you want to + read a CD drive owned by OS/400, say Y here. + +config VIOTAPE + tristate "iSeries Virtual Tape Support" + select VIOPATH + help + If you are running Linux on an iSeries system and you want Linux + to read and/or write a tape drive owned by OS/400, say Y here. + +endmenu + +config VIOPATH + bool diff --git a/trunk/arch/powerpc/platforms/iseries/Makefile b/trunk/arch/powerpc/platforms/iseries/Makefile new file mode 100644 index 000000000000..a7602b11ed9d --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/Makefile @@ -0,0 +1,9 @@ +ccflags-y := -mno-minimal-toc + +obj-y += exception.o +obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \ + hvcall.o proc.o htab.o iommu.o misc.o irq.o +obj-$(CONFIG_PCI) += pci.o +obj-$(CONFIG_SMP) += smp.o +obj-$(CONFIG_VIOPATH) += viopath.o vio.o +obj-$(CONFIG_MODULES) += ksyms.o diff --git a/trunk/arch/powerpc/platforms/iseries/call_hpt.h b/trunk/arch/powerpc/platforms/iseries/call_hpt.h new file mode 100644 index 000000000000..8d95fe4b554e --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/call_hpt.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _PLATFORMS_ISERIES_CALL_HPT_H +#define _PLATFORMS_ISERIES_CALL_HPT_H + +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ + +#include +#include +#include + +#define HvCallHptGetHptAddress HvCallHpt + 0 +#define HvCallHptGetHptPages HvCallHpt + 1 +#define HvCallHptSetPp HvCallHpt + 5 +#define HvCallHptSetSwBits HvCallHpt + 6 +#define HvCallHptUpdate HvCallHpt + 7 +#define HvCallHptInvalidateNoSyncICache HvCallHpt + 8 +#define HvCallHptGet HvCallHpt + 11 +#define HvCallHptFindNextValid HvCallHpt + 12 +#define HvCallHptFindValid HvCallHpt + 13 +#define HvCallHptAddValidate HvCallHpt + 16 +#define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18 + + +static inline u64 HvCallHpt_getHptAddress(void) +{ + return HvCall0(HvCallHptGetHptAddress); +} + +static inline u64 HvCallHpt_getHptPages(void) +{ + return HvCall0(HvCallHptGetHptPages); +} + +static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value) +{ + HvCall2(HvCallHptSetPp, hpteIndex, value); +} + +static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff) +{ + HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff); +} + +static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex) +{ + HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); +} + +static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, + u8 bitsoff) +{ + u64 compressedStatus; + + compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet, + hpteIndex, bitson, bitsoff, 1); + HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); + return compressedStatus; +} + +static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn) +{ + return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0); +} + +static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex, + u8 bitson, u8 bitsoff) +{ + return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex, + bitson, bitsoff); +} + +static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex) +{ + HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); +} + +static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, + struct hash_pte *hpte) +{ + HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r); +} + +#endif /* _PLATFORMS_ISERIES_CALL_HPT_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/call_pci.h b/trunk/arch/powerpc/platforms/iseries/call_pci.h new file mode 100644 index 000000000000..dbdf69850ed9 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/call_pci.h @@ -0,0 +1,309 @@ +/* + * Provides the Hypervisor PCI calls for iSeries Linux Parition. + * Copyright (C) 2001 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * Change Activity: + * Created, Jan 9, 2001 + */ + +#ifndef _PLATFORMS_ISERIES_CALL_PCI_H +#define _PLATFORMS_ISERIES_CALL_PCI_H + +#include +#include + +/* + * DSA == Direct Select Address + * this struct must be 64 bits in total + */ +struct HvCallPci_DsaAddr { + u16 busNumber; /* PHB index? */ + u8 subBusNumber; /* PCI bus number? */ + u8 deviceId; /* device and function? */ + u8 barNumber; + u8 reserved[3]; +}; + +union HvDsaMap { + u64 DsaAddr; + struct HvCallPci_DsaAddr Dsa; +}; + +struct HvCallPci_LoadReturn { + u64 rc; + u64 value; +}; + +enum HvCallPci_DeviceType { + HvCallPci_NodeDevice = 1, + HvCallPci_SpDevice = 2, + HvCallPci_IopDevice = 3, + HvCallPci_BridgeDevice = 4, + HvCallPci_MultiFunctionDevice = 5, + HvCallPci_IoaDevice = 6 +}; + + +struct HvCallPci_DeviceInfo { + u32 deviceType; /* See DeviceType enum for values */ +}; + +struct HvCallPci_BusUnitInfo { + u32 sizeReturned; /* length of data returned */ + u32 deviceType; /* see DeviceType enum for values */ +}; + +struct HvCallPci_BridgeInfo { + struct HvCallPci_BusUnitInfo busUnitInfo; /* Generic bus unit info */ + u8 subBusNumber; /* Bus number of secondary bus */ + u8 maxAgents; /* Max idsels on secondary bus */ + u8 maxSubBusNumber; /* Max Sub Bus */ + u8 logicalSlotNumber; /* Logical Slot Number for IOA */ +}; + + +/* + * Maximum BusUnitInfo buffer size. Provided for clients so + * they can allocate a buffer big enough for any type of bus + * unit. Increase as needed. + */ +enum {HvCallPci_MaxBusUnitInfoSize = 128}; + +struct HvCallPci_BarParms { + u64 vaddr; + u64 raddr; + u64 size; + u64 protectStart; + u64 protectEnd; + u64 relocationOffset; + u64 pciAddress; + u64 reserved[3]; +}; + +enum HvCallPci_VpdType { + HvCallPci_BusVpd = 1, + HvCallPci_BusAdapterVpd = 2 +}; + +#define HvCallPciConfigLoad8 HvCallPci + 0 +#define HvCallPciConfigLoad16 HvCallPci + 1 +#define HvCallPciConfigLoad32 HvCallPci + 2 +#define HvCallPciConfigStore8 HvCallPci + 3 +#define HvCallPciConfigStore16 HvCallPci + 4 +#define HvCallPciConfigStore32 HvCallPci + 5 +#define HvCallPciEoi HvCallPci + 16 +#define HvCallPciGetBarParms HvCallPci + 18 +#define HvCallPciMaskFisr HvCallPci + 20 +#define HvCallPciUnmaskFisr HvCallPci + 21 +#define HvCallPciSetSlotReset HvCallPci + 25 +#define HvCallPciGetDeviceInfo HvCallPci + 27 +#define HvCallPciGetCardVpd HvCallPci + 28 +#define HvCallPciBarLoad8 HvCallPci + 40 +#define HvCallPciBarLoad16 HvCallPci + 41 +#define HvCallPciBarLoad32 HvCallPci + 42 +#define HvCallPciBarLoad64 HvCallPci + 43 +#define HvCallPciBarStore8 HvCallPci + 44 +#define HvCallPciBarStore16 HvCallPci + 45 +#define HvCallPciBarStore32 HvCallPci + 46 +#define HvCallPciBarStore64 HvCallPci + 47 +#define HvCallPciMaskInterrupts HvCallPci + 48 +#define HvCallPciUnmaskInterrupts HvCallPci + 49 +#define HvCallPciGetBusUnitInfo HvCallPci + 50 + +static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u16 *value) +{ + struct HvCallPci_DsaAddr dsa; + struct HvCallPci_LoadReturn retVal; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumber; + dsa.subBusNumber = subBusNumber; + dsa.deviceId = deviceId; + + HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0); + + *value = retVal.value; + + return retVal.rc; +} + +static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u32 *value) +{ + struct HvCallPci_DsaAddr dsa; + struct HvCallPci_LoadReturn retVal; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumber; + dsa.subBusNumber = subBusNumber; + dsa.deviceId = deviceId; + + HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0); + + *value = retVal.value; + + return retVal.rc; +} + +static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, + u8 deviceId, u32 offset, u8 value) +{ + struct HvCallPci_DsaAddr dsa; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumber; + dsa.subBusNumber = subBusNumber; + dsa.deviceId = deviceId; + + return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0); +} + +static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm) +{ + struct HvCallPci_DsaAddr dsa; + struct HvCallPci_LoadReturn retVal; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumberParm; + dsa.subBusNumber = subBusParm; + dsa.deviceId = deviceIdParm; + + HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa); + + return retVal.rc; +} + +static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms) +{ + struct HvCallPci_DsaAddr dsa; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumberParm; + dsa.subBusNumber = subBusParm; + dsa.deviceId = deviceIdParm; + dsa.barNumber = barNumberParm; + + return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms); +} + +static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 fisrMask) +{ + struct HvCallPci_DsaAddr dsa; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumberParm; + dsa.subBusNumber = subBusParm; + dsa.deviceId = deviceIdParm; + + return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask); +} + +static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 fisrMask) +{ + struct HvCallPci_DsaAddr dsa; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumberParm; + dsa.subBusNumber = subBusParm; + dsa.deviceId = deviceIdParm; + + return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask); +} + +static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm, + u8 deviceNumberParm, u64 parms, u32 sizeofParms) +{ + struct HvCallPci_DsaAddr dsa; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumberParm; + dsa.subBusNumber = subBusParm; + dsa.deviceId = deviceNumberParm << 4; + + return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms); +} + +static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 interruptMask) +{ + struct HvCallPci_DsaAddr dsa; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumberParm; + dsa.subBusNumber = subBusParm; + dsa.deviceId = deviceIdParm; + + return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask); +} + +static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 interruptMask) +{ + struct HvCallPci_DsaAddr dsa; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumberParm; + dsa.subBusNumber = subBusParm; + dsa.deviceId = deviceIdParm; + + return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask); +} + +static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm, + u8 deviceIdParm, u64 parms, u32 sizeofParms) +{ + struct HvCallPci_DsaAddr dsa; + + *((u64*)&dsa) = 0; + + dsa.busNumber = busNumberParm; + dsa.subBusNumber = subBusParm; + dsa.deviceId = deviceIdParm; + + return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms, + sizeofParms); +} + +static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, + u16 sizeParm) +{ + u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, + sizeParm, HvCallPci_BusVpd); + if (xRc == -1) + return -1; + else + return xRc & 0xFFFF; +} + +#endif /* _PLATFORMS_ISERIES_CALL_PCI_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/call_sm.h b/trunk/arch/powerpc/platforms/iseries/call_sm.h new file mode 100644 index 000000000000..c7e251619f48 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/call_sm.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ISERIES_CALL_SM_H +#define _ISERIES_CALL_SM_H + +/* + * This file contains the "hypervisor call" interface which is used to + * drive the hypervisor from the OS. + */ + +#include +#include + +#define HvCallSmGet64BitsOfAccessMap HvCallSm + 11 + +static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex, + u64 indexIntoBitMap) +{ + return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap); +} + +#endif /* _ISERIES_CALL_SM_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/dt.c b/trunk/arch/powerpc/platforms/iseries/dt.c new file mode 100644 index 000000000000..f0491cc28900 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/dt.c @@ -0,0 +1,643 @@ +/* + * Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation + * Copyright (C) 2000-2004, IBM Corporation + * + * Description: + * This file contains all the routines to build a flattened device + * tree for a legacy iSeries machine. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* ETH_ALEN */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "processor_vpd.h" +#include "call_hpt.h" +#include "call_pci.h" +#include "pci.h" +#include "it_exp_vpd_panel.h" +#include "naca.h" + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +/* + * These are created by the linker script at the start and end + * of the section containing all the strings marked with the DS macro. + */ +extern char __dt_strings_start[]; +extern char __dt_strings_end[]; + +#define DS(s) ({ \ + static const char __s[] __attribute__((section(".dt_strings"))) = s; \ + __s; \ +}) + +struct iseries_flat_dt { + struct boot_param_header header; + u64 reserve_map[2]; +}; + +static void * __initdata dt_data; + +/* + * Putting these strings here keeps them out of the .dt_strings section + * that we capture for the strings blob of the flattened device tree. + */ +static char __initdata device_type_cpu[] = "cpu"; +static char __initdata device_type_memory[] = "memory"; +static char __initdata device_type_serial[] = "serial"; +static char __initdata device_type_network[] = "network"; +static char __initdata device_type_pci[] = "pci"; +static char __initdata device_type_vdevice[] = "vdevice"; +static char __initdata device_type_vscsi[] = "vscsi"; + + +/* EBCDIC to ASCII conversion routines */ + +static unsigned char __init e2a(unsigned char x) +{ + switch (x) { + case 0x81 ... 0x89: + return x - 0x81 + 'a'; + case 0x91 ... 0x99: + return x - 0x91 + 'j'; + case 0xA2 ... 0xA9: + return x - 0xA2 + 's'; + case 0xC1 ... 0xC9: + return x - 0xC1 + 'A'; + case 0xD1 ... 0xD9: + return x - 0xD1 + 'J'; + case 0xE2 ... 0xE9: + return x - 0xE2 + 'S'; + case 0xF0 ... 0xF9: + return x - 0xF0 + '0'; + } + return ' '; +} + +static unsigned char * __init strne2a(unsigned char *dest, + const unsigned char *src, size_t n) +{ + int i; + + n = strnlen(src, n); + + for (i = 0; i < n; i++) + dest[i] = e2a(src[i]); + + return dest; +} + +static struct iseries_flat_dt * __init dt_init(void) +{ + struct iseries_flat_dt *dt; + unsigned long str_len; + + str_len = __dt_strings_end - __dt_strings_start; + dt = (struct iseries_flat_dt *)ALIGN(klimit, 8); + dt->header.off_mem_rsvmap = + offsetof(struct iseries_flat_dt, reserve_map); + dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8); + dt->header.off_dt_struct = dt->header.off_dt_strings + + ALIGN(str_len, 8); + dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct); + dt->header.dt_strings_size = str_len; + + /* There is no notion of hardware cpu id on iSeries */ + dt->header.boot_cpuid_phys = smp_processor_id(); + + memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start, + str_len); + + dt->header.magic = OF_DT_HEADER; + dt->header.version = 0x10; + dt->header.last_comp_version = 0x10; + + dt->reserve_map[0] = 0; + dt->reserve_map[1] = 0; + + return dt; +} + +static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value) +{ + *((u32 *)dt_data) = value; + dt_data += sizeof(u32); +} + +#ifdef notyet +static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value) +{ + *((u64 *)dt_data) = value; + dt_data += sizeof(u64); +} +#endif + +static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data, + int len) +{ + memcpy(dt_data, data, len); + dt_data += ALIGN(len, 4); +} + +static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name) +{ + dt_push_u32(dt, OF_DT_BEGIN_NODE); + dt_push_bytes(dt, name, strlen(name) + 1); +} + +#define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE) + +static void __init __dt_prop(struct iseries_flat_dt *dt, const char *name, + const void *data, int len) +{ + unsigned long offset; + + dt_push_u32(dt, OF_DT_PROP); + + /* Length of the data */ + dt_push_u32(dt, len); + + offset = name - __dt_strings_start; + + /* The offset of the properties name in the string blob. */ + dt_push_u32(dt, (u32)offset); + + /* The actual data. */ + dt_push_bytes(dt, data, len); +} +#define dt_prop(dt, name, data, len) __dt_prop((dt), DS(name), (data), (len)) + +#define dt_prop_str(dt, name, data) \ + dt_prop((dt), name, (data), strlen((data)) + 1); /* + 1 for NULL */ + +static void __init __dt_prop_u32(struct iseries_flat_dt *dt, const char *name, + u32 data) +{ + __dt_prop(dt, name, &data, sizeof(u32)); +} +#define dt_prop_u32(dt, name, data) __dt_prop_u32((dt), DS(name), (data)) + +static void __init __maybe_unused __dt_prop_u64(struct iseries_flat_dt *dt, + const char *name, u64 data) +{ + __dt_prop(dt, name, &data, sizeof(u64)); +} +#define dt_prop_u64(dt, name, data) __dt_prop_u64((dt), DS(name), (data)) + +#define dt_prop_u64_list(dt, name, data, n) \ + dt_prop((dt), name, (data), sizeof(u64) * (n)) + +#define dt_prop_u32_list(dt, name, data, n) \ + dt_prop((dt), name, (data), sizeof(u32) * (n)) + +#define dt_prop_empty(dt, name) dt_prop((dt), name, NULL, 0) + +static void __init dt_cpus(struct iseries_flat_dt *dt) +{ + unsigned char buf[32]; + unsigned char *p; + unsigned int i, index; + struct IoHriProcessorVpd *d; + u32 pft_size[2]; + + /* yuck */ + snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name); + p = strchr(buf, ' '); + if (!p) p = buf + strlen(buf); + + dt_start_node(dt, "cpus"); + dt_prop_u32(dt, "#address-cells", 1); + dt_prop_u32(dt, "#size-cells", 0); + + pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA */ + pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE); + + for (i = 0; i < NR_LPPACAS; i++) { + if (lppaca[i].dyn_proc_status >= 2) + continue; + + snprintf(p, 32 - (p - buf), "@%d", i); + dt_start_node(dt, buf); + + dt_prop_str(dt, "device_type", device_type_cpu); + + index = lppaca[i].dyn_hv_phys_proc_index; + d = &xIoHriProcessorVpd[index]; + + dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024); + dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize); + + dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024); + dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize); + + /* magic conversions to Hz copied from old code */ + dt_prop_u32(dt, "clock-frequency", + ((1UL << 34) * 1000000) / d->xProcFreq); + dt_prop_u32(dt, "timebase-frequency", + ((1UL << 32) * 1000000) / d->xTimeBaseFreq); + + dt_prop_u32(dt, "reg", i); + + dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2); + + dt_end_node(dt); + } + + dt_end_node(dt); +} + +static void __init dt_model(struct iseries_flat_dt *dt) +{ + char buf[16] = "IBM,"; + + /* N.B. lparcfg.c knows about the "IBM," prefixes ... */ + /* "IBM," + mfgId[2:3] + systemSerial[1:5] */ + strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2); + strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5); + buf[11] = '\0'; + dt_prop_str(dt, "system-id", buf); + + /* "IBM," + machineType[0:4] */ + strne2a(buf + 4, xItExtVpdPanel.machineType, 4); + buf[8] = '\0'; + dt_prop_str(dt, "model", buf); + + dt_prop_str(dt, "compatible", "IBM,iSeries"); + dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex()); +} + +static void __init dt_initrd(struct iseries_flat_dt *dt) +{ +#ifdef CONFIG_BLK_DEV_INITRD + if (naca.xRamDisk) { + dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk); + dt_prop_u64(dt, "linux,initrd-end", + (u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE); + } +#endif +} + +static void __init dt_do_vdevice(struct iseries_flat_dt *dt, + const char *name, u32 reg, int unit, + const char *type, const char *compat, int end) +{ + char buf[32]; + + snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0)); + dt_start_node(dt, buf); + dt_prop_str(dt, "device_type", type); + if (compat) + dt_prop_str(dt, "compatible", compat); + dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0)); + if (unit >= 0) + dt_prop_u32(dt, "linux,unit_address", unit); + if (end) + dt_end_node(dt); +} + +static void __init dt_vdevices(struct iseries_flat_dt *dt) +{ + u32 reg = 0; + HvLpIndexMap vlan_map; + int i; + + dt_start_node(dt, "vdevice"); + dt_prop_str(dt, "device_type", device_type_vdevice); + dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice"); + dt_prop_u32(dt, "#address-cells", 1); + dt_prop_u32(dt, "#size-cells", 0); + + dt_do_vdevice(dt, "vty", reg, -1, device_type_serial, + "IBM,iSeries-vty", 1); + reg++; + + dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi, + "IBM,v-scsi", 1); + reg++; + + vlan_map = HvLpConfig_getVirtualLanIndexMap(); + for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { + unsigned char mac_addr[ETH_ALEN]; + + if ((vlan_map & (0x8000 >> i)) == 0) + continue; + dt_do_vdevice(dt, "l-lan", reg, i, device_type_network, + "IBM,iSeries-l-lan", 0); + mac_addr[0] = 0x02; + mac_addr[1] = 0x01; + mac_addr[2] = 0xff; + mac_addr[3] = i; + mac_addr[4] = 0xff; + mac_addr[5] = HvLpConfig_getLpIndex_outline(); + dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN); + dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN); + dt_prop_u32(dt, "max-frame-size", 9000); + dt_prop_u32(dt, "address-bits", 48); + + dt_end_node(dt); + } + + dt_end_node(dt); +} + +struct pci_class_name { + u16 code; + const char *name; + const char *type; +}; + +static struct pci_class_name __initdata pci_class_name[] = { + { PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network }, +}; + +static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code) +{ + struct pci_class_name *cp; + + for (cp = pci_class_name; + cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++) + if (cp->code == class_code) + return cp; + return NULL; +} + +/* + * This assumes that the node slot is always on the primary bus! + */ +static void __init scan_bridge_slot(struct iseries_flat_dt *dt, + HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info) +{ + HvSubBusNumber sub_bus = bridge_info->subBusNumber; + u16 vendor_id; + u16 device_id; + u32 class_id; + int err; + char buf[32]; + u32 reg[5]; + int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus); + int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus); + HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function); + u8 devfn; + struct pci_class_name *cp; + + /* + * Connect all functions of any device found. + */ + for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) { + for (function = 0; function < 8; function++) { + HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel, + function); + err = HvCallXm_connectBusUnit(bus, sub_bus, + agent_id, 0); + if (err) { + if (err != 0x302) + DBG("connectBusUnit(%x, %x, %x) %x\n", + bus, sub_bus, agent_id, err); + continue; + } + + err = HvCallPci_configLoad16(bus, sub_bus, agent_id, + PCI_VENDOR_ID, &vendor_id); + if (err) { + DBG("ReadVendor(%x, %x, %x) %x\n", + bus, sub_bus, agent_id, err); + continue; + } + err = HvCallPci_configLoad16(bus, sub_bus, agent_id, + PCI_DEVICE_ID, &device_id); + if (err) { + DBG("ReadDevice(%x, %x, %x) %x\n", + bus, sub_bus, agent_id, err); + continue; + } + err = HvCallPci_configLoad32(bus, sub_bus, agent_id, + PCI_CLASS_REVISION , &class_id); + if (err) { + DBG("ReadClass(%x, %x, %x) %x\n", + bus, sub_bus, agent_id, err); + continue; + } + + devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel), + function); + cp = dt_find_pci_class_name(class_id >> 16); + if (cp && cp->name) + strncpy(buf, cp->name, sizeof(buf) - 1); + else + snprintf(buf, sizeof(buf), "pci%x,%x", + vendor_id, device_id); + buf[sizeof(buf) - 1] = '\0'; + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + "@%x", PCI_SLOT(devfn)); + buf[sizeof(buf) - 1] = '\0'; + if (function != 0) + snprintf(buf + strlen(buf), + sizeof(buf) - strlen(buf), + ",%x", function); + dt_start_node(dt, buf); + reg[0] = (bus << 16) | (devfn << 8); + reg[1] = 0; + reg[2] = 0; + reg[3] = 0; + reg[4] = 0; + dt_prop_u32_list(dt, "reg", reg, 5); + if (cp && (cp->type || cp->name)) + dt_prop_str(dt, "device_type", + cp->type ? cp->type : cp->name); + dt_prop_u32(dt, "vendor-id", vendor_id); + dt_prop_u32(dt, "device-id", device_id); + dt_prop_u32(dt, "class-code", class_id >> 8); + dt_prop_u32(dt, "revision-id", class_id & 0xff); + dt_prop_u32(dt, "linux,subbus", sub_bus); + dt_prop_u32(dt, "linux,agent-id", agent_id); + dt_prop_u32(dt, "linux,logical-slot-number", + bridge_info->logicalSlotNumber); + dt_end_node(dt); + + } + } +} + +static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus, + HvSubBusNumber sub_bus, int id_sel) +{ + struct HvCallPci_BridgeInfo bridge_info; + HvAgentId agent_id; + int function; + int ret; + + /* Note: hvSubBus and irq is always be 0 at this level! */ + for (function = 0; function < 8; ++function) { + agent_id = ISERIES_PCI_AGENTID(id_sel, function); + ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0); + if (ret != 0) { + if (ret != 0xb) + DBG("connectBusUnit(%x, %x, %x) %x\n", + bus, sub_bus, agent_id, ret); + continue; + } + DBG("found device at bus %d idsel %d func %d (AgentId %x)\n", + bus, id_sel, function, agent_id); + ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id, + iseries_hv_addr(&bridge_info), + sizeof(struct HvCallPci_BridgeInfo)); + if (ret != 0) + continue; + DBG("bridge info: type %x subbus %x " + "maxAgents %x maxsubbus %x logslot %x\n", + bridge_info.busUnitInfo.deviceType, + bridge_info.subBusNumber, + bridge_info.maxAgents, + bridge_info.maxSubBusNumber, + bridge_info.logicalSlotNumber); + if (bridge_info.busUnitInfo.deviceType == + HvCallPci_BridgeDevice) + scan_bridge_slot(dt, bus, &bridge_info); + else + DBG("PCI: Invalid Bridge Configuration(0x%02X)", + bridge_info.busUnitInfo.deviceType); + } +} + +static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus) +{ + struct HvCallPci_DeviceInfo dev_info; + const HvSubBusNumber sub_bus = 0; /* EADs is always 0. */ + int err; + int id_sel; + const int max_agents = 8; + + /* + * Probe for EADs Bridges + */ + for (id_sel = 1; id_sel < max_agents; ++id_sel) { + err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel, + iseries_hv_addr(&dev_info), + sizeof(struct HvCallPci_DeviceInfo)); + if (err) { + if (err != 0x302) + DBG("getDeviceInfo(%x, %x, %x) %x\n", + bus, sub_bus, id_sel, err); + continue; + } + if (dev_info.deviceType != HvCallPci_NodeDevice) { + DBG("PCI: Invalid System Configuration" + "(0x%02X) for bus 0x%02x id 0x%02x.\n", + dev_info.deviceType, bus, id_sel); + continue; + } + scan_bridge(dt, bus, sub_bus, id_sel); + } +} + +static void __init dt_pci_devices(struct iseries_flat_dt *dt) +{ + HvBusNumber bus; + char buf[32]; + u32 buses[2]; + int phb_num = 0; + + /* Check all possible buses. */ + for (bus = 0; bus < 256; bus++) { + int err = HvCallXm_testBus(bus); + + if (err) { + /* + * Check for Unexpected Return code, a clue that + * something has gone wrong. + */ + if (err != 0x0301) + DBG("Unexpected Return on Probe(0x%02X) " + "0x%04X\n", bus, err); + continue; + } + DBG("bus %d appears to exist\n", bus); + snprintf(buf, 32, "pci@%d", phb_num); + dt_start_node(dt, buf); + dt_prop_str(dt, "device_type", device_type_pci); + dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB"); + dt_prop_u32(dt, "#address-cells", 3); + dt_prop_u32(dt, "#size-cells", 2); + buses[0] = buses[1] = bus; + dt_prop_u32_list(dt, "bus-range", buses, 2); + scan_phb(dt, bus); + dt_end_node(dt); + phb_num++; + } +} + +static void dt_finish(struct iseries_flat_dt *dt) +{ + dt_push_u32(dt, OF_DT_END); + dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt; + klimit = ALIGN((unsigned long)dt_data, 8); +} + +void * __init build_flat_dt(unsigned long phys_mem_size) +{ + struct iseries_flat_dt *iseries_dt; + u64 tmp[2]; + + iseries_dt = dt_init(); + + dt_start_node(iseries_dt, ""); + + dt_prop_u32(iseries_dt, "#address-cells", 2); + dt_prop_u32(iseries_dt, "#size-cells", 2); + dt_model(iseries_dt); + + /* /memory */ + dt_start_node(iseries_dt, "memory@0"); + dt_prop_str(iseries_dt, "device_type", device_type_memory); + tmp[0] = 0; + tmp[1] = phys_mem_size; + dt_prop_u64_list(iseries_dt, "reg", tmp, 2); + dt_end_node(iseries_dt); + + /* /chosen */ + dt_start_node(iseries_dt, "chosen"); + dt_prop_str(iseries_dt, "bootargs", cmd_line); + dt_initrd(iseries_dt); + dt_end_node(iseries_dt); + + dt_cpus(iseries_dt); + + dt_vdevices(iseries_dt); + dt_pci_devices(iseries_dt); + + dt_end_node(iseries_dt); + + dt_finish(iseries_dt); + + return iseries_dt; +} diff --git a/trunk/arch/powerpc/platforms/iseries/exception.S b/trunk/arch/powerpc/platforms/iseries/exception.S new file mode 100644 index 000000000000..f519ee17ff7d --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/exception.S @@ -0,0 +1,311 @@ +/* + * Low level routines for legacy iSeries support. + * + * Extracted from head_64.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com + * + * This file contains the low-level support and setup for the + * PowerPC-64 platform, including trap and interrupt dispatch. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "exception.h" + + .text + + .globl system_reset_iSeries +system_reset_iSeries: + bl .relative_toc + mfspr r13,SPRN_SPRG3 /* Get alpaca address */ + LOAD_REG_ADDR(r23, alpaca) + li r0,ALPACA_SIZE + sub r23,r13,r23 + divdu r24,r23,r0 /* r24 has cpu number */ + cmpwi 0,r24,0 /* Are we processor 0? */ + bne 1f + LOAD_REG_ADDR(r13, boot_paca) + mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */ + mfmsr r23 + ori r23,r23,MSR_RI + mtmsrd r23 /* RI on */ + b .__start_initialization_iSeries /* Start up the first processor */ +1: mfspr r4,SPRN_CTRLF + li r5,CTRL_RUNLATCH /* Turn off the run light */ + andc r4,r4,r5 + mtspr SPRN_CTRLT,r4 + +/* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */ +/* In the UP case we'll yield() later, and we will not access the paca anyway */ +#ifdef CONFIG_SMP +iSeries_secondary_wait_paca: + HMT_LOW + LOAD_REG_ADDR(r23, __secondary_hold_spinloop) + ld r23,0(r23) + + cmpdi 0,r23,0 + bne 2f /* go on when the master is ready */ + + /* Keep poking the Hypervisor until we're released */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + b iSeries_secondary_wait_paca + +2: + HMT_MEDIUM + sync + + LOAD_REG_ADDR(r3, nr_cpu_ids) /* get number of pacas allocated */ + lwz r3,0(r3) /* nr_cpus= or NR_CPUS can limit */ + cmpld 0,r24,r3 /* is our cpu number allocated? */ + bge iSeries_secondary_yield /* no, yield forever */ + + /* Load our paca now that it's been allocated */ + LOAD_REG_ADDR(r13, paca) + ld r13,0(r13) + mulli r0,r24,PACA_SIZE + add r13,r13,r0 + mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */ + mfmsr r23 + ori r23,r23,MSR_RI + mtmsrd r23 /* RI on */ + +iSeries_secondary_smp_loop: + lbz r23,PACAPROCSTART(r13) /* Test if this processor + * should start */ + cmpwi 0,r23,0 + bne 3f /* go on when we are told */ + + HMT_LOW + /* Let the Hypervisor know we are alive */ + /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ + lis r3,0x8002 + rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ + b iSeries_secondary_smp_loop /* wait for signal to start */ + +3: + HMT_MEDIUM + sync + LOAD_REG_ADDR(r3,current_set) + sldi r28,r24,3 /* get current_set[cpu#] */ + ldx r3,r3,r28 + addi r1,r3,THREAD_SIZE + subi r1,r1,STACK_FRAME_OVERHEAD + + b __secondary_start /* Loop until told to go */ +#endif /* CONFIG_SMP */ + +iSeries_secondary_yield: + /* Yield the processor. This is required for non-SMP kernels + which are running on multi-threaded machines. */ + HMT_LOW + lis r3,0x8000 + rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ + addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ + li r4,0 /* "yield timed" */ + li r5,-1 /* "yield forever" */ + li r0,-1 /* r0=-1 indicates a Hypervisor call */ + sc /* Invoke the hypervisor via a system call */ + mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ + b iSeries_secondary_yield /* If SMP not configured, secondaries + * loop forever */ + +/*** ISeries-LPAR interrupt handlers ***/ + + STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC) + + .globl data_access_iSeries +data_access_iSeries: + mtspr SPRN_SPRG_SCRATCH0,r13 +BEGIN_FTR_SECTION + mfspr r13,SPRN_SPRG_PACA + std r9,PACA_EXSLB+EX_R9(r13) + std r10,PACA_EXSLB+EX_R10(r13) + mfspr r10,SPRN_DAR + mfspr r9,SPRN_DSISR + srdi r10,r10,60 + rlwimi r10,r9,16,0x20 + mfcr r9 + cmpwi r10,0x2c + beq .do_stab_bolted_iSeries + ld r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXGEN+EX_R11(r13) + ld r11,PACA_EXSLB+EX_R9(r13) + std r12,PACA_EXGEN+EX_R12(r13) + mfspr r12,SPRN_SPRG_SCRATCH0 + std r10,PACA_EXGEN+EX_R10(r13) + std r11,PACA_EXGEN+EX_R9(r13) + std r12,PACA_EXGEN+EX_R13(r13) + EXCEPTION_PROLOG_ISERIES_1 +FTR_SECTION_ELSE + EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0) + EXCEPTION_PROLOG_ISERIES_1 +ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) + b data_access_common + +.do_stab_bolted_iSeries: + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + mfspr r10,SPRN_SPRG_SCRATCH0 + std r10,PACA_EXSLB+EX_R13(r13) + EXCEPTION_PROLOG_ISERIES_1 + b .do_stab_bolted + + .globl data_access_slb_iSeries +data_access_slb_iSeries: + mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ + mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ + std r3,PACA_EXSLB+EX_R3(r13) + mfspr r3,SPRN_DAR + std r9,PACA_EXSLB+EX_R9(r13) + mfcr r9 +#ifdef __DISABLED__ + cmpdi r3,0 + bge slb_miss_user_iseries +#endif + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + mfspr r10,SPRN_SPRG_SCRATCH0 + std r10,PACA_EXSLB+EX_R13(r13) + ld r12,PACALPPACAPTR(r13) + ld r12,LPPACASRR1(r12) + b .slb_miss_realmode + + STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN) + + .globl instruction_access_slb_iSeries +instruction_access_slb_iSeries: + mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ + mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ + std r3,PACA_EXSLB+EX_R3(r13) + ld r3,PACALPPACAPTR(r13) + ld r3,LPPACASRR0(r3) /* get SRR0 value */ + std r9,PACA_EXSLB+EX_R9(r13) + mfcr r9 +#ifdef __DISABLED__ + cmpdi r3,0 + bge slb_miss_user_iseries +#endif + std r10,PACA_EXSLB+EX_R10(r13) + std r11,PACA_EXSLB+EX_R11(r13) + std r12,PACA_EXSLB+EX_R12(r13) + mfspr r10,SPRN_SPRG_SCRATCH0 + std r10,PACA_EXSLB+EX_R13(r13) + ld r12,PACALPPACAPTR(r13) + ld r12,LPPACASRR1(r12) + b .slb_miss_realmode + +#ifdef __DISABLED__ +slb_miss_user_iseries: + std r10,PACA_EXGEN+EX_R10(r13) + std r11,PACA_EXGEN+EX_R11(r13) + std r12,PACA_EXGEN+EX_R12(r13) + mfspr r10,SPRG_SCRATCH0 + ld r11,PACA_EXSLB+EX_R9(r13) + ld r12,PACA_EXSLB+EX_R3(r13) + std r10,PACA_EXGEN+EX_R13(r13) + std r11,PACA_EXGEN+EX_R9(r13) + std r12,PACA_EXGEN+EX_R3(r13) + EXCEPTION_PROLOG_ISERIES_1 + b slb_miss_user_common +#endif + + MASKABLE_EXCEPTION_ISERIES(hardware_interrupt) + STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN) + STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN) + STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN) + MASKABLE_EXCEPTION_ISERIES(decrementer) + STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN) + STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN) + + .globl system_call_iSeries +system_call_iSeries: + mr r9,r13 + mfspr r13,SPRN_SPRG_PACA + EXCEPTION_PROLOG_ISERIES_1 + b system_call_common + + STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN) + STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN) + STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN) + +decrementer_iSeries_masked: + /* We may not have a valid TOC pointer in here. */ + li r11,1 + ld r12,PACALPPACAPTR(r13) + stb r11,LPPACADECRINT(r12) + li r12,-1 + clrldi r12,r12,33 /* set DEC to 0x7fffffff */ + mtspr SPRN_DEC,r12 + /* fall through */ + +hardware_interrupt_iSeries_masked: + mtcrf 0x80,r9 /* Restore regs */ + ld r12,PACALPPACAPTR(r13) + ld r11,LPPACASRR0(r12) + ld r12,LPPACASRR1(r12) + mtspr SPRN_SRR0,r11 + mtspr SPRN_SRR1,r12 + ld r9,PACA_EXGEN+EX_R9(r13) + ld r10,PACA_EXGEN+EX_R10(r13) + ld r11,PACA_EXGEN+EX_R11(r13) + ld r12,PACA_EXGEN+EX_R12(r13) + ld r13,PACA_EXGEN+EX_R13(r13) + rfid + b . /* prevent speculative execution */ + +_INIT_STATIC(__start_initialization_iSeries) + /* Clear out the BSS */ + LOAD_REG_ADDR(r11,__bss_stop) + LOAD_REG_ADDR(r8,__bss_start) + sub r11,r11,r8 /* bss size */ + addi r11,r11,7 /* round up to an even double word */ + rldicl. r11,r11,61,3 /* shift right by 3 */ + beq 4f + addi r8,r8,-8 + li r0,0 + mtctr r11 /* zero this many doublewords */ +3: stdu r0,8(r8) + bdnz 3b +4: + LOAD_REG_ADDR(r1,init_thread_union) + addi r1,r1,THREAD_SIZE + li r0,0 + stdu r0,-STACK_FRAME_OVERHEAD(r1) + + bl .iSeries_early_setup + bl .early_setup + + /* relocation is on at this point */ + + b .start_here_common diff --git a/trunk/arch/powerpc/platforms/iseries/exception.h b/trunk/arch/powerpc/platforms/iseries/exception.h new file mode 100644 index 000000000000..50271b550a99 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/exception.h @@ -0,0 +1,58 @@ +#ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H +#define _ASM_POWERPC_ISERIES_EXCEPTION_H +/* + * Extracted from head_64.S + * + * PowerPC version + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP + * Copyright (C) 1996 Cort Dougan + * Adapted for Power Macintosh by Paul Mackerras. + * Low-level exception handlers and MMU support + * rewritten by Paul Mackerras. + * Copyright (C) 1996 Paul Mackerras. + * + * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com + * + * This file contains the low-level support and setup for the + * PowerPC-64 platform, including trap and interrupt dispatch. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include + +#define EXCEPTION_PROLOG_ISERIES_1 \ + mfmsr r10; \ + ld r12,PACALPPACAPTR(r13); \ + ld r11,LPPACASRR0(r12); \ + ld r12,LPPACASRR1(r12); \ + ori r10,r10,MSR_RI; \ + mtmsrd r10,1 + +#define STD_EXCEPTION_ISERIES(label, area) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ + EXCEPTION_PROLOG_1(area, NOTEST, 0); \ + EXCEPTION_PROLOG_ISERIES_1; \ + b label##_common + +#define MASKABLE_EXCEPTION_ISERIES(label) \ + .globl label##_iSeries; \ +label##_iSeries: \ + HMT_MEDIUM; \ + mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ + EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0); \ + lbz r10,PACASOFTIRQEN(r13); \ + cmpwi 0,r10,0; \ + beq- label##_iSeries_masked; \ + EXCEPTION_PROLOG_ISERIES_1; \ + b label##_common; \ + +#endif /* _ASM_POWERPC_ISERIES_EXCEPTION_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/htab.c b/trunk/arch/powerpc/platforms/iseries/htab.c new file mode 100644 index 000000000000..3ae66ab9d5e7 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/htab.c @@ -0,0 +1,257 @@ +/* + * iSeries hashtable management. + * Derived from pSeries_htab.c + * + * SMP scalability work: + * Copyright (C) 2001 Anton Blanchard , IBM + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include + +#include "call_hpt.h" + +static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp; + +/* + * Very primitive algorithm for picking up a lock + */ +static inline void iSeries_hlock(unsigned long slot) +{ + if (slot & 0x8) + slot = ~slot; + spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]); +} + +static inline void iSeries_hunlock(unsigned long slot) +{ + if (slot & 0x8) + slot = ~slot; + spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]); +} + +static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, + unsigned long pa, unsigned long rflags, + unsigned long vflags, int psize, int ssize) +{ + long slot; + struct hash_pte lhpte; + int secondary = 0; + + BUG_ON(psize != MMU_PAGE_4K); + + /* + * The hypervisor tries both primary and secondary. + * If we are being called to insert in the secondary, + * it means we have already tried both primary and secondary, + * so we return failure immediately. + */ + if (vflags & HPTE_V_SECONDARY) + return -1; + + iSeries_hlock(hpte_group); + + slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT); + if (unlikely(lhpte.v & HPTE_V_VALID)) { + if (vflags & HPTE_V_BOLTED) { + HvCallHpt_setSwBits(slot, 0x10, 0); + HvCallHpt_setPp(slot, PP_RWXX); + iSeries_hunlock(hpte_group); + if (slot < 0) + return 0x8 | (slot & 7); + else + return slot & 7; + } + BUG(); + } + + if (slot == -1) { /* No available entry found in either group */ + iSeries_hunlock(hpte_group); + return -1; + } + + if (slot < 0) { /* MSB set means secondary group */ + vflags |= HPTE_V_SECONDARY; + secondary = 1; + slot &= 0x7fffffffffffffff; + } + + + lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) | + vflags | HPTE_V_VALID; + lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags; + + /* Now fill in the actual HPTE */ + HvCallHpt_addValidate(slot, secondary, &lhpte); + + iSeries_hunlock(hpte_group); + + return (secondary << 3) | (slot & 7); +} + +static unsigned long iSeries_hpte_getword0(unsigned long slot) +{ + struct hash_pte hpte; + + HvCallHpt_get(&hpte, slot); + return hpte.v; +} + +static long iSeries_hpte_remove(unsigned long hpte_group) +{ + unsigned long slot_offset; + int i; + unsigned long hpte_v; + + /* Pick a random slot to start at */ + slot_offset = mftb() & 0x7; + + iSeries_hlock(hpte_group); + + for (i = 0; i < HPTES_PER_GROUP; i++) { + hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset); + + if (! (hpte_v & HPTE_V_BOLTED)) { + HvCallHpt_invalidateSetSwBitsGet(hpte_group + + slot_offset, 0, 0); + iSeries_hunlock(hpte_group); + return i; + } + + slot_offset++; + slot_offset &= 0x7; + } + + iSeries_hunlock(hpte_group); + + return -1; +} + +/* + * The HyperVisor expects the "flags" argument in this form: + * bits 0..59 : reserved + * bit 60 : N + * bits 61..63 : PP2,PP1,PP0 + */ +static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, + unsigned long va, int psize, int ssize, int local) +{ + struct hash_pte hpte; + unsigned long want_v; + + iSeries_hlock(slot); + + HvCallHpt_get(&hpte, slot); + want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M); + + if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) { + /* + * Hypervisor expects bits as NPPP, which is + * different from how they are mapped in our PP. + */ + HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1)); + iSeries_hunlock(slot); + return 0; + } + iSeries_hunlock(slot); + + return -1; +} + +/* + * Functions used to find the PTE for a particular virtual address. + * Only used during boot when bolting pages. + * + * Input : vpn : virtual page number + * Output: PTE index within the page table of the entry + * -1 on failure + */ +static long iSeries_hpte_find(unsigned long vpn) +{ + struct hash_pte hpte; + long slot; + + /* + * The HvCallHpt_findValid interface is as follows: + * 0xffffffffffffffff : No entry found. + * 0x00000000xxxxxxxx : Entry found in primary group, slot x + * 0x80000000xxxxxxxx : Entry found in secondary group, slot x + */ + slot = HvCallHpt_findValid(&hpte, vpn); + if (hpte.v & HPTE_V_VALID) { + if (slot < 0) { + slot &= 0x7fffffffffffffff; + slot = -slot; + } + } else + slot = -1; + return slot; +} + +/* + * Update the page protection bits. Intended to be used to create + * guard pages for kernel data structures on pages which are bolted + * in the HPT. Assumes pages being operated on will not be stolen. + * Does not work on large pages. + * + * No need to lock here because we should be the only user. + */ +static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, + int psize, int ssize) +{ + unsigned long vsid,va,vpn; + long slot; + + BUG_ON(psize != MMU_PAGE_4K); + + vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); + va = (vsid << 28) | (ea & 0x0fffffff); + vpn = va >> HW_PAGE_SHIFT; + slot = iSeries_hpte_find(vpn); + if (slot == -1) + panic("updateboltedpp: Could not find page to bolt\n"); + HvCallHpt_setPp(slot, newpp); +} + +static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, + int psize, int ssize, int local) +{ + unsigned long hpte_v; + unsigned long avpn = va >> 23; + unsigned long flags; + + local_irq_save(flags); + + iSeries_hlock(slot); + + hpte_v = iSeries_hpte_getword0(slot); + + if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID)) + HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0); + + iSeries_hunlock(slot); + + local_irq_restore(flags); +} + +void __init hpte_init_iSeries(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++) + spin_lock_init(&iSeries_hlocks[i]); + + ppc_md.hpte_invalidate = iSeries_hpte_invalidate; + ppc_md.hpte_updatepp = iSeries_hpte_updatepp; + ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; + ppc_md.hpte_insert = iSeries_hpte_insert; + ppc_md.hpte_remove = iSeries_hpte_remove; +} diff --git a/trunk/arch/powerpc/platforms/iseries/hvcall.S b/trunk/arch/powerpc/platforms/iseries/hvcall.S new file mode 100644 index 000000000000..07ae6ad5f49f --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/hvcall.S @@ -0,0 +1,94 @@ +/* + * This file contains the code to perform calls to the + * iSeries LPAR hypervisor + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include /* XXX for STACK_FRAME_OVERHEAD */ + + .text + +/* + * Hypervisor call + * + * Invoke the iSeries hypervisor via the System Call instruction + * Parameters are passed to this routine in registers r3 - r10 + * + * r3 contains the HV function to be called + * r4-r10 contain the operands to the hypervisor function + * + */ + +_GLOBAL(HvCall) +_GLOBAL(HvCall0) +_GLOBAL(HvCall1) +_GLOBAL(HvCall2) +_GLOBAL(HvCall3) +_GLOBAL(HvCall4) +_GLOBAL(HvCall5) +_GLOBAL(HvCall6) +_GLOBAL(HvCall7) + + + mfcr r0 + std r0,-8(r1) + stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1) + + /* r0 = 0xffffffffffffffff indicates a hypervisor call */ + + li r0,-1 + + /* Invoke the hypervisor */ + + sc + + ld r1,0(r1) + ld r0,-8(r1) + mtcrf 0xff,r0 + + /* return to caller, return value in r3 */ + + blr + +_GLOBAL(HvCall0Ret16) +_GLOBAL(HvCall1Ret16) +_GLOBAL(HvCall2Ret16) +_GLOBAL(HvCall3Ret16) +_GLOBAL(HvCall4Ret16) +_GLOBAL(HvCall5Ret16) +_GLOBAL(HvCall6Ret16) +_GLOBAL(HvCall7Ret16) + + mfcr r0 + std r0,-8(r1) + std r31,-16(r1) + stdu r1,-(STACK_FRAME_OVERHEAD+32)(r1) + + mr r31,r4 + li r0,-1 + mr r4,r5 + mr r5,r6 + mr r6,r7 + mr r7,r8 + mr r8,r9 + mr r9,r10 + + sc + + std r3,0(r31) + std r4,8(r31) + + mr r3,r5 + + ld r1,0(r1) + ld r0,-8(r1) + mtcrf 0xff,r0 + ld r31,-16(r1) + + blr diff --git a/trunk/arch/powerpc/platforms/iseries/hvlog.c b/trunk/arch/powerpc/platforms/iseries/hvlog.c new file mode 100644 index 000000000000..f476d71194fa --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/hvlog.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include + + +void HvCall_writeLogBuffer(const void *buffer, u64 len) +{ + struct HvLpBufferList hv_buf; + u64 left_this_page; + u64 cur = virt_to_abs(buffer); + + while (len) { + hv_buf.addr = cur; + left_this_page = ((cur & HW_PAGE_MASK) + HW_PAGE_SIZE) - cur; + if (left_this_page > len) + left_this_page = len; + hv_buf.len = left_this_page; + len -= left_this_page; + HvCall2(HvCallBaseWriteLogBuffer, + virt_to_abs(&hv_buf), + left_this_page); + cur = (cur & HW_PAGE_MASK) + HW_PAGE_SIZE; + } +} diff --git a/trunk/arch/powerpc/platforms/iseries/hvlpconfig.c b/trunk/arch/powerpc/platforms/iseries/hvlpconfig.c new file mode 100644 index 000000000000..f62a0c5fa670 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/hvlpconfig.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2001 Kyle A. Lucke, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include "it_lp_naca.h" + +HvLpIndex HvLpConfig_getLpIndex_outline(void) +{ + return HvLpConfig_getLpIndex(); +} +EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline); + +HvLpIndex HvLpConfig_getLpIndex(void) +{ + return itLpNaca.xLpIndex; +} +EXPORT_SYMBOL(HvLpConfig_getLpIndex); + +HvLpIndex HvLpConfig_getPrimaryLpIndex(void) +{ + return itLpNaca.xPrimaryLpIndex; +} +EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex); diff --git a/trunk/arch/powerpc/platforms/iseries/iommu.c b/trunk/arch/powerpc/platforms/iseries/iommu.c new file mode 100644 index 000000000000..2f3d9110248c --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/iommu.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation + * + * Rewrite, cleanup: + * + * Copyright (C) 2004 Olof Johansson , IBM Corporation + * Copyright (C) 2006 Olof Johansson + * + * Dynamic DMA mapping support, iSeries-specific parts. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int tce_build_iSeries(struct iommu_table *tbl, long index, long npages, + unsigned long uaddr, enum dma_data_direction direction, + struct dma_attrs *attrs) +{ + u64 rc; + u64 tce, rpn; + + while (npages--) { + rpn = virt_to_abs(uaddr) >> TCE_SHIFT; + tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; + + if (tbl->it_type == TCE_VB) { + /* Virtual Bus */ + tce |= TCE_VALID|TCE_ALLIO; + if (direction != DMA_TO_DEVICE) + tce |= TCE_VB_WRITE; + } else { + /* PCI Bus */ + tce |= TCE_PCI_READ; /* Read allowed */ + if (direction != DMA_TO_DEVICE) + tce |= TCE_PCI_WRITE; + } + + rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce); + if (rc) + panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n", + rc); + index++; + uaddr += TCE_PAGE_SIZE; + } + return 0; +} + +static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages) +{ + u64 rc; + + while (npages--) { + rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0); + if (rc) + panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n", + rc); + index++; + } +} + +/* + * Structure passed to HvCallXm_getTceTableParms + */ +struct iommu_table_cb { + unsigned long itc_busno; /* Bus number for this tce table */ + unsigned long itc_start; /* Will be NULL for secondary */ + unsigned long itc_totalsize; /* Size (in pages) of whole table */ + unsigned long itc_offset; /* Index into real tce table of the + start of our section */ + unsigned long itc_size; /* Size (in pages) of our section */ + unsigned long itc_index; /* Index of this tce table */ + unsigned short itc_maxtables; /* Max num of tables for partition */ + unsigned char itc_virtbus; /* Flag to indicate virtual bus */ + unsigned char itc_slotno; /* IOA Tce Slot Index */ + unsigned char itc_rsvd[4]; +}; + +/* + * Call Hv with the architected data structure to get TCE table info. + * info. Put the returned data into the Linux representation of the + * TCE table data. + * The Hardware Tce table comes in three flavors. + * 1. TCE table shared between Buses. + * 2. TCE table per Bus. + * 3. TCE Table per IOA. + */ +void iommu_table_getparms_iSeries(unsigned long busno, + unsigned char slotno, + unsigned char virtbus, + struct iommu_table* tbl) +{ + struct iommu_table_cb *parms; + + parms = kzalloc(sizeof(*parms), GFP_KERNEL); + if (parms == NULL) + panic("PCI_DMA: TCE Table Allocation failed."); + + parms->itc_busno = busno; + parms->itc_slotno = slotno; + parms->itc_virtbus = virtbus; + + HvCallXm_getTceTableParms(iseries_hv_addr(parms)); + + if (parms->itc_size == 0) + panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms); + + /* itc_size is in pages worth of table, it_size is in # of entries */ + tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE; + tbl->it_busno = parms->itc_busno; + tbl->it_offset = parms->itc_offset; + tbl->it_index = parms->itc_index; + tbl->it_blocksize = 1; + tbl->it_type = virtbus ? TCE_VB : TCE_PCI; + + kfree(parms); +} + + +#ifdef CONFIG_PCI +/* + * This function compares the known tables to find an iommu_table + * that has already been built for hardware TCEs. + */ +static struct iommu_table *iommu_table_find(struct iommu_table * tbl) +{ + struct device_node *node; + + for (node = NULL; (node = of_find_all_nodes(node)); ) { + struct pci_dn *pdn = PCI_DN(node); + struct iommu_table *it; + + if (pdn == NULL) + continue; + it = pdn->iommu_table; + if ((it != NULL) && + (it->it_type == TCE_PCI) && + (it->it_offset == tbl->it_offset) && + (it->it_index == tbl->it_index) && + (it->it_size == tbl->it_size)) { + of_node_put(node); + return it; + } + } + return NULL; +} + + +static void pci_dma_dev_setup_iseries(struct pci_dev *pdev) +{ + struct iommu_table *tbl; + struct device_node *dn = pci_device_to_OF_node(pdev); + struct pci_dn *pdn = PCI_DN(dn); + const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL); + + BUG_ON(lsn == NULL); + + tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL); + + iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl); + + /* Look for existing tce table */ + pdn->iommu_table = iommu_table_find(tbl); + if (pdn->iommu_table == NULL) + pdn->iommu_table = iommu_init_table(tbl, -1); + else + kfree(tbl); + set_iommu_table_base(&pdev->dev, pdn->iommu_table); +} +#else +#define pci_dma_dev_setup_iseries NULL +#endif + +static struct iommu_table veth_iommu_table; +static struct iommu_table vio_iommu_table; + +void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag) +{ + return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle, + DMA_BIT_MASK(32), flag, -1); +} +EXPORT_SYMBOL_GPL(iseries_hv_alloc); + +void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle) +{ + iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle); +} +EXPORT_SYMBOL_GPL(iseries_hv_free); + +dma_addr_t iseries_hv_map(void *vaddr, size_t size, + enum dma_data_direction direction) +{ + return iommu_map_page(NULL, &vio_iommu_table, virt_to_page(vaddr), + (unsigned long)vaddr % PAGE_SIZE, size, + DMA_BIT_MASK(32), direction, NULL); +} + +void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) +{ + iommu_unmap_page(&vio_iommu_table, dma_handle, size, direction, NULL); +} + +void __init iommu_vio_init(void) +{ + iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table); + veth_iommu_table.it_size /= 2; + vio_iommu_table = veth_iommu_table; + vio_iommu_table.it_offset += veth_iommu_table.it_size; + + if (!iommu_init_table(&veth_iommu_table, -1)) + printk("Virtual Bus VETH TCE table failed.\n"); + if (!iommu_init_table(&vio_iommu_table, -1)) + printk("Virtual Bus VIO TCE table failed.\n"); +} + +struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev) +{ + if (strcmp(dev->type, "network") == 0) + return &veth_iommu_table; + return &vio_iommu_table; +} + +void iommu_init_early_iSeries(void) +{ + ppc_md.tce_build = tce_build_iSeries; + ppc_md.tce_free = tce_free_iSeries; + + ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_iseries; + set_pci_dma_ops(&dma_iommu_ops); +} diff --git a/trunk/arch/powerpc/platforms/iseries/ipl_parms.h b/trunk/arch/powerpc/platforms/iseries/ipl_parms.h new file mode 100644 index 000000000000..83e4ca42fc57 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/ipl_parms.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ISERIES_IPL_PARMS_H +#define _ISERIES_IPL_PARMS_H + +/* + * This struct maps the IPL Parameters DMA'd from the SP. + * + * Warning: + * This data must map in exactly 64 bytes and match the architecture for + * the IPL parms + */ + +#include + +struct ItIplParmsReal { + u8 xFormat; // Defines format of IplParms x00-x00 + u8 xRsvd01:6; // Reserved x01-x01 + u8 xAlternateSearch:1; // Alternate search indicator ... + u8 xUaSupplied:1; // UA Supplied on programmed IPL... + u8 xLsUaFormat; // Format byte for UA x02-x02 + u8 xRsvd02; // Reserved x03-x03 + u32 xLsUa; // LS UA x04-x07 + u32 xUnusedLsLid; // First OS LID to load x08-x0B + u16 xLsBusNumber; // LS Bus Number x0C-x0D + u8 xLsCardAdr; // LS Card Address x0E-x0E + u8 xLsBoardAdr; // LS Board Address x0F-x0F + u32 xRsvd03; // Reserved x10-x13 + u8 xSpcnPresent:1; // SPCN present x14-x14 + u8 xCpmPresent:1; // CPM present ... + u8 xRsvd04:6; // Reserved ... + u8 xRsvd05:4; // Reserved x15-x15 + u8 xKeyLock:4; // Keylock setting ... + u8 xRsvd06:6; // Reserved x16-x16 + u8 xIplMode:2; // Ipl mode (A|B|C|D) ... + u8 xHwIplType; // Fast v slow v slow EC HW IPL x17-x17 + u16 xCpmEnabledIpl:1; // CPM in effect when IPL initiatedx18-x19 + u16 xPowerOnResetIpl:1; // Indicate POR condition ... + u16 xMainStorePreserved:1; // Main Storage is preserved ... + u16 xRsvd07:13; // Reserved ... + u16 xIplSource:16; // Ipl source x1A-x1B + u8 xIplReason:8; // Reason for this IPL x1C-x1C + u8 xRsvd08; // Reserved x1D-x1D + u16 xRsvd09; // Reserved x1E-x1F + u16 xSysBoxType; // System Box Type x20-x21 + u16 xSysProcType; // System Processor Type x22-x23 + u32 xRsvd10; // Reserved x24-x27 + u64 xRsvd11; // Reserved x28-x2F + u64 xRsvd12; // Reserved x30-x37 + u64 xRsvd13; // Reserved x38-x3F +}; + +#endif /* _ISERIES_IPL_PARMS_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/irq.c b/trunk/arch/powerpc/platforms/iseries/irq.c new file mode 100644 index 000000000000..05ce5164cafc --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/irq.c @@ -0,0 +1,399 @@ +/* + * This module supports the iSeries PCI bus interrupt handling + * Copyright (C) 20yy + * Copyright (C) 2004-2005 IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * Change Activity: + * Created, December 13, 2000 by Wayne Holm + * End Change Activity + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "irq.h" +#include "pci.h" +#include "call_pci.h" + +#ifdef CONFIG_PCI + +enum pci_event_type { + pe_bus_created = 0, /* PHB has been created */ + pe_bus_error = 1, /* PHB has failed */ + pe_bus_failed = 2, /* Msg to Secondary, Primary failed bus */ + pe_node_failed = 4, /* Multi-adapter bridge has failed */ + pe_node_recovered = 5, /* Multi-adapter bridge has recovered */ + pe_bus_recovered = 12, /* PHB has been recovered */ + pe_unquiese_bus = 18, /* Secondary bus unqiescing */ + pe_bridge_error = 21, /* Bridge Error */ + pe_slot_interrupt = 22 /* Slot interrupt */ +}; + +struct pci_event { + struct HvLpEvent event; + union { + u64 __align; /* Align on an 8-byte boundary */ + struct { + u32 fisr; + HvBusNumber bus_number; + HvSubBusNumber sub_bus_number; + HvAgentId dev_id; + } slot; + struct { + HvBusNumber bus_number; + HvSubBusNumber sub_bus_number; + } bus; + struct { + HvBusNumber bus_number; + HvSubBusNumber sub_bus_number; + HvAgentId dev_id; + } node; + } data; +}; + +static DEFINE_SPINLOCK(pending_irqs_lock); +static int num_pending_irqs; +static int pending_irqs[NR_IRQS]; + +static void int_received(struct pci_event *event) +{ + int irq; + + switch (event->event.xSubtype) { + case pe_slot_interrupt: + irq = event->event.xCorrelationToken; + if (irq < NR_IRQS) { + spin_lock(&pending_irqs_lock); + pending_irqs[irq]++; + num_pending_irqs++; + spin_unlock(&pending_irqs_lock); + } else { + printk(KERN_WARNING "int_received: bad irq number %d\n", + irq); + HvCallPci_eoi(event->data.slot.bus_number, + event->data.slot.sub_bus_number, + event->data.slot.dev_id); + } + break; + /* Ignore error recovery events for now */ + case pe_bus_created: + printk(KERN_INFO "int_received: system bus %d created\n", + event->data.bus.bus_number); + break; + case pe_bus_error: + case pe_bus_failed: + printk(KERN_INFO "int_received: system bus %d failed\n", + event->data.bus.bus_number); + break; + case pe_bus_recovered: + case pe_unquiese_bus: + printk(KERN_INFO "int_received: system bus %d recovered\n", + event->data.bus.bus_number); + break; + case pe_node_failed: + case pe_bridge_error: + printk(KERN_INFO + "int_received: multi-adapter bridge %d/%d/%d failed\n", + event->data.node.bus_number, + event->data.node.sub_bus_number, + event->data.node.dev_id); + break; + case pe_node_recovered: + printk(KERN_INFO + "int_received: multi-adapter bridge %d/%d/%d recovered\n", + event->data.node.bus_number, + event->data.node.sub_bus_number, + event->data.node.dev_id); + break; + default: + printk(KERN_ERR + "int_received: unrecognized event subtype 0x%x\n", + event->event.xSubtype); + break; + } +} + +static void pci_event_handler(struct HvLpEvent *event) +{ + if (event && (event->xType == HvLpEvent_Type_PciIo)) { + if (hvlpevent_is_int(event)) + int_received((struct pci_event *)event); + else + printk(KERN_ERR + "pci_event_handler: unexpected ack received\n"); + } else if (event) + printk(KERN_ERR + "pci_event_handler: Unrecognized PCI event type 0x%x\n", + (int)event->xType); + else + printk(KERN_ERR "pci_event_handler: NULL event received\n"); +} + +#define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff) +#define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) +#define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) +#define REAL_IRQ_TO_FUNC(irq) ((irq) & 7) + +/* + * This will be called by device drivers (via enable_IRQ) + * to enable INTA in the bridge interrupt status register. + */ +static void iseries_enable_IRQ(struct irq_data *d) +{ + u32 bus, dev_id, function, mask; + const u32 sub_bus = 0; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); + + /* The IRQ has already been locked by the caller */ + bus = REAL_IRQ_TO_BUS(rirq); + function = REAL_IRQ_TO_FUNC(rirq); + dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; + + /* Unmask secondary INTA */ + mask = 0x80000000; + HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask); +} + +/* This is called by iseries_activate_IRQs */ +static unsigned int iseries_startup_IRQ(struct irq_data *d) +{ + u32 bus, dev_id, function, mask; + const u32 sub_bus = 0; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); + + bus = REAL_IRQ_TO_BUS(rirq); + function = REAL_IRQ_TO_FUNC(rirq); + dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; + + /* Link the IRQ number to the bridge */ + HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq); + + /* Unmask bridge interrupts in the FISR */ + mask = 0x01010000 << function; + HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask); + iseries_enable_IRQ(d); + return 0; +} + +/* + * This is called out of iSeries_fixup to activate interrupt + * generation for usable slots + */ +void __init iSeries_activate_IRQs() +{ + int irq; + unsigned long flags; + + for_each_irq (irq) { + struct irq_desc *desc = irq_to_desc(irq); + struct irq_chip *chip; + + if (!desc) + continue; + + chip = irq_desc_get_chip(desc); + if (chip && chip->irq_startup) { + raw_spin_lock_irqsave(&desc->lock, flags); + chip->irq_startup(&desc->irq_data); + raw_spin_unlock_irqrestore(&desc->lock, flags); + } + } +} + +/* this is not called anywhere currently */ +static void iseries_shutdown_IRQ(struct irq_data *d) +{ + u32 bus, dev_id, function, mask; + const u32 sub_bus = 0; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); + + /* irq should be locked by the caller */ + bus = REAL_IRQ_TO_BUS(rirq); + function = REAL_IRQ_TO_FUNC(rirq); + dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; + + /* Invalidate the IRQ number in the bridge */ + HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0); + + /* Mask bridge interrupts in the FISR */ + mask = 0x01010000 << function; + HvCallPci_maskFisr(bus, sub_bus, dev_id, mask); +} + +/* + * This will be called by device drivers (via disable_IRQ) + * to disable INTA in the bridge interrupt status register. + */ +static void iseries_disable_IRQ(struct irq_data *d) +{ + u32 bus, dev_id, function, mask; + const u32 sub_bus = 0; + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); + + /* The IRQ has already been locked by the caller */ + bus = REAL_IRQ_TO_BUS(rirq); + function = REAL_IRQ_TO_FUNC(rirq); + dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; + + /* Mask secondary INTA */ + mask = 0x80000000; + HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask); +} + +static void iseries_end_IRQ(struct irq_data *d) +{ + unsigned int rirq = (unsigned int)irqd_to_hwirq(d); + + HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), + (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); +} + +static struct irq_chip iseries_pic = { + .name = "iSeries", + .irq_startup = iseries_startup_IRQ, + .irq_shutdown = iseries_shutdown_IRQ, + .irq_unmask = iseries_enable_IRQ, + .irq_mask = iseries_disable_IRQ, + .irq_eoi = iseries_end_IRQ +}; + +/* + * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot + * It calculates the irq value for the slot. + * Note that sub_bus is always 0 (at the moment at least). + */ +int __init iSeries_allocate_IRQ(HvBusNumber bus, + HvSubBusNumber sub_bus, u32 bsubbus) +{ + unsigned int realirq; + u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus); + u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus); + + realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) + + function; + + return irq_create_mapping(NULL, realirq); +} + +#endif /* CONFIG_PCI */ + +/* + * Get the next pending IRQ. + */ +unsigned int iSeries_get_irq(void) +{ + int irq = NO_IRQ_IGNORE; + +#ifdef CONFIG_SMP + if (get_lppaca()->int_dword.fields.ipi_cnt) { + get_lppaca()->int_dword.fields.ipi_cnt = 0; + smp_ipi_demux(); + } +#endif /* CONFIG_SMP */ + if (hvlpevent_is_pending()) + process_hvlpevents(); + +#ifdef CONFIG_PCI + if (num_pending_irqs) { + spin_lock(&pending_irqs_lock); + for (irq = 0; irq < NR_IRQS; irq++) { + if (pending_irqs[irq]) { + pending_irqs[irq]--; + num_pending_irqs--; + break; + } + } + spin_unlock(&pending_irqs_lock); + if (irq >= NR_IRQS) + irq = NO_IRQ_IGNORE; + } +#endif + + return irq; +} + +#ifdef CONFIG_PCI + +static int iseries_irq_host_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq); + + return 0; +} + +static int iseries_irq_host_match(struct irq_domain *h, struct device_node *np) +{ + /* Match all */ + return 1; +} + +static const struct irq_domain_ops iseries_irq_domain_ops = { + .map = iseries_irq_host_map, + .match = iseries_irq_host_match, +}; + +/* + * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c + * It must be called before the bus walk. + */ +void __init iSeries_init_IRQ(void) +{ + /* Register PCI event handler and open an event path */ + struct irq_domain *host; + int ret; + + /* + * The Hypervisor only allows us up to 256 interrupt + * sources (the irq number is passed in a u8). + */ + irq_set_virq_count(256); + + /* Create irq host. No need for a revmap since HV will give us + * back our virtual irq number + */ + host = irq_domain_add_nomap(NULL, &iseries_irq_domain_ops, NULL); + BUG_ON(host == NULL); + irq_set_default_host(host); + + ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, + &pci_event_handler); + if (ret == 0) { + ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); + if (ret != 0) + printk(KERN_ERR "iseries_init_IRQ: open event path " + "failed with rc 0x%x\n", ret); + } else + printk(KERN_ERR "iseries_init_IRQ: register handler " + "failed with rc 0x%x\n", ret); +} + +#endif /* CONFIG_PCI */ diff --git a/trunk/arch/powerpc/platforms/iseries/irq.h b/trunk/arch/powerpc/platforms/iseries/irq.h new file mode 100644 index 000000000000..a1c236074034 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/irq.h @@ -0,0 +1,13 @@ +#ifndef _ISERIES_IRQ_H +#define _ISERIES_IRQ_H + +#ifdef CONFIG_PCI +extern void iSeries_init_IRQ(void); +extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32); +extern void iSeries_activate_IRQs(void); +#else +#define iSeries_init_IRQ NULL +#endif +extern unsigned int iSeries_get_irq(void); + +#endif /* _ISERIES_IRQ_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h b/trunk/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h new file mode 100644 index 000000000000..6de9097b7f57 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2002 Dave Boutcher IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H +#define _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H + +/* + * This struct maps the panel information + * + * Warning: + * This data must match the architecture for the panel information + */ + +#include + +struct ItExtVpdPanel { + /* Definition of the Extended Vpd On Panel Data Area */ + char systemSerial[8]; + char mfgID[4]; + char reserved1[24]; + char machineType[4]; + char systemID[6]; + char somUniqueCnt[4]; + char serialNumberCount; + char reserved2[7]; + u16 bbu3; + u16 bbu2; + u16 bbu1; + char xLocationLabel[8]; + u8 xRsvd1[6]; + u16 xFrameId; + u8 xRsvd2[48]; +}; + +extern struct ItExtVpdPanel xItExtVpdPanel; + +#endif /* _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/it_lp_naca.h b/trunk/arch/powerpc/platforms/iseries/it_lp_naca.h new file mode 100644 index 000000000000..cf6dcf6ef07b --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/it_lp_naca.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _PLATFORMS_ISERIES_IT_LP_NACA_H +#define _PLATFORMS_ISERIES_IT_LP_NACA_H + +#include + +/* + * This control block contains the data that is shared between the + * hypervisor (PLIC) and the OS. + */ + +struct ItLpNaca { +// CACHE_LINE_1 0x0000 - 0x007F Contains read-only data + u32 xDesc; // Eye catcher x00-x03 + u16 xSize; // Size of this class x04-x05 + u16 xIntHdlrOffset; // Offset to IntHdlr array x06-x07 + u8 xMaxIntHdlrEntries; // Number of entries in array x08-x08 + u8 xPrimaryLpIndex; // LP Index of Primary x09-x09 + u8 xServiceLpIndex; // LP Ind of Service Focal Pointx0A-x0A + u8 xLpIndex; // LP Index x0B-x0B + u16 xMaxLpQueues; // Number of allocated queues x0C-x0D + u16 xLpQueueOffset; // Offset to start of LP queues x0E-x0F + u8 xPirEnvironMode; // Piranha or hardware x10-x10 + u8 xPirConsoleMode; // Piranha console indicator x11-x11 + u8 xPirDasdMode; // Piranha dasd indicator x12-x12 + u8 xRsvd1_0[5]; // Reserved for Piranha related x13-x17 + u8 flags; // flags, see below x18-x1F + u8 xSpVpdFormat; // VPD areas are in CSP format ... + u8 xIntProcRatio; // Ratio of int procs to procs ... + u8 xRsvd1_2[5]; // Reserved ... + u16 xRsvd1_3; // Reserved x20-x21 + u16 xPlicVrmIndex; // VRM index of PLIC x22-x23 + u16 xMinSupportedSlicVrmInd;// Min supported OS VRM index x24-x25 + u16 xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x27 + u64 xLoadAreaAddr; // ER address of load area x28-x2F + u32 xLoadAreaChunks; // Chunks for the load area x30-x33 + u32 xPaseSysCallCRMask; // Mask used to test CR before x34-x37 + // doing an ASR switch on PASE + // system call. + u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f + u8 xRsvd1_4[64]; // x40-x7F + +// CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data + u8 xRsvd2_0[128]; // Reserved x00-x7F + +// CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators +// NB: Padding required to keep xInterruptHdlr at x300 which is required +// for v4r4 PLIC. + u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F + u8 xRsvd3_0[384]; // Reserved 180-2FF + +// CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt +// handlers + u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF +}; + +extern struct ItLpNaca itLpNaca; + +#define ITLPNACA_LPAR 0x80 /* Is LPAR installed on the system */ +#define ITLPNACA_PARTITIONED 0x40 /* Is the system partitioned */ +#define ITLPNACA_HWSYNCEDTBS 0x20 /* Hardware synced TBs */ +#define ITLPNACA_HMTINT 0x10 /* Utilize MHT for interrupts */ + +#endif /* _PLATFORMS_ISERIES_IT_LP_NACA_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/ksyms.c b/trunk/arch/powerpc/platforms/iseries/ksyms.c new file mode 100644 index 000000000000..997e234fb8b7 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/ksyms.c @@ -0,0 +1,21 @@ +/* + * (C) 2001-2005 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include + +#include +#include + +EXPORT_SYMBOL(HvCall0); +EXPORT_SYMBOL(HvCall1); +EXPORT_SYMBOL(HvCall2); +EXPORT_SYMBOL(HvCall3); +EXPORT_SYMBOL(HvCall4); +EXPORT_SYMBOL(HvCall5); +EXPORT_SYMBOL(HvCall6); +EXPORT_SYMBOL(HvCall7); diff --git a/trunk/arch/powerpc/platforms/iseries/lpardata.c b/trunk/arch/powerpc/platforms/iseries/lpardata.c new file mode 100644 index 000000000000..00e0ec813a1c --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/lpardata.c @@ -0,0 +1,318 @@ +/* + * Copyright 2001 Mike Corrigan, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "naca.h" +#include "vpd_areas.h" +#include "spcomm_area.h" +#include "ipl_parms.h" +#include "processor_vpd.h" +#include "release_data.h" +#include "it_exp_vpd_panel.h" +#include "it_lp_naca.h" + +/* The HvReleaseData is the root of the information shared between + * the hypervisor and Linux. + */ +const struct HvReleaseData hvReleaseData = { + .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */ + .xSize = sizeof(struct HvReleaseData), + .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas), + .xSlicNacaAddr = &naca, /* 64-bit Naca address */ + .xMsNucDataOffset = LPARMAP_PHYS, + .xFlags = HVREL_TAGSINACTIVE /* tags inactive */ + /* 64 bit */ + /* shared processors */ + /* HMT allowed */ + | 6, /* TEMP: This allows non-GA driver */ + .xVrmIndex = 4, /* We are v5r2m0 */ + .xMinSupportedPlicVrmIndex = 3, /* v5r1m0 */ + .xMinCompatablePlicVrmIndex = 3, /* v5r1m0 */ + .xVrmName = { 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4.64" ebcdic */ + 0xa7, 0x40, 0xf2, 0x4b, + 0xf4, 0x4b, 0xf6, 0xf4 }, +}; + +/* + * The NACA. The first dword of the naca is required by the iSeries + * hypervisor to point to itVpdAreas. The hypervisor finds the NACA + * through the pointer in hvReleaseData. + */ +struct naca_struct naca = { + .xItVpdAreas = &itVpdAreas, + .xRamDisk = 0, + .xRamDiskSize = 0, +}; + +struct ItLpRegSave { + u32 xDesc; // Eye catcher "LpRS" ebcdic 000-003 + u16 xSize; // Size of this class 004-005 + u8 xInUse; // Area is live 006-007 + u8 xRsvd1[9]; // Reserved 007-00F + + u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F + u32 xCTRL; // Control Register 170-173 + u32 xDEC; // Decrementer 174-177 + u32 xFPSCR; // FP Status and Control Reg 178-17B + u32 xPVR; // Processor Version Number 17C-17F + + u64 xMMCR0; // Monitor Mode Control Reg 0 180-187 + u32 xPMC1; // Perf Monitor Counter 1 188-18B + u32 xPMC2; // Perf Monitor Counter 2 18C-18F + u32 xPMC3; // Perf Monitor Counter 3 190-193 + u32 xPMC4; // Perf Monitor Counter 4 194-197 + u32 xPIR; // Processor ID Reg 198-19B + + u32 xMMCR1; // Monitor Mode Control Reg 1 19C-19F + u32 xMMCRA; // Monitor Mode Control Reg A 1A0-1A3 + u32 xPMC5; // Perf Monitor Counter 5 1A4-1A7 + u32 xPMC6; // Perf Monitor Counter 6 1A8-1AB + u32 xPMC7; // Perf Monitor Counter 7 1AC-1AF + u32 xPMC8; // Perf Monitor Counter 8 1B0-1B3 + u32 xTSC; // Thread Switch Control 1B4-1B7 + u32 xTST; // Thread Switch Timeout 1B8-1BB + u32 xRsvd; // Reserved 1BC-1BF + + u64 xACCR; // Address Compare Control Reg 1C0-1C7 + u64 xIMR; // Instruction Match Register 1C8-1CF + u64 xSDR1; // Storage Description Reg 1 1D0-1D7 + u64 xSPRG0; // Special Purpose Reg General0 1D8-1DF + u64 xSPRG1; // Special Purpose Reg General1 1E0-1E7 + u64 xSPRG2; // Special Purpose Reg General2 1E8-1EF + u64 xSPRG3; // Special Purpose Reg General3 1F0-1F7 + u64 xTB; // Time Base Register 1F8-1FF + + u64 xFPR[32]; // Floating Point Registers 200-2FF + + u64 xMSR; // Machine State Register 300-307 + u64 xNIA; // Next Instruction Address 308-30F + + u64 xDABR; // Data Address Breakpoint Reg 310-317 + u64 xIABR; // Inst Address Breakpoint Reg 318-31F + + u64 xHID0; // HW Implementation Dependent0 320-327 + + u64 xHID4; // HW Implementation Dependent4 328-32F + u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337 + u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F + u64 xSDAR; // Sample Data Address Register 340-347 + u64 xSIAR; // Sample Inst Address Register 348-34F + + u8 xRsvd3[176]; // Reserved 350-3FF +}; + +extern void system_reset_iSeries(void); +extern void machine_check_iSeries(void); +extern void data_access_iSeries(void); +extern void instruction_access_iSeries(void); +extern void hardware_interrupt_iSeries(void); +extern void alignment_iSeries(void); +extern void program_check_iSeries(void); +extern void fp_unavailable_iSeries(void); +extern void decrementer_iSeries(void); +extern void trap_0a_iSeries(void); +extern void trap_0b_iSeries(void); +extern void system_call_iSeries(void); +extern void single_step_iSeries(void); +extern void trap_0e_iSeries(void); +extern void performance_monitor_iSeries(void); +extern void data_access_slb_iSeries(void); +extern void instruction_access_slb_iSeries(void); + +struct ItLpNaca itLpNaca = { + .xDesc = 0xd397d581, /* "LpNa" ebcdic */ + .xSize = 0x0400, /* size of ItLpNaca */ + .xIntHdlrOffset = 0x0300, /* offset to int array */ + .xMaxIntHdlrEntries = 19, /* # ents */ + .xPrimaryLpIndex = 0, /* Part # of primary */ + .xServiceLpIndex = 0, /* Part # of serv */ + .xLpIndex = 0, /* Part # of me */ + .xMaxLpQueues = 0, /* # of LP queues */ + .xLpQueueOffset = 0x100, /* offset of start of LP queues */ + .xPirEnvironMode = 0, /* Piranha stuff */ + .xPirConsoleMode = 0, + .xPirDasdMode = 0, + .flags = 0, + .xSpVpdFormat = 0, + .xIntProcRatio = 0, + .xPlicVrmIndex = 0, /* VRM index of PLIC */ + .xMinSupportedSlicVrmInd = 0, /* min supported SLIC */ + .xMinCompatableSlicVrmInd = 0, /* min compat SLIC */ + .xLoadAreaAddr = 0, /* 64-bit addr of load area */ + .xLoadAreaChunks = 0, /* chunks for load area */ + .xPaseSysCallCRMask = 0, /* PASE mask */ + .xSlicSegmentTablePtr = 0, /* seg table */ + .xOldLpQueue = { 0 }, /* Old LP Queue */ + .xInterruptHdlr = { + (u64)system_reset_iSeries, /* 0x100 System Reset */ + (u64)machine_check_iSeries, /* 0x200 Machine Check */ + (u64)data_access_iSeries, /* 0x300 Data Access */ + (u64)instruction_access_iSeries, /* 0x400 Instruction Access */ + (u64)hardware_interrupt_iSeries, /* 0x500 External */ + (u64)alignment_iSeries, /* 0x600 Alignment */ + (u64)program_check_iSeries, /* 0x700 Program Check */ + (u64)fp_unavailable_iSeries, /* 0x800 FP Unavailable */ + (u64)decrementer_iSeries, /* 0x900 Decrementer */ + (u64)trap_0a_iSeries, /* 0xa00 Trap 0A */ + (u64)trap_0b_iSeries, /* 0xb00 Trap 0B */ + (u64)system_call_iSeries, /* 0xc00 System Call */ + (u64)single_step_iSeries, /* 0xd00 Single Step */ + (u64)trap_0e_iSeries, /* 0xe00 Trap 0E */ + (u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */ + 0, /* int 0x1000 */ + 0, /* int 0x1010 */ + 0, /* int 0x1020 CPU ctls */ + (u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */ + (u64)data_access_slb_iSeries, /* 0x380 D-SLB */ + (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */ + } +}; + +/* May be filled in by the hypervisor so cannot end up in the BSS */ +static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data"))); + +/* May be filled in by the hypervisor so cannot end up in the BSS */ +struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data"))); + +#define maxPhysicalProcessors 32 + +struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = { + { + .xInstCacheOperandSize = 32, + .xDataCacheOperandSize = 32, + .xProcFreq = 50000000, + .xTimeBaseFreq = 50000000, + .xPVR = 0x3600 + } +}; + +/* Space for Main Store Vpd 27,200 bytes */ +/* May be filled in by the hypervisor so cannot end up in the BSS */ +u64 xMsVpd[3400] __attribute__((__section__(".data"))); + +/* Space for Recovery Log Buffer */ +/* May be filled in by the hypervisor so cannot end up in the BSS */ +static u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data"))); + +static const struct SpCommArea xSpCommArea = { + .xDesc = 0xE2D7C3C2, + .xFormat = 1, +}; + +static const struct ItLpRegSave iseries_reg_save[] = { + [0 ... (NR_CPUS-1)] = { + .xDesc = 0xd397d9e2, /* "LpRS" */ + .xSize = sizeof(struct ItLpRegSave), + }, +}; + +#define ALPACA_INIT(number) \ +{ \ + .lppaca_ptr = &lppaca[number], \ + .reg_save_ptr = &iseries_reg_save[number], \ +} + +const struct alpaca alpaca[] = { + ALPACA_INIT( 0), +#if NR_CPUS > 1 + ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3), +#if NR_CPUS > 4 + ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7), +#if NR_CPUS > 8 + ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11), + ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15), + ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19), + ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23), + ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27), + ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31), +#if NR_CPUS > 32 + ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35), + ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39), + ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43), + ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47), + ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51), + ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55), + ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59), + ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63), +#endif +#endif +#endif +#endif +}; + +/* The LparMap data is now located at offset 0x6000 in head.S + * It was put there so that the HvReleaseData could address it + * with a 32-bit offset as required by the iSeries hypervisor + * + * The Naca has a pointer to the ItVpdAreas. The hypervisor finds + * the Naca via the HvReleaseData area. The HvReleaseData has the + * offset into the Naca of the pointer to the ItVpdAreas. + */ +const struct ItVpdAreas itVpdAreas = { + .xSlicDesc = 0xc9a3e5c1, /* "ItVA" */ + .xSlicSize = sizeof(struct ItVpdAreas), + .xSlicVpdEntries = ItVpdMaxEntries, /* # VPD array entries */ + .xSlicDmaEntries = ItDmaMaxEntries, /* # DMA array entries */ + .xSlicMaxLogicalProcs = NR_CPUS * 2, /* Max logical procs */ + .xSlicMaxPhysicalProcs = maxPhysicalProcessors, /* Max physical procs */ + .xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks), + .xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs), + .xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens), + .xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens), + .xSlicMaxSlotLabels = 0, /* max slot labels */ + .xSlicMaxLpQueues = 1, /* max LP queues */ + .xPlicDmaLens = { 0 }, /* DMA lengths */ + .xPlicDmaToks = { 0 }, /* DMA tokens */ + .xSlicVpdLens = { /* VPD lengths */ + 0,0,0, /* 0 - 2 */ + sizeof(xItExtVpdPanel), /* 3 Extended VPD */ + sizeof(struct alpaca), /* 4 length of (fake) Paca */ + 0, /* 5 */ + sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */ + 26992, /* 7 length of MS VPD */ + 0, /* 8 */ + sizeof(struct ItLpNaca),/* 9 length of LP Naca */ + 0, /* 10 */ + 256, /* 11 length of Recovery Log Buf */ + sizeof(struct SpCommArea), /* 12 length of SP Comm Area */ + 0,0,0, /* 13 - 15 */ + sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */ + 0,0,0,0,0,0, /* 17 - 22 */ + sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */ + 0,0 /* 24 - 25 */ + }, + .xSlicVpdAdrs = { /* VPD addresses */ + 0,0,0, /* 0 - 2 */ + &xItExtVpdPanel, /* 3 Extended VPD */ + &alpaca[0], /* 4 first (fake) Paca */ + 0, /* 5 */ + &xItIplParmsReal, /* 6 IPL parms */ + &xMsVpd, /* 7 MS Vpd */ + 0, /* 8 */ + &itLpNaca, /* 9 LpNaca */ + 0, /* 10 */ + &xRecoveryLogBuffer, /* 11 Recovery Log Buffer */ + &xSpCommArea, /* 12 SP Comm Area */ + 0,0,0, /* 13 - 15 */ + &xIoHriProcessorVpd, /* 16 Proc Vpd */ + 0,0,0,0,0,0, /* 17 - 22 */ + &hvlpevent_queue, /* 23 Lp Queue */ + 0,0 + } +}; diff --git a/trunk/arch/powerpc/platforms/iseries/lpevents.c b/trunk/arch/powerpc/platforms/iseries/lpevents.c new file mode 100644 index 000000000000..202e22798d30 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/lpevents.c @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "it_lp_naca.h" + +/* + * The LpQueue is used to pass event data from the hypervisor to + * the partition. This is where I/O interrupt events are communicated. + * + * It is written to by the hypervisor so cannot end up in the BSS. + */ +struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data"))); + +DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts); + +static char *event_types[HvLpEvent_Type_NumTypes] = { + "Hypervisor", + "Machine Facilities", + "Session Manager", + "SPD I/O", + "Virtual Bus", + "PCI I/O", + "RIO I/O", + "Virtual Lan", + "Virtual I/O" +}; + +/* Array of LpEvent handler functions */ +static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; +static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes]; + +static struct HvLpEvent * get_next_hvlpevent(void) +{ + struct HvLpEvent * event; + event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event; + + if (hvlpevent_is_valid(event)) { + /* rmb() needed only for weakly consistent machines (regatta) */ + rmb(); + /* Set pointer to next potential event */ + hvlpevent_queue.hq_current_event += ((event->xSizeMinus1 + + IT_LP_EVENT_ALIGN) / IT_LP_EVENT_ALIGN) * + IT_LP_EVENT_ALIGN; + + /* Wrap to beginning if no room at end */ + if (hvlpevent_queue.hq_current_event > + hvlpevent_queue.hq_last_event) { + hvlpevent_queue.hq_current_event = + hvlpevent_queue.hq_event_stack; + } + } else { + event = NULL; + } + + return event; +} + +static unsigned long spread_lpevents = NR_CPUS; + +int hvlpevent_is_pending(void) +{ + struct HvLpEvent *next_event; + + if (smp_processor_id() >= spread_lpevents) + return 0; + + next_event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event; + + return hvlpevent_is_valid(next_event) || + hvlpevent_queue.hq_overflow_pending; +} + +static void hvlpevent_clear_valid(struct HvLpEvent * event) +{ + /* Tell the Hypervisor that we're done with this event. + * Also clear bits within this event that might look like valid bits. + * ie. on 64-byte boundaries. + */ + struct HvLpEvent *tmp; + unsigned extra = ((event->xSizeMinus1 + IT_LP_EVENT_ALIGN) / + IT_LP_EVENT_ALIGN) - 1; + + switch (extra) { + case 3: + tmp = (struct HvLpEvent*)((char*)event + 3 * IT_LP_EVENT_ALIGN); + hvlpevent_invalidate(tmp); + case 2: + tmp = (struct HvLpEvent*)((char*)event + 2 * IT_LP_EVENT_ALIGN); + hvlpevent_invalidate(tmp); + case 1: + tmp = (struct HvLpEvent*)((char*)event + 1 * IT_LP_EVENT_ALIGN); + hvlpevent_invalidate(tmp); + } + + mb(); + + hvlpevent_invalidate(event); +} + +void process_hvlpevents(void) +{ + struct HvLpEvent * event; + + restart: + /* If we have recursed, just return */ + if (!spin_trylock(&hvlpevent_queue.hq_lock)) + return; + + for (;;) { + event = get_next_hvlpevent(); + if (event) { + /* Call appropriate handler here, passing + * a pointer to the LpEvent. The handler + * must make a copy of the LpEvent if it + * needs it in a bottom half. (perhaps for + * an ACK) + * + * Handlers are responsible for ACK processing + * + * The Hypervisor guarantees that LpEvents will + * only be delivered with types that we have + * registered for, so no type check is necessary + * here! + */ + if (event->xType < HvLpEvent_Type_NumTypes) + __get_cpu_var(hvlpevent_counts)[event->xType]++; + if (event->xType < HvLpEvent_Type_NumTypes && + lpEventHandler[event->xType]) + lpEventHandler[event->xType](event); + else { + u8 type = event->xType; + + /* + * Don't printk in the spinlock as printk + * may require ack events form the HV to send + * any characters there. + */ + hvlpevent_clear_valid(event); + spin_unlock(&hvlpevent_queue.hq_lock); + printk(KERN_INFO + "Unexpected Lp Event type=%d\n", type); + goto restart; + } + + hvlpevent_clear_valid(event); + } else if (hvlpevent_queue.hq_overflow_pending) + /* + * No more valid events. If overflow events are + * pending process them + */ + HvCallEvent_getOverflowLpEvents(hvlpevent_queue.hq_index); + else + break; + } + + spin_unlock(&hvlpevent_queue.hq_lock); +} + +static int set_spread_lpevents(char *str) +{ + unsigned long val = simple_strtoul(str, NULL, 0); + + /* + * The parameter is the number of processors to share in processing + * lp events. + */ + if (( val > 0) && (val <= NR_CPUS)) { + spread_lpevents = val; + printk("lpevent processing spread over %ld processors\n", val); + } else { + printk("invalid spread_lpevents %ld\n", val); + } + + return 1; +} +__setup("spread_lpevents=", set_spread_lpevents); + +void __init setup_hvlpevent_queue(void) +{ + void *eventStack; + + spin_lock_init(&hvlpevent_queue.hq_lock); + + /* Allocate a page for the Event Stack. */ + eventStack = alloc_bootmem_pages(IT_LP_EVENT_STACK_SIZE); + memset(eventStack, 0, IT_LP_EVENT_STACK_SIZE); + + /* Invoke the hypervisor to initialize the event stack */ + HvCallEvent_setLpEventStack(0, eventStack, IT_LP_EVENT_STACK_SIZE); + + hvlpevent_queue.hq_event_stack = eventStack; + hvlpevent_queue.hq_current_event = eventStack; + hvlpevent_queue.hq_last_event = (char *)eventStack + + (IT_LP_EVENT_STACK_SIZE - IT_LP_EVENT_MAX_SIZE); + hvlpevent_queue.hq_index = 0; +} + +/* Register a handler for an LpEvent type */ +int HvLpEvent_registerHandler(HvLpEvent_Type eventType, LpEventHandler handler) +{ + if (eventType < HvLpEvent_Type_NumTypes) { + lpEventHandler[eventType] = handler; + return 0; + } + return 1; +} +EXPORT_SYMBOL(HvLpEvent_registerHandler); + +int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType) +{ + might_sleep(); + + if (eventType < HvLpEvent_Type_NumTypes) { + if (!lpEventHandlerPaths[eventType]) { + lpEventHandler[eventType] = NULL; + /* + * We now sleep until all other CPUs have scheduled. + * This ensures that the deletion is seen by all + * other CPUs, and that the deleted handler isn't + * still running on another CPU when we return. + */ + synchronize_sched(); + return 0; + } + } + return 1; +} +EXPORT_SYMBOL(HvLpEvent_unregisterHandler); + +/* + * lpIndex is the partition index of the target partition. + * needed only for VirtualIo, VirtualLan and SessionMgr. Zero + * indicates to use our partition index - for the other types. + */ +int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex) +{ + if ((eventType < HvLpEvent_Type_NumTypes) && + lpEventHandler[eventType]) { + if (lpIndex == 0) + lpIndex = itLpNaca.xLpIndex; + HvCallEvent_openLpEventPath(lpIndex, eventType); + ++lpEventHandlerPaths[eventType]; + return 0; + } + return 1; +} + +int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex) +{ + if ((eventType < HvLpEvent_Type_NumTypes) && + lpEventHandler[eventType] && + lpEventHandlerPaths[eventType]) { + if (lpIndex == 0) + lpIndex = itLpNaca.xLpIndex; + HvCallEvent_closeLpEventPath(lpIndex, eventType); + --lpEventHandlerPaths[eventType]; + return 0; + } + return 1; +} + +static int proc_lpevents_show(struct seq_file *m, void *v) +{ + int cpu, i; + unsigned long sum; + static unsigned long cpu_totals[NR_CPUS]; + + /* FIXME: do we care that there's no locking here? */ + sum = 0; + for_each_online_cpu(cpu) { + cpu_totals[cpu] = 0; + for (i = 0; i < HvLpEvent_Type_NumTypes; i++) { + cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i]; + } + sum += cpu_totals[cpu]; + } + + seq_printf(m, "LpEventQueue 0\n"); + seq_printf(m, " events processed:\t%lu\n", sum); + + for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) { + sum = 0; + for_each_online_cpu(cpu) { + sum += per_cpu(hvlpevent_counts, cpu)[i]; + } + + seq_printf(m, " %-20s %10lu\n", event_types[i], sum); + } + + seq_printf(m, "\n events processed by processor:\n"); + + for_each_online_cpu(cpu) { + seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]); + } + + return 0; +} + +static int proc_lpevents_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_lpevents_show, NULL); +} + +static const struct file_operations proc_lpevents_operations = { + .open = proc_lpevents_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init proc_lpevents_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return 0; + + proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL, + &proc_lpevents_operations); + return 0; +} +__initcall(proc_lpevents_init); + diff --git a/trunk/arch/powerpc/platforms/iseries/main_store.h b/trunk/arch/powerpc/platforms/iseries/main_store.h new file mode 100644 index 000000000000..1a7a3f50e40b --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/main_store.h @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ISERIES_MAIN_STORE_H +#define _ISERIES_MAIN_STORE_H + +/* Main Store Vpd for Condor,iStar,sStar */ +struct IoHriMainStoreSegment4 { + u8 msArea0Exists:1; + u8 msArea1Exists:1; + u8 msArea2Exists:1; + u8 msArea3Exists:1; + u8 reserved1:4; + u8 reserved2; + + u8 msArea0Functional:1; + u8 msArea1Functional:1; + u8 msArea2Functional:1; + u8 msArea3Functional:1; + u8 reserved3:4; + u8 reserved4; + + u32 totalMainStore; + + u64 msArea0Ptr; + u64 msArea1Ptr; + u64 msArea2Ptr; + u64 msArea3Ptr; + + u32 cardProductionLevel; + + u32 msAdrHole; + + u8 msArea0HasRiserVpd:1; + u8 msArea1HasRiserVpd:1; + u8 msArea2HasRiserVpd:1; + u8 msArea3HasRiserVpd:1; + u8 reserved5:4; + u8 reserved6; + u16 reserved7; + + u8 reserved8[28]; + + u64 nonInterleavedBlocksStartAdr; + u64 nonInterleavedBlocksEndAdr; +}; + +/* Main Store VPD for Power4 */ +struct __attribute((packed)) IoHriMainStoreChipInfo1 { + u32 chipMfgID; + char chipECLevel[4]; +}; + +struct IoHriMainStoreVpdIdData { + char typeNumber[4]; + char modelNumber[4]; + char partNumber[12]; + char serialNumber[12]; +}; + +struct __attribute((packed)) IoHriMainStoreVpdFruData { + char fruLabel[8]; + u8 numberOfSlots; + u8 pluggingType; + u16 slotMapIndex; +}; + +struct __attribute((packed)) IoHriMainStoreAdrRangeBlock { + void *blockStart; + void *blockEnd; + u32 blockProcChipId; +}; + +#define MaxAreaAdrRangeBlocks 4 + +struct __attribute((packed)) IoHriMainStoreArea4 { + u32 msVpdFormat; + u8 containedVpdType; + u8 reserved1; + u16 reserved2; + + u64 msExists; + u64 msFunctional; + + u32 memorySize; + u32 procNodeId; + + u32 numAdrRangeBlocks; + struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks]; + + struct IoHriMainStoreChipInfo1 chipInfo0; + struct IoHriMainStoreChipInfo1 chipInfo1; + struct IoHriMainStoreChipInfo1 chipInfo2; + struct IoHriMainStoreChipInfo1 chipInfo3; + struct IoHriMainStoreChipInfo1 chipInfo4; + struct IoHriMainStoreChipInfo1 chipInfo5; + struct IoHriMainStoreChipInfo1 chipInfo6; + struct IoHriMainStoreChipInfo1 chipInfo7; + + void *msRamAreaArray; + u32 msRamAreaArrayNumEntries; + u32 msRamAreaArrayEntrySize; + + u32 numaDimmExists; + u32 numaDimmFunctional; + void *numaDimmArray; + u32 numaDimmArrayNumEntries; + u32 numaDimmArrayEntrySize; + + struct IoHriMainStoreVpdIdData idData; + + u64 powerData; + u64 cardAssemblyPartNum; + u64 chipSerialNum; + + u64 reserved3; + char reserved4[16]; + + struct IoHriMainStoreVpdFruData fruData; + + u8 vpdPortNum; + u8 reserved5; + u8 frameId; + u8 rackUnit; + char asciiKeywordVpd[256]; + u32 reserved6; +}; + + +struct IoHriMainStoreSegment5 { + u16 reserved1; + u8 reserved2; + u8 msVpdFormat; + + u32 totalMainStore; + u64 maxConfiguredMsAdr; + + struct IoHriMainStoreArea4 *msAreaArray; + u32 msAreaArrayNumEntries; + u32 msAreaArrayEntrySize; + + u32 msAreaExists; + u32 msAreaFunctional; + + u64 reserved3; +}; + +extern u64 xMsVpd[]; + +#endif /* _ISERIES_MAIN_STORE_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/mf.c b/trunk/arch/powerpc/platforms/iseries/mf.c new file mode 100644 index 000000000000..254c1fc3d8dd --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/mf.c @@ -0,0 +1,1275 @@ +/* + * Copyright (C) 2001 Troy D. Armstrong IBM Corporation + * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation + * + * This modules exists as an interface between a Linux secondary partition + * running on an iSeries and the primary partition's Virtual Service + * Processor (VSP) object. The VSP has final authority over powering on/off + * all partitions in the iSeries. It also provides miscellaneous low-level + * machine facility type operations. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "setup.h" + +static int mf_initialized; + +/* + * This is the structure layout for the Machine Facilities LPAR event + * flows. + */ +struct vsp_cmd_data { + u64 token; + u16 cmd; + HvLpIndex lp_index; + u8 result_code; + u32 reserved; + union { + u64 state; /* GetStateOut */ + u64 ipl_type; /* GetIplTypeOut, Function02SelectIplTypeIn */ + u64 ipl_mode; /* GetIplModeOut, Function02SelectIplModeIn */ + u64 page[4]; /* GetSrcHistoryIn */ + u64 flag; /* GetAutoIplWhenPrimaryIplsOut, + SetAutoIplWhenPrimaryIplsIn, + WhiteButtonPowerOffIn, + Function08FastPowerOffIn, + IsSpcnRackPowerIncompleteOut */ + struct { + u64 token; + u64 address_type; + u64 side; + u32 length; + u32 offset; + } kern; /* SetKernelImageIn, GetKernelImageIn, + SetKernelCmdLineIn, GetKernelCmdLineIn */ + u32 length_out; /* GetKernelImageOut, GetKernelCmdLineOut */ + u8 reserved[80]; + } sub_data; +}; + +struct vsp_rsp_data { + struct completion com; + struct vsp_cmd_data *response; +}; + +struct alloc_data { + u16 size; + u16 type; + u32 count; + u16 reserved1; + u8 reserved2; + HvLpIndex target_lp; +}; + +struct ce_msg_data; + +typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp); + +struct ce_msg_comp_data { + ce_msg_comp_hdlr handler; + void *token; +}; + +struct ce_msg_data { + u8 ce_msg[12]; + char reserved[4]; + struct ce_msg_comp_data *completion; +}; + +struct io_mf_lp_event { + struct HvLpEvent hp_lp_event; + u16 subtype_result_code; + u16 reserved1; + u32 reserved2; + union { + struct alloc_data alloc; + struct ce_msg_data ce_msg; + struct vsp_cmd_data vsp_cmd; + } data; +}; + +#define subtype_data(a, b, c, d) \ + (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) + +/* + * All outgoing event traffic is kept on a FIFO queue. The first + * pointer points to the one that is outstanding, and all new + * requests get stuck on the end. Also, we keep a certain number of + * preallocated pending events so that we can operate very early in + * the boot up sequence (before kmalloc is ready). + */ +struct pending_event { + struct pending_event *next; + struct io_mf_lp_event event; + MFCompleteHandler hdlr; + char dma_data[72]; + unsigned dma_data_length; + unsigned remote_address; +}; +static spinlock_t pending_event_spinlock; +static struct pending_event *pending_event_head; +static struct pending_event *pending_event_tail; +static struct pending_event *pending_event_avail; +#define PENDING_EVENT_PREALLOC_LEN 16 +static struct pending_event pending_event_prealloc[PENDING_EVENT_PREALLOC_LEN]; + +/* + * Put a pending event onto the available queue, so it can get reused. + * Attention! You must have the pending_event_spinlock before calling! + */ +static void free_pending_event(struct pending_event *ev) +{ + if (ev != NULL) { + ev->next = pending_event_avail; + pending_event_avail = ev; + } +} + +/* + * Enqueue the outbound event onto the stack. If the queue was + * empty to begin with, we must also issue it via the Hypervisor + * interface. There is a section of code below that will touch + * the first stack pointer without the protection of the pending_event_spinlock. + * This is OK, because we know that nobody else will be modifying + * the first pointer when we do this. + */ +static int signal_event(struct pending_event *ev) +{ + int rc = 0; + unsigned long flags; + int go = 1; + struct pending_event *ev1; + HvLpEvent_Rc hv_rc; + + /* enqueue the event */ + if (ev != NULL) { + ev->next = NULL; + spin_lock_irqsave(&pending_event_spinlock, flags); + if (pending_event_head == NULL) + pending_event_head = ev; + else { + go = 0; + pending_event_tail->next = ev; + } + pending_event_tail = ev; + spin_unlock_irqrestore(&pending_event_spinlock, flags); + } + + /* send the event */ + while (go) { + go = 0; + + /* any DMA data to send beforehand? */ + if (pending_event_head->dma_data_length > 0) + HvCallEvent_dmaToSp(pending_event_head->dma_data, + pending_event_head->remote_address, + pending_event_head->dma_data_length, + HvLpDma_Direction_LocalToRemote); + + hv_rc = HvCallEvent_signalLpEvent( + &pending_event_head->event.hp_lp_event); + if (hv_rc != HvLpEvent_Rc_Good) { + printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() " + "failed with %d\n", (int)hv_rc); + + spin_lock_irqsave(&pending_event_spinlock, flags); + ev1 = pending_event_head; + pending_event_head = pending_event_head->next; + if (pending_event_head != NULL) + go = 1; + spin_unlock_irqrestore(&pending_event_spinlock, flags); + + if (ev1 == ev) + rc = -EIO; + else if (ev1->hdlr != NULL) + (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO); + + spin_lock_irqsave(&pending_event_spinlock, flags); + free_pending_event(ev1); + spin_unlock_irqrestore(&pending_event_spinlock, flags); + } + } + + return rc; +} + +/* + * Allocate a new pending_event structure, and initialize it. + */ +static struct pending_event *new_pending_event(void) +{ + struct pending_event *ev = NULL; + HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex(); + unsigned long flags; + struct HvLpEvent *hev; + + spin_lock_irqsave(&pending_event_spinlock, flags); + if (pending_event_avail != NULL) { + ev = pending_event_avail; + pending_event_avail = pending_event_avail->next; + } + spin_unlock_irqrestore(&pending_event_spinlock, flags); + if (ev == NULL) { + ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC); + if (ev == NULL) { + printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n", + sizeof(struct pending_event)); + return NULL; + } + } + memset(ev, 0, sizeof(struct pending_event)); + hev = &ev->event.hp_lp_event; + hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | HV_LP_EVENT_INT; + hev->xType = HvLpEvent_Type_MachineFac; + hev->xSourceLp = HvLpConfig_getLpIndex(); + hev->xTargetLp = primary_lp; + hev->xSizeMinus1 = sizeof(ev->event) - 1; + hev->xRc = HvLpEvent_Rc_Good; + hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp, + HvLpEvent_Type_MachineFac); + hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp, + HvLpEvent_Type_MachineFac); + + return ev; +} + +static int __maybe_unused +signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) +{ + struct pending_event *ev = new_pending_event(); + int rc; + struct vsp_rsp_data response; + + if (ev == NULL) + return -ENOMEM; + + init_completion(&response.com); + response.response = vsp_cmd; + ev->event.hp_lp_event.xSubtype = 6; + ev->event.hp_lp_event.x.xSubtypeData = + subtype_data('M', 'F', 'V', 'I'); + ev->event.data.vsp_cmd.token = (u64)&response; + ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd; + ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex(); + ev->event.data.vsp_cmd.result_code = 0xFF; + ev->event.data.vsp_cmd.reserved = 0; + memcpy(&(ev->event.data.vsp_cmd.sub_data), + &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data)); + mb(); + + rc = signal_event(ev); + if (rc == 0) + wait_for_completion(&response.com); + return rc; +} + + +/* + * Send a 12-byte CE message to the primary partition VSP object + */ +static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion) +{ + struct pending_event *ev = new_pending_event(); + + if (ev == NULL) + return -ENOMEM; + + ev->event.hp_lp_event.xSubtype = 0; + ev->event.hp_lp_event.x.xSubtypeData = + subtype_data('M', 'F', 'C', 'E'); + memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); + ev->event.data.ce_msg.completion = completion; + return signal_event(ev); +} + +/* + * Send a 12-byte CE message (with no data) to the primary partition VSP object + */ +static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion) +{ + u8 ce_msg[12]; + + memset(ce_msg, 0, sizeof(ce_msg)); + ce_msg[3] = ce_op; + return signal_ce_msg(ce_msg, completion); +} + +/* + * Send a 12-byte CE message and DMA data to the primary partition VSP object + */ +static int dma_and_signal_ce_msg(char *ce_msg, + struct ce_msg_comp_data *completion, void *dma_data, + unsigned dma_data_length, unsigned remote_address) +{ + struct pending_event *ev = new_pending_event(); + + if (ev == NULL) + return -ENOMEM; + + ev->event.hp_lp_event.xSubtype = 0; + ev->event.hp_lp_event.x.xSubtypeData = + subtype_data('M', 'F', 'C', 'E'); + memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); + ev->event.data.ce_msg.completion = completion; + memcpy(ev->dma_data, dma_data, dma_data_length); + ev->dma_data_length = dma_data_length; + ev->remote_address = remote_address; + return signal_event(ev); +} + +/* + * Initiate a nice (hopefully) shutdown of Linux. We simply are + * going to try and send the init process a SIGINT signal. If + * this fails (why?), we'll simply force it off in a not-so-nice + * manner. + */ +static int shutdown(void) +{ + int rc = kill_cad_pid(SIGINT, 1); + + if (rc) { + printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), " + "hard shutdown commencing\n", rc); + mf_power_off(); + } else + printk(KERN_INFO "mf.c: init has been successfully notified " + "to proceed with shutdown\n"); + return rc; +} + +/* + * The primary partition VSP object is sending us a new + * event flow. Handle it... + */ +static void handle_int(struct io_mf_lp_event *event) +{ + struct ce_msg_data *ce_msg_data; + struct ce_msg_data *pce_msg_data; + unsigned long flags; + struct pending_event *pev; + + /* ack the interrupt */ + event->hp_lp_event.xRc = HvLpEvent_Rc_Good; + HvCallEvent_ackLpEvent(&event->hp_lp_event); + + /* process interrupt */ + switch (event->hp_lp_event.xSubtype) { + case 0: /* CE message */ + ce_msg_data = &event->data.ce_msg; + switch (ce_msg_data->ce_msg[3]) { + case 0x5B: /* power control notification */ + if ((ce_msg_data->ce_msg[5] & 0x20) != 0) { + printk(KERN_INFO "mf.c: Commencing partition shutdown\n"); + if (shutdown() == 0) + signal_ce_msg_simple(0xDB, NULL); + } + break; + case 0xC0: /* get time */ + spin_lock_irqsave(&pending_event_spinlock, flags); + pev = pending_event_head; + if (pev != NULL) + pending_event_head = pending_event_head->next; + spin_unlock_irqrestore(&pending_event_spinlock, flags); + if (pev == NULL) + break; + pce_msg_data = &pev->event.data.ce_msg; + if (pce_msg_data->ce_msg[3] != 0x40) + break; + if (pce_msg_data->completion != NULL) { + ce_msg_comp_hdlr handler = + pce_msg_data->completion->handler; + void *token = pce_msg_data->completion->token; + + if (handler != NULL) + (*handler)(token, ce_msg_data); + } + spin_lock_irqsave(&pending_event_spinlock, flags); + free_pending_event(pev); + spin_unlock_irqrestore(&pending_event_spinlock, flags); + /* send next waiting event */ + if (pending_event_head != NULL) + signal_event(NULL); + break; + } + break; + case 1: /* IT sys shutdown */ + printk(KERN_INFO "mf.c: Commencing system shutdown\n"); + shutdown(); + break; + } +} + +/* + * The primary partition VSP object is acknowledging the receipt + * of a flow we sent to them. If there are other flows queued + * up, we must send another one now... + */ +static void handle_ack(struct io_mf_lp_event *event) +{ + unsigned long flags; + struct pending_event *two = NULL; + unsigned long free_it = 0; + struct ce_msg_data *ce_msg_data; + struct ce_msg_data *pce_msg_data; + struct vsp_rsp_data *rsp; + + /* handle current event */ + if (pending_event_head == NULL) { + printk(KERN_ERR "mf.c: stack empty for receiving ack\n"); + return; + } + + switch (event->hp_lp_event.xSubtype) { + case 0: /* CE msg */ + ce_msg_data = &event->data.ce_msg; + if (ce_msg_data->ce_msg[3] != 0x40) { + free_it = 1; + break; + } + if (ce_msg_data->ce_msg[2] == 0) + break; + free_it = 1; + pce_msg_data = &pending_event_head->event.data.ce_msg; + if (pce_msg_data->completion != NULL) { + ce_msg_comp_hdlr handler = + pce_msg_data->completion->handler; + void *token = pce_msg_data->completion->token; + + if (handler != NULL) + (*handler)(token, ce_msg_data); + } + break; + case 4: /* allocate */ + case 5: /* deallocate */ + if (pending_event_head->hdlr != NULL) + (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count); + free_it = 1; + break; + case 6: + free_it = 1; + rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token; + if (rsp == NULL) { + printk(KERN_ERR "mf.c: no rsp\n"); + break; + } + if (rsp->response != NULL) + memcpy(rsp->response, &event->data.vsp_cmd, + sizeof(event->data.vsp_cmd)); + complete(&rsp->com); + break; + } + + /* remove from queue */ + spin_lock_irqsave(&pending_event_spinlock, flags); + if ((pending_event_head != NULL) && (free_it == 1)) { + struct pending_event *oldHead = pending_event_head; + + pending_event_head = pending_event_head->next; + two = pending_event_head; + free_pending_event(oldHead); + } + spin_unlock_irqrestore(&pending_event_spinlock, flags); + + /* send next waiting event */ + if (two != NULL) + signal_event(NULL); +} + +/* + * This is the generic event handler we are registering with + * the Hypervisor. Ensure the flows are for us, and then + * parse it enough to know if it is an interrupt or an + * acknowledge. + */ +static void hv_handler(struct HvLpEvent *event) +{ + if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) { + if (hvlpevent_is_ack(event)) + handle_ack((struct io_mf_lp_event *)event); + else + handle_int((struct io_mf_lp_event *)event); + } else + printk(KERN_ERR "mf.c: alien event received\n"); +} + +/* + * Global kernel interface to allocate and seed events into the + * Hypervisor. + */ +void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, + unsigned size, unsigned count, MFCompleteHandler hdlr, + void *user_token) +{ + struct pending_event *ev = new_pending_event(); + int rc; + + if (ev == NULL) { + rc = -ENOMEM; + } else { + ev->event.hp_lp_event.xSubtype = 4; + ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; + ev->event.hp_lp_event.x.xSubtypeData = + subtype_data('M', 'F', 'M', 'A'); + ev->event.data.alloc.target_lp = target_lp; + ev->event.data.alloc.type = type; + ev->event.data.alloc.size = size; + ev->event.data.alloc.count = count; + ev->hdlr = hdlr; + rc = signal_event(ev); + } + if ((rc != 0) && (hdlr != NULL)) + (*hdlr)(user_token, rc); +} +EXPORT_SYMBOL(mf_allocate_lp_events); + +/* + * Global kernel interface to unseed and deallocate events already in + * Hypervisor. + */ +void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, + unsigned count, MFCompleteHandler hdlr, void *user_token) +{ + struct pending_event *ev = new_pending_event(); + int rc; + + if (ev == NULL) + rc = -ENOMEM; + else { + ev->event.hp_lp_event.xSubtype = 5; + ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; + ev->event.hp_lp_event.x.xSubtypeData = + subtype_data('M', 'F', 'M', 'D'); + ev->event.data.alloc.target_lp = target_lp; + ev->event.data.alloc.type = type; + ev->event.data.alloc.count = count; + ev->hdlr = hdlr; + rc = signal_event(ev); + } + if ((rc != 0) && (hdlr != NULL)) + (*hdlr)(user_token, rc); +} +EXPORT_SYMBOL(mf_deallocate_lp_events); + +/* + * Global kernel interface to tell the VSP object in the primary + * partition to power this partition off. + */ +void mf_power_off(void) +{ + printk(KERN_INFO "mf.c: Down it goes...\n"); + signal_ce_msg_simple(0x4d, NULL); + for (;;) + ; +} + +/* + * Global kernel interface to tell the VSP object in the primary + * partition to reboot this partition. + */ +void mf_reboot(char *cmd) +{ + printk(KERN_INFO "mf.c: Preparing to bounce...\n"); + signal_ce_msg_simple(0x4e, NULL); + for (;;) + ; +} + +/* + * Display a single word SRC onto the VSP control panel. + */ +void mf_display_src(u32 word) +{ + u8 ce[12]; + + memset(ce, 0, sizeof(ce)); + ce[3] = 0x4a; + ce[7] = 0x01; + ce[8] = word >> 24; + ce[9] = word >> 16; + ce[10] = word >> 8; + ce[11] = word; + signal_ce_msg(ce, NULL); +} + +/* + * Display a single word SRC of the form "PROGXXXX" on the VSP control panel. + */ +static __init void mf_display_progress_src(u16 value) +{ + u8 ce[12]; + u8 src[72]; + + memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12); + memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + "\x00\x00\x00\x00PROGxxxx ", + 72); + src[6] = value >> 8; + src[7] = value & 255; + src[44] = "0123456789ABCDEF"[(value >> 12) & 15]; + src[45] = "0123456789ABCDEF"[(value >> 8) & 15]; + src[46] = "0123456789ABCDEF"[(value >> 4) & 15]; + src[47] = "0123456789ABCDEF"[value & 15]; + dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024); +} + +/* + * Clear the VSP control panel. Used to "erase" an SRC that was + * previously displayed. + */ +static void mf_clear_src(void) +{ + signal_ce_msg_simple(0x4b, NULL); +} + +void __init mf_display_progress(u16 value) +{ + if (!mf_initialized) + return; + + if (0xFFFF == value) + mf_clear_src(); + else + mf_display_progress_src(value); +} + +/* + * Initialization code here. + */ +void __init mf_init(void) +{ + int i; + + spin_lock_init(&pending_event_spinlock); + + for (i = 0; i < PENDING_EVENT_PREALLOC_LEN; i++) + free_pending_event(&pending_event_prealloc[i]); + + HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler); + + /* virtual continue ack */ + signal_ce_msg_simple(0x57, NULL); + + mf_initialized = 1; + mb(); + + printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities " + "initialized\n"); +} + +struct rtc_time_data { + struct completion com; + struct ce_msg_data ce_msg; + int rc; +}; + +static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) +{ + struct rtc_time_data *rtc = token; + + memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); + rtc->rc = 0; + complete(&rtc->com); +} + +static int mf_set_rtc(struct rtc_time *tm) +{ + char ce_time[12]; + u8 day, mon, hour, min, sec, y1, y2; + unsigned year; + + year = 1900 + tm->tm_year; + y1 = year / 100; + y2 = year % 100; + + sec = tm->tm_sec; + min = tm->tm_min; + hour = tm->tm_hour; + day = tm->tm_mday; + mon = tm->tm_mon + 1; + + sec = bin2bcd(sec); + min = bin2bcd(min); + hour = bin2bcd(hour); + mon = bin2bcd(mon); + day = bin2bcd(day); + y1 = bin2bcd(y1); + y2 = bin2bcd(y2); + + memset(ce_time, 0, sizeof(ce_time)); + ce_time[3] = 0x41; + ce_time[4] = y1; + ce_time[5] = y2; + ce_time[6] = sec; + ce_time[7] = min; + ce_time[8] = hour; + ce_time[10] = day; + ce_time[11] = mon; + + return signal_ce_msg(ce_time, NULL); +} + +static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm) +{ + tm->tm_wday = 0; + tm->tm_yday = 0; + tm->tm_isdst = 0; + if (rc) { + tm->tm_sec = 0; + tm->tm_min = 0; + tm->tm_hour = 0; + tm->tm_mday = 15; + tm->tm_mon = 5; + tm->tm_year = 52; + return rc; + } + + if ((ce_msg[2] == 0xa9) || + (ce_msg[2] == 0xaf)) { + /* TOD clock is not set */ + tm->tm_sec = 1; + tm->tm_min = 1; + tm->tm_hour = 1; + tm->tm_mday = 10; + tm->tm_mon = 8; + tm->tm_year = 71; + mf_set_rtc(tm); + } + { + u8 year = ce_msg[5]; + u8 sec = ce_msg[6]; + u8 min = ce_msg[7]; + u8 hour = ce_msg[8]; + u8 day = ce_msg[10]; + u8 mon = ce_msg[11]; + + sec = bcd2bin(sec); + min = bcd2bin(min); + hour = bcd2bin(hour); + day = bcd2bin(day); + mon = bcd2bin(mon); + year = bcd2bin(year); + + if (year <= 69) + year += 100; + + tm->tm_sec = sec; + tm->tm_min = min; + tm->tm_hour = hour; + tm->tm_mday = day; + tm->tm_mon = mon; + tm->tm_year = year; + } + + return 0; +} + +static int mf_get_rtc(struct rtc_time *tm) +{ + struct ce_msg_comp_data ce_complete; + struct rtc_time_data rtc_data; + int rc; + + memset(&ce_complete, 0, sizeof(ce_complete)); + memset(&rtc_data, 0, sizeof(rtc_data)); + init_completion(&rtc_data.com); + ce_complete.handler = &get_rtc_time_complete; + ce_complete.token = &rtc_data; + rc = signal_ce_msg_simple(0x40, &ce_complete); + if (rc) + return rc; + wait_for_completion(&rtc_data.com); + return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); +} + +struct boot_rtc_time_data { + int busy; + struct ce_msg_data ce_msg; + int rc; +}; + +static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) +{ + struct boot_rtc_time_data *rtc = token; + + memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); + rtc->rc = 0; + rtc->busy = 0; +} + +static int mf_get_boot_rtc(struct rtc_time *tm) +{ + struct ce_msg_comp_data ce_complete; + struct boot_rtc_time_data rtc_data; + int rc; + + memset(&ce_complete, 0, sizeof(ce_complete)); + memset(&rtc_data, 0, sizeof(rtc_data)); + rtc_data.busy = 1; + ce_complete.handler = &get_boot_rtc_time_complete; + ce_complete.token = &rtc_data; + rc = signal_ce_msg_simple(0x40, &ce_complete); + if (rc) + return rc; + /* We need to poll here as we are not yet taking interrupts */ + while (rtc_data.busy) { + if (hvlpevent_is_pending()) + process_hvlpevents(); + } + return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); +} + +#ifdef CONFIG_PROC_FS +static int mf_cmdline_proc_show(struct seq_file *m, void *v) +{ + char *page, *p; + struct vsp_cmd_data vsp_cmd; + int rc; + dma_addr_t dma_addr; + + /* The HV appears to return no more than 256 bytes of command line */ + page = kmalloc(256, GFP_KERNEL); + if (!page) + return -ENOMEM; + + dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE); + if (dma_addr == DMA_ERROR_CODE) { + kfree(page); + return -ENOMEM; + } + memset(page, 0, 256); + memset(&vsp_cmd, 0, sizeof(vsp_cmd)); + vsp_cmd.cmd = 33; + vsp_cmd.sub_data.kern.token = dma_addr; + vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; + vsp_cmd.sub_data.kern.side = (u64)m->private; + vsp_cmd.sub_data.kern.length = 256; + mb(); + rc = signal_vsp_instruction(&vsp_cmd); + iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE); + if (rc) { + kfree(page); + return rc; + } + if (vsp_cmd.result_code != 0) { + kfree(page); + return -ENOMEM; + } + p = page; + while (p - page < 256) { + if (*p == '\0' || *p == '\n') { + *p = '\n'; + break; + } + p++; + + } + seq_write(m, page, p - page); + kfree(page); + return 0; +} + +static int mf_cmdline_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mf_cmdline_proc_show, PDE(inode)->data); +} + +#if 0 +static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) +{ + struct vsp_cmd_data vsp_cmd; + int rc; + int len = *size; + dma_addr_t dma_addr; + + dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE); + memset(buffer, 0, len); + memset(&vsp_cmd, 0, sizeof(vsp_cmd)); + vsp_cmd.cmd = 32; + vsp_cmd.sub_data.kern.token = dma_addr; + vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; + vsp_cmd.sub_data.kern.side = side; + vsp_cmd.sub_data.kern.offset = offset; + vsp_cmd.sub_data.kern.length = len; + mb(); + rc = signal_vsp_instruction(&vsp_cmd); + if (rc == 0) { + if (vsp_cmd.result_code == 0) + *size = vsp_cmd.sub_data.length_out; + else + rc = -ENOMEM; + } + + iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE); + + return rc; +} + +static int proc_mf_dump_vmlinux(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int sizeToGet = count; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) { + if (sizeToGet != 0) { + *start = page + off; + return sizeToGet; + } + *eof = 1; + return 0; + } + *eof = 1; + return 0; +} +#endif + +static int mf_side_proc_show(struct seq_file *m, void *v) +{ + char mf_current_side = ' '; + struct vsp_cmd_data vsp_cmd; + + memset(&vsp_cmd, 0, sizeof(vsp_cmd)); + vsp_cmd.cmd = 2; + vsp_cmd.sub_data.ipl_type = 0; + mb(); + + if (signal_vsp_instruction(&vsp_cmd) == 0) { + if (vsp_cmd.result_code == 0) { + switch (vsp_cmd.sub_data.ipl_type) { + case 0: mf_current_side = 'A'; + break; + case 1: mf_current_side = 'B'; + break; + case 2: mf_current_side = 'C'; + break; + default: mf_current_side = 'D'; + break; + } + } + } + + seq_printf(m, "%c\n", mf_current_side); + return 0; +} + +static int mf_side_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mf_side_proc_show, NULL); +} + +static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + char side; + u64 newSide; + struct vsp_cmd_data vsp_cmd; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (count == 0) + return 0; + + if (get_user(side, buffer)) + return -EFAULT; + + switch (side) { + case 'A': newSide = 0; + break; + case 'B': newSide = 1; + break; + case 'C': newSide = 2; + break; + case 'D': newSide = 3; + break; + default: + printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n"); + return -EINVAL; + } + + memset(&vsp_cmd, 0, sizeof(vsp_cmd)); + vsp_cmd.sub_data.ipl_type = newSide; + vsp_cmd.cmd = 10; + + (void)signal_vsp_instruction(&vsp_cmd); + + return count; +} + +static const struct file_operations mf_side_proc_fops = { + .owner = THIS_MODULE, + .open = mf_side_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = mf_side_proc_write, +}; + +static int mf_src_proc_show(struct seq_file *m, void *v) +{ + return 0; +} + +static int mf_src_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, mf_src_proc_show, NULL); +} + +static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + char stkbuf[10]; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if ((count < 4) && (count != 1)) { + printk(KERN_ERR "mf_proc: invalid src\n"); + return -EINVAL; + } + + if (count > (sizeof(stkbuf) - 1)) + count = sizeof(stkbuf) - 1; + if (copy_from_user(stkbuf, buffer, count)) + return -EFAULT; + + if ((count == 1) && (*stkbuf == '\0')) + mf_clear_src(); + else + mf_display_src(*(u32 *)stkbuf); + + return count; +} + +static const struct file_operations mf_src_proc_fops = { + .owner = THIS_MODULE, + .open = mf_src_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = mf_src_proc_write, +}; + +static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *pos) +{ + void *data = PDE(file->f_path.dentry->d_inode)->data; + struct vsp_cmd_data vsp_cmd; + dma_addr_t dma_addr; + char *page; + int ret = -EACCES; + + if (!capable(CAP_SYS_ADMIN)) + goto out; + + dma_addr = 0; + page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); + ret = -ENOMEM; + if (page == NULL) + goto out; + + ret = -EFAULT; + if (copy_from_user(page, buffer, count)) + goto out_free; + + memset(&vsp_cmd, 0, sizeof(vsp_cmd)); + vsp_cmd.cmd = 31; + vsp_cmd.sub_data.kern.token = dma_addr; + vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; + vsp_cmd.sub_data.kern.side = (u64)data; + vsp_cmd.sub_data.kern.length = count; + mb(); + (void)signal_vsp_instruction(&vsp_cmd); + ret = count; + +out_free: + iseries_hv_free(count, page, dma_addr); +out: + return ret; +} + +static const struct file_operations mf_cmdline_proc_fops = { + .owner = THIS_MODULE, + .open = mf_cmdline_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .write = mf_cmdline_proc_write, +}; + +static ssize_t proc_mf_change_vmlinux(struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); + ssize_t rc; + dma_addr_t dma_addr; + char *page; + struct vsp_cmd_data vsp_cmd; + + rc = -EACCES; + if (!capable(CAP_SYS_ADMIN)) + goto out; + + dma_addr = 0; + page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); + rc = -ENOMEM; + if (page == NULL) { + printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); + goto out; + } + rc = -EFAULT; + if (copy_from_user(page, buf, count)) + goto out_free; + + memset(&vsp_cmd, 0, sizeof(vsp_cmd)); + vsp_cmd.cmd = 30; + vsp_cmd.sub_data.kern.token = dma_addr; + vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; + vsp_cmd.sub_data.kern.side = (u64)dp->data; + vsp_cmd.sub_data.kern.offset = *ppos; + vsp_cmd.sub_data.kern.length = count; + mb(); + rc = signal_vsp_instruction(&vsp_cmd); + if (rc) + goto out_free; + rc = -ENOMEM; + if (vsp_cmd.result_code != 0) + goto out_free; + + *ppos += count; + rc = count; +out_free: + iseries_hv_free(count, page, dma_addr); +out: + return rc; +} + +static const struct file_operations proc_vmlinux_operations = { + .write = proc_mf_change_vmlinux, + .llseek = default_llseek, +}; + +static int __init mf_proc_init(void) +{ + struct proc_dir_entry *mf_proc_root; + struct proc_dir_entry *ent; + struct proc_dir_entry *mf; + char name[2]; + int i; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return 0; + + mf_proc_root = proc_mkdir("iSeries/mf", NULL); + if (!mf_proc_root) + return 1; + + name[1] = '\0'; + for (i = 0; i < 4; i++) { + name[0] = 'A' + i; + mf = proc_mkdir(name, mf_proc_root); + if (!mf) + return 1; + + ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf, + &mf_cmdline_proc_fops, (void *)(long)i); + if (!ent) + return 1; + + if (i == 3) /* no vmlinux entry for 'D' */ + continue; + + ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf, + &proc_vmlinux_operations, + (void *)(long)i); + if (!ent) + return 1; + } + + ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, + &mf_side_proc_fops); + if (!ent) + return 1; + + ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, + &mf_src_proc_fops); + if (!ent) + return 1; + + return 0; +} + +__initcall(mf_proc_init); + +#endif /* CONFIG_PROC_FS */ + +/* + * Get the RTC from the virtual service processor + * This requires flowing LpEvents to the primary partition + */ +void iSeries_get_rtc_time(struct rtc_time *rtc_tm) +{ + mf_get_rtc(rtc_tm); + rtc_tm->tm_mon--; +} + +/* + * Set the RTC in the virtual service processor + * This requires flowing LpEvents to the primary partition + */ +int iSeries_set_rtc_time(struct rtc_time *tm) +{ + mf_set_rtc(tm); + return 0; +} + +unsigned long iSeries_get_boot_time(void) +{ + struct rtc_time tm; + + mf_get_boot_rtc(&tm); + return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +} diff --git a/trunk/arch/powerpc/platforms/iseries/misc.S b/trunk/arch/powerpc/platforms/iseries/misc.S new file mode 100644 index 000000000000..2c6ff0fdac98 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/misc.S @@ -0,0 +1,26 @@ +/* + * This file contains miscellaneous low-level functions. + * Copyright (C) 1995-2005 IBM Corp + * + * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras. + * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) + * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include + + .text + +/* Handle pending interrupts in interrupt context */ +_GLOBAL(iseries_handle_interrupts) + li r0,0x5555 + sc + blr diff --git a/trunk/arch/powerpc/platforms/iseries/naca.h b/trunk/arch/powerpc/platforms/iseries/naca.h new file mode 100644 index 000000000000..f01708e12862 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/naca.h @@ -0,0 +1,24 @@ +#ifndef _PLATFORMS_ISERIES_NACA_H +#define _PLATFORMS_ISERIES_NACA_H + +/* + * c 2001 PPC 64 Team, IBM Corp + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include + +struct naca_struct { + /* Kernel only data - undefined for user space */ + const void *xItVpdAreas; /* VPD Data 0x00 */ + void *xRamDisk; /* iSeries ramdisk 0x08 */ + u64 xRamDiskSize; /* In pages 0x10 */ +}; + +extern struct naca_struct naca; + +#endif /* _PLATFORMS_ISERIES_NACA_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/pci.c b/trunk/arch/powerpc/platforms/iseries/pci.c new file mode 100644 index 000000000000..c75412884625 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/pci.c @@ -0,0 +1,919 @@ +/* + * Copyright (C) 2001 Allan Trautman, IBM Corporation + * Copyright (C) 2005,2007 Stephen Rothwell, IBM Corp + * + * iSeries specific routines for PCI. + * + * Based on code from pci.c and iSeries_pci.c 32bit + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "irq.h" +#include "pci.h" +#include "call_pci.h" + +#define PCI_RETRY_MAX 3 +static int limit_pci_retries = 1; /* Set Retry Error on. */ + +/* + * Table defines + * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. + */ +#define IOMM_TABLE_MAX_ENTRIES 1024 +#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL +#define BASE_IO_MEMORY 0xE000000000000000UL +#define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL + +static unsigned long max_io_memory = BASE_IO_MEMORY; +static long current_iomm_table_entry; + +/* + * Lookup Tables. + */ +static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES]; +static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES]; + +static DEFINE_SPINLOCK(iomm_table_lock); + +/* + * Generate a Direct Select Address for the Hypervisor + */ +static inline u64 iseries_ds_addr(struct device_node *node) +{ + struct pci_dn *pdn = PCI_DN(node); + const u32 *sbp = of_get_property(node, "linux,subbus", NULL); + + return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40) + + ((u64)0x10 << 32); +} + +/* + * Size of Bus VPD data + */ +#define BUS_VPDSIZE 1024 + +/* + * Bus Vpd Tags + */ +#define VPD_END_OF_AREA 0x79 +#define VPD_ID_STRING 0x82 +#define VPD_VENDOR_AREA 0x84 + +/* + * Mfg Area Tags + */ +#define VPD_FRU_FRAME_ID 0x4649 /* "FI" */ +#define VPD_SLOT_MAP_FORMAT 0x4D46 /* "MF" */ +#define VPD_SLOT_MAP 0x534D /* "SM" */ + +/* + * Structures of the areas + */ +struct mfg_vpd_area { + u16 tag; + u8 length; + u8 data1; + u8 data2; +}; +#define MFG_ENTRY_SIZE 3 + +struct slot_map { + u8 agent; + u8 secondary_agent; + u8 phb; + char card_location[3]; + char parms[8]; + char reserved[2]; +}; +#define SLOT_ENTRY_SIZE 16 + +/* + * Parse the Slot Area + */ +static void __init iseries_parse_slot_area(struct slot_map *map, int len, + HvAgentId agent, u8 *phb, char card[4]) +{ + /* + * Parse Slot label until we find the one requested + */ + while (len > 0) { + if (map->agent == agent) { + /* + * If Phb wasn't found, grab the entry first one found. + */ + if (*phb == 0xff) + *phb = map->phb; + /* Found it, extract the data. */ + if (map->phb == *phb) { + memcpy(card, &map->card_location, 3); + card[3] = 0; + break; + } + } + /* Point to the next Slot */ + map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE); + len -= SLOT_ENTRY_SIZE; + } +} + +/* + * Parse the Mfg Area + */ +static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len, + HvAgentId agent, u8 *phb, u8 *frame, char card[4]) +{ + u16 slot_map_fmt = 0; + + /* Parse Mfg Data */ + while (len > 0) { + int mfg_tag_len = area->length; + /* Frame ID (FI 4649020310 ) */ + if (area->tag == VPD_FRU_FRAME_ID) + *frame = area->data1; + /* Slot Map Format (MF 4D46020004 ) */ + else if (area->tag == VPD_SLOT_MAP_FORMAT) + slot_map_fmt = (area->data1 * 256) + + area->data2; + /* Slot Map (SM 534D90 */ + else if (area->tag == VPD_SLOT_MAP) { + struct slot_map *slot_map; + + if (slot_map_fmt == 0x1004) + slot_map = (struct slot_map *)((char *)area + + MFG_ENTRY_SIZE + 1); + else + slot_map = (struct slot_map *)((char *)area + + MFG_ENTRY_SIZE); + iseries_parse_slot_area(slot_map, mfg_tag_len, + agent, phb, card); + } + /* + * Point to the next Mfg Area + * Use defined size, sizeof give wrong answer + */ + area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len + + MFG_ENTRY_SIZE); + len -= (mfg_tag_len + MFG_ENTRY_SIZE); + } +} + +/* + * Look for "BUS".. Data is not Null terminated. + * PHBID of 0xFF indicates PHB was not found in VPD Data. + */ +static u8 __init iseries_parse_phbid(u8 *area, int len) +{ + while (len > 0) { + if ((*area == 'B') && (*(area + 1) == 'U') + && (*(area + 2) == 'S')) { + area += 3; + while (*area == ' ') + area++; + return *area & 0x0F; + } + area++; + len--; + } + return 0xff; +} + +/* + * Parse out the VPD Areas + */ +static void __init iseries_parse_vpd(u8 *data, int data_len, + HvAgentId agent, u8 *frame, char card[4]) +{ + u8 phb = 0xff; + + while (data_len > 0) { + int len; + u8 tag = *data; + + if (tag == VPD_END_OF_AREA) + break; + len = *(data + 1) + (*(data + 2) * 256); + data += 3; + data_len -= 3; + if (tag == VPD_ID_STRING) + phb = iseries_parse_phbid(data, len); + else if (tag == VPD_VENDOR_AREA) + iseries_parse_mfg_area((struct mfg_vpd_area *)data, len, + agent, &phb, frame, card); + /* Point to next Area. */ + data += len; + data_len -= len; + } +} + +static int __init iseries_get_location_code(u16 bus, HvAgentId agent, + u8 *frame, char card[4]) +{ + int status = 0; + int bus_vpd_len = 0; + u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL); + + if (bus_vpd == NULL) { + printk("PCI: Bus VPD Buffer allocation failure.\n"); + return 0; + } + bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd), + BUS_VPDSIZE); + if (bus_vpd_len == 0) { + printk("PCI: Bus VPD Buffer zero length.\n"); + goto out_free; + } + /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */ + /* Make sure this is what I think it is */ + if (*bus_vpd != VPD_ID_STRING) { + printk("PCI: Bus VPD Buffer missing starting tag.\n"); + goto out_free; + } + iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card); + status = 1; +out_free: + kfree(bus_vpd); + return status; +} + +/* + * Prints the device information. + * - Pass in pci_dev* pointer to the device. + * - Pass in the device count + * + * Format: + * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet + * controller + */ +static void __init iseries_device_information(struct pci_dev *pdev, + u16 bus, HvSubBusNumber subbus) +{ + u8 frame = 0; + char card[4]; + HvAgentId agent; + + agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), + ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); + + if (iseries_get_location_code(bus, agent, &frame, card)) { + printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, " + "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor, + frame, card, (int)(pdev->class >> 8)); + } +} + +/* + * iomm_table_allocate_entry + * + * Adds pci_dev entry in address translation table + * + * - Allocates the number of entries required in table base on BAR + * size. + * - Allocates starting at BASE_IO_MEMORY and increases. + * - The size is round up to be a multiple of entry size. + * - CurrentIndex is incremented to keep track of the last entry. + * - Builds the resource entry for allocated BARs. + */ +static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) +{ + struct resource *bar_res = &dev->resource[bar_num]; + long bar_size = pci_resource_len(dev, bar_num); + struct device_node *dn = pci_device_to_OF_node(dev); + + /* + * No space to allocate, quick exit, skip Allocation. + */ + if (bar_size == 0) + return; + /* + * Set Resource values. + */ + spin_lock(&iomm_table_lock); + bar_res->start = BASE_IO_MEMORY + + IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; + bar_res->end = bar_res->start + bar_size - 1; + /* + * Allocate the number of table entries needed for BAR. + */ + while (bar_size > 0 ) { + iomm_table[current_iomm_table_entry] = dn; + ds_addr_table[current_iomm_table_entry] = + iseries_ds_addr(dn) | (bar_num << 24); + bar_size -= IOMM_TABLE_ENTRY_SIZE; + ++current_iomm_table_entry; + } + max_io_memory = BASE_IO_MEMORY + + IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; + spin_unlock(&iomm_table_lock); +} + +/* + * allocate_device_bars + * + * - Allocates ALL pci_dev BAR's and updates the resources with the + * BAR value. BARS with zero length will have the resources + * The HvCallPci_getBarParms is used to get the size of the BAR + * space. It calls iomm_table_allocate_entry to allocate + * each entry. + * - Loops through The Bar resources(0 - 5) including the ROM + * is resource(6). + */ +static void __init allocate_device_bars(struct pci_dev *dev) +{ + int bar_num; + + for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) + iomm_table_allocate_entry(dev, bar_num); +} + +/* + * Log error information to system console. + * Filter out the device not there errors. + * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx + * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx + * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx + */ +static void pci_log_error(char *error, int bus, int subbus, + int agent, int hv_res) +{ + if (hv_res == 0x0302) + return; + printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X", + error, bus, subbus, agent, hv_res); +} + +/* + * Look down the chain to find the matching Device Device + */ +static struct device_node *find_device_node(int bus, int devfn) +{ + struct device_node *node; + + for (node = NULL; (node = of_find_all_nodes(node)); ) { + struct pci_dn *pdn = PCI_DN(node); + + if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn)) + return node; + } + return NULL; +} + +/* + * iSeries_pcibios_fixup_resources + * + * Fixes up all resources for devices + */ +void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev) +{ + const u32 *agent; + const u32 *sub_bus; + unsigned char bus = pdev->bus->number; + struct device_node *node; + int i; + + node = pci_device_to_OF_node(pdev); + pr_debug("PCI: iSeries %s, pdev %p, node %p\n", + pci_name(pdev), pdev, node); + if (!node) { + printk("PCI: %s disabled, device tree entry not found !\n", + pci_name(pdev)); + for (i = 0; i <= PCI_ROM_RESOURCE; i++) + pdev->resource[i].flags = 0; + return; + } + sub_bus = of_get_property(node, "linux,subbus", NULL); + agent = of_get_property(node, "linux,agent-id", NULL); + if (agent && sub_bus) { + u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus); + int err; + + err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq); + if (err) + pci_log_error("Connect Bus Unit", + bus, *sub_bus, *agent, err); + else { + err = HvCallPci_configStore8(bus, *sub_bus, + *agent, PCI_INTERRUPT_LINE, irq); + if (err) + pci_log_error("PciCfgStore Irq Failed!", + bus, *sub_bus, *agent, err); + else + pdev->irq = irq; + } + } + + allocate_device_bars(pdev); + if (likely(sub_bus)) + iseries_device_information(pdev, bus, *sub_bus); + else + printk(KERN_ERR "PCI: Device node %s has missing or invalid " + "linux,subbus property\n", node->full_name); +} + +/* + * iSeries_pci_final_fixup(void) + */ +void __init iSeries_pci_final_fixup(void) +{ + /* Fix up at the device node and pci_dev relationship */ + mf_display_src(0xC9000100); + iSeries_activate_IRQs(); + mf_display_src(0xC9000200); +} + +/* + * Config space read and write functions. + * For now at least, we look for the device node for the bus and devfn + * that we are asked to access. It may be possible to translate the devfn + * to a subbus and deviceid more directly. + */ +static u64 hv_cfg_read_func[4] = { + HvCallPciConfigLoad8, HvCallPciConfigLoad16, + HvCallPciConfigLoad32, HvCallPciConfigLoad32 +}; + +static u64 hv_cfg_write_func[4] = { + HvCallPciConfigStore8, HvCallPciConfigStore16, + HvCallPciConfigStore32, HvCallPciConfigStore32 +}; + +/* + * Read PCI config space + */ +static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, + int offset, int size, u32 *val) +{ + struct device_node *node = find_device_node(bus->number, devfn); + u64 fn; + struct HvCallPci_LoadReturn ret; + + if (node == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset > 255) { + *val = ~0; + return PCIBIOS_BAD_REGISTER_NUMBER; + } + + fn = hv_cfg_read_func[(size - 1) & 3]; + HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0); + + if (ret.rc != 0) { + *val = ~0; + return PCIBIOS_DEVICE_NOT_FOUND; /* or something */ + } + + *val = ret.value; + return 0; +} + +/* + * Write PCI config space + */ + +static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, + int offset, int size, u32 val) +{ + struct device_node *node = find_device_node(bus->number, devfn); + u64 fn; + u64 ret; + + if (node == NULL) + return PCIBIOS_DEVICE_NOT_FOUND; + if (offset > 255) + return PCIBIOS_BAD_REGISTER_NUMBER; + + fn = hv_cfg_write_func[(size - 1) & 3]; + ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0); + + if (ret != 0) + return PCIBIOS_DEVICE_NOT_FOUND; + + return 0; +} + +static struct pci_ops iSeries_pci_ops = { + .read = iSeries_pci_read_config, + .write = iSeries_pci_write_config +}; + +/* + * Check Return Code + * -> On Failure, print and log information. + * Increment Retry Count, if exceeds max, panic partition. + * + * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234 + * PCI: Device 23.90 ReadL Retry( 1) + * PCI: Device 23.90 ReadL Retry Successful(1) + */ +static int check_return_code(char *type, struct device_node *dn, + int *retry, u64 ret) +{ + if (ret != 0) { + struct pci_dn *pdn = PCI_DN(dn); + + (*retry)++; + printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", + type, pdn->busno, pdn->devfn, + *retry, (int)ret); + /* + * Bump the retry and check for retry count exceeded. + * If, Exceeded, panic the system. + */ + if (((*retry) > PCI_RETRY_MAX) && + (limit_pci_retries > 0)) { + mf_display_src(0xB6000103); + panic_timeout = 0; + panic("PCI: Hardware I/O Error, SRC B6000103, " + "Automatic Reboot Disabled.\n"); + } + return -1; /* Retry Try */ + } + return 0; +} + +/* + * Translate the I/O Address into a device node, bar, and bar offset. + * Note: Make sure the passed variable end up on the stack to avoid + * the exposure of being device global. + */ +static inline struct device_node *xlate_iomm_address( + const volatile void __iomem *addr, + u64 *dsaptr, u64 *bar_offset, const char *func) +{ + unsigned long orig_addr; + unsigned long base_addr; + unsigned long ind; + struct device_node *dn; + + orig_addr = (unsigned long __force)addr; + if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) { + static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10); + + if (__ratelimit(&ratelimit)) + printk(KERN_ERR + "iSeries_%s: invalid access at IO address %p\n", + func, addr); + return NULL; + } + base_addr = orig_addr - BASE_IO_MEMORY; + ind = base_addr / IOMM_TABLE_ENTRY_SIZE; + dn = iomm_table[ind]; + + if (dn != NULL) { + *dsaptr = ds_addr_table[ind]; + *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE; + } else + panic("PCI: Invalid PCI IO address detected!\n"); + return dn; +} + +/* + * Read MM I/O Instructions for the iSeries + * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal + * else, data is returned in Big Endian format. + */ +static u8 iseries_readb(const volatile void __iomem *addr) +{ + u64 bar_offset; + u64 dsa; + int retry = 0; + struct HvCallPci_LoadReturn ret; + struct device_node *dn = + xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte"); + + if (dn == NULL) + return 0xff; + do { + HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0); + } while (check_return_code("RDB", dn, &retry, ret.rc) != 0); + + return ret.value; +} + +static u16 iseries_readw_be(const volatile void __iomem *addr) +{ + u64 bar_offset; + u64 dsa; + int retry = 0; + struct HvCallPci_LoadReturn ret; + struct device_node *dn = + xlate_iomm_address(addr, &dsa, &bar_offset, "read_word"); + + if (dn == NULL) + return 0xffff; + do { + HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, + bar_offset, 0); + } while (check_return_code("RDW", dn, &retry, ret.rc) != 0); + + return ret.value; +} + +static u32 iseries_readl_be(const volatile void __iomem *addr) +{ + u64 bar_offset; + u64 dsa; + int retry = 0; + struct HvCallPci_LoadReturn ret; + struct device_node *dn = + xlate_iomm_address(addr, &dsa, &bar_offset, "read_long"); + + if (dn == NULL) + return 0xffffffff; + do { + HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, + bar_offset, 0); + } while (check_return_code("RDL", dn, &retry, ret.rc) != 0); + + return ret.value; +} + +/* + * Write MM I/O Instructions for the iSeries + * + */ +static void iseries_writeb(u8 data, volatile void __iomem *addr) +{ + u64 bar_offset; + u64 dsa; + int retry = 0; + u64 rc; + struct device_node *dn = + xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte"); + + if (dn == NULL) + return; + do { + rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0); + } while (check_return_code("WWB", dn, &retry, rc) != 0); +} + +static void iseries_writew_be(u16 data, volatile void __iomem *addr) +{ + u64 bar_offset; + u64 dsa; + int retry = 0; + u64 rc; + struct device_node *dn = + xlate_iomm_address(addr, &dsa, &bar_offset, "write_word"); + + if (dn == NULL) + return; + do { + rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0); + } while (check_return_code("WWW", dn, &retry, rc) != 0); +} + +static void iseries_writel_be(u32 data, volatile void __iomem *addr) +{ + u64 bar_offset; + u64 dsa; + int retry = 0; + u64 rc; + struct device_node *dn = + xlate_iomm_address(addr, &dsa, &bar_offset, "write_long"); + + if (dn == NULL) + return; + do { + rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0); + } while (check_return_code("WWL", dn, &retry, rc) != 0); +} + +static u16 iseries_readw(const volatile void __iomem *addr) +{ + return le16_to_cpu(iseries_readw_be(addr)); +} + +static u32 iseries_readl(const volatile void __iomem *addr) +{ + return le32_to_cpu(iseries_readl_be(addr)); +} + +static void iseries_writew(u16 data, volatile void __iomem *addr) +{ + iseries_writew_be(cpu_to_le16(data), addr); +} + +static void iseries_writel(u32 data, volatile void __iomem *addr) +{ + iseries_writel(cpu_to_le32(data), addr); +} + +static void iseries_readsb(const volatile void __iomem *addr, void *buf, + unsigned long count) +{ + u8 *dst = buf; + while(count-- > 0) + *(dst++) = iseries_readb(addr); +} + +static void iseries_readsw(const volatile void __iomem *addr, void *buf, + unsigned long count) +{ + u16 *dst = buf; + while(count-- > 0) + *(dst++) = iseries_readw_be(addr); +} + +static void iseries_readsl(const volatile void __iomem *addr, void *buf, + unsigned long count) +{ + u32 *dst = buf; + while(count-- > 0) + *(dst++) = iseries_readl_be(addr); +} + +static void iseries_writesb(volatile void __iomem *addr, const void *buf, + unsigned long count) +{ + const u8 *src = buf; + while(count-- > 0) + iseries_writeb(*(src++), addr); +} + +static void iseries_writesw(volatile void __iomem *addr, const void *buf, + unsigned long count) +{ + const u16 *src = buf; + while(count-- > 0) + iseries_writew_be(*(src++), addr); +} + +static void iseries_writesl(volatile void __iomem *addr, const void *buf, + unsigned long count) +{ + const u32 *src = buf; + while(count-- > 0) + iseries_writel_be(*(src++), addr); +} + +static void iseries_memset_io(volatile void __iomem *addr, int c, + unsigned long n) +{ + volatile char __iomem *d = addr; + + while (n-- > 0) + iseries_writeb(c, d++); +} + +static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src, + unsigned long n) +{ + char *d = dest; + const volatile char __iomem *s = src; + + while (n-- > 0) + *d++ = iseries_readb(s++); +} + +static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src, + unsigned long n) +{ + const char *s = src; + volatile char __iomem *d = dest; + + while (n-- > 0) + iseries_writeb(*s++, d++); +} + +/* We only set MMIO ops. The default PIO ops will be default + * to the MMIO ops + pci_io_base which is 0 on iSeries as + * expected so both should work. + * + * Note that we don't implement the readq/writeq versions as + * I don't know of an HV call for doing so. Thus, the default + * operation will be used instead, which will fault a the value + * return by iSeries for MMIO addresses always hits a non mapped + * area. This is as good as the BUG() we used to have there. + */ +static struct ppc_pci_io __initdata iseries_pci_io = { + .readb = iseries_readb, + .readw = iseries_readw, + .readl = iseries_readl, + .readw_be = iseries_readw_be, + .readl_be = iseries_readl_be, + .writeb = iseries_writeb, + .writew = iseries_writew, + .writel = iseries_writel, + .writew_be = iseries_writew_be, + .writel_be = iseries_writel_be, + .readsb = iseries_readsb, + .readsw = iseries_readsw, + .readsl = iseries_readsl, + .writesb = iseries_writesb, + .writesw = iseries_writesw, + .writesl = iseries_writesl, + .memset_io = iseries_memset_io, + .memcpy_fromio = iseries_memcpy_fromio, + .memcpy_toio = iseries_memcpy_toio, +}; + +/* + * iSeries_pcibios_init + * + * Description: + * This function checks for all possible system PCI host bridges that connect + * PCI buses. The system hypervisor is queried as to the guest partition + * ownership status. A pci_controller is built for any bus which is partially + * owned or fully owned by this guest partition. + */ +void __init iSeries_pcibios_init(void) +{ + struct pci_controller *phb; + struct device_node *root = of_find_node_by_path("/"); + struct device_node *node = NULL; + + /* Install IO hooks */ + ppc_pci_io = iseries_pci_io; + + pci_probe_only = 1; + + /* iSeries has no IO space in the common sense, it needs to set + * the IO base to 0 + */ + pci_io_base = 0; + + if (root == NULL) { + printk(KERN_CRIT "iSeries_pcibios_init: can't find root " + "of device tree\n"); + return; + } + while ((node = of_get_next_child(root, node)) != NULL) { + HvBusNumber bus; + const u32 *busp; + + if ((node->type == NULL) || (strcmp(node->type, "pci") != 0)) + continue; + + busp = of_get_property(node, "bus-range", NULL); + if (busp == NULL) + continue; + bus = *busp; + printk("bus %d appears to exist\n", bus); + phb = pcibios_alloc_controller(node); + if (phb == NULL) + continue; + /* All legacy iSeries PHBs are in domain zero */ + phb->global_number = 0; + + phb->first_busno = bus; + phb->last_busno = bus; + phb->ops = &iSeries_pci_ops; + phb->io_base_virt = (void __iomem *)_IO_BASE; + phb->io_resource.flags = IORESOURCE_IO; + phb->io_resource.start = BASE_IO_MEMORY; + phb->io_resource.end = END_IO_MEMORY; + phb->io_resource.name = "iSeries PCI IO"; + phb->mem_resources[0].flags = IORESOURCE_MEM; + phb->mem_resources[0].start = BASE_IO_MEMORY; + phb->mem_resources[0].end = END_IO_MEMORY; + phb->mem_resources[0].name = "Series PCI MEM"; + } + + of_node_put(root); + + pci_devs_phb_init(); +} + diff --git a/trunk/arch/powerpc/platforms/iseries/pci.h b/trunk/arch/powerpc/platforms/iseries/pci.h new file mode 100644 index 000000000000..d9cf974c2718 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/pci.h @@ -0,0 +1,58 @@ +#ifndef _PLATFORMS_ISERIES_PCI_H +#define _PLATFORMS_ISERIES_PCI_H + +/* + * Created by Allan Trautman on Tue Feb 20, 2001. + * + * Define some useful macros for the iSeries pci routines. + * Copyright (C) 2001 Allan H Trautman, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, + * Boston, MA 02111-1307 USA + * + * Change Activity: + * Created Feb 20, 2001 + * Added device reset, March 22, 2001 + * Ported to ppc64, May 25, 2001 + * End Change Activity + */ + +/* + * Decodes Linux DevFn to iSeries DevFn, bridge device, or function. + * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h + */ + +#define ISERIES_PCI_AGENTID(idsel, func) \ + (((idsel & 0x0F) << 4) | (func & 0x07)) +#define ISERIES_ENCODE_DEVICE(agentid) \ + ((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07)) + +#define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) +#define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) + +struct pci_dev; + +#ifdef CONFIG_PCI +extern void iSeries_pcibios_init(void); +extern void iSeries_pci_final_fixup(void); +extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev); +#else +static inline void iSeries_pcibios_init(void) { } +static inline void iSeries_pci_final_fixup(void) { } +static inline void iSeries_pcibios_fixup_resources(struct pci_dev *dev) {} +#endif + +#endif /* _PLATFORMS_ISERIES_PCI_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/proc.c b/trunk/arch/powerpc/platforms/iseries/proc.c new file mode 100644 index 000000000000..06763682db47 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/proc.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2001 Kyle A. Lucke IBM Corporation + * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include /* for HZ */ +#include +#include +#include +#include +#include +#include + +#include "processor_vpd.h" +#include "main_store.h" + +static int __init iseries_proc_create(void) +{ + struct proc_dir_entry *e; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return 0; + + e = proc_mkdir("iSeries", 0); + if (!e) + return 1; + + return 0; +} +core_initcall(iseries_proc_create); + +static unsigned long startTitan = 0; +static unsigned long startTb = 0; + +static int proc_titantod_show(struct seq_file *m, void *v) +{ + unsigned long tb0, titan_tod; + + tb0 = get_tb(); + titan_tod = HvCallXm_loadTod(); + + seq_printf(m, "Titan\n" ); + seq_printf(m, " time base = %016lx\n", tb0); + seq_printf(m, " titan tod = %016lx\n", titan_tod); + seq_printf(m, " xProcFreq = %016x\n", + xIoHriProcessorVpd[0].xProcFreq); + seq_printf(m, " xTimeBaseFreq = %016x\n", + xIoHriProcessorVpd[0].xTimeBaseFreq); + seq_printf(m, " tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy); + seq_printf(m, " tb_ticks_per_usec = %lu\n", tb_ticks_per_usec); + + if (!startTitan) { + startTitan = titan_tod; + startTb = tb0; + } else { + unsigned long titan_usec = (titan_tod - startTitan) >> 12; + unsigned long tb_ticks = (tb0 - startTb); + unsigned long titan_jiffies = titan_usec / (1000000/HZ); + unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ); + unsigned long titan_jiff_rem_usec = + titan_usec - titan_jiff_usec; + unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy; + unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy; + unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks; + unsigned long tb_jiff_rem_usec = + tb_jiff_rem_ticks / tb_ticks_per_usec; + unsigned long new_tb_ticks_per_jiffy = + (tb_ticks * (1000000/HZ))/titan_usec; + + seq_printf(m, " titan elapsed = %lu uSec\n", titan_usec); + seq_printf(m, " tb elapsed = %lu ticks\n", tb_ticks); + seq_printf(m, " titan jiffies = %lu.%04lu\n", titan_jiffies, + titan_jiff_rem_usec); + seq_printf(m, " tb jiffies = %lu.%04lu\n", tb_jiffies, + tb_jiff_rem_usec); + seq_printf(m, " new tb_ticks_per_jiffy = %lu\n", + new_tb_ticks_per_jiffy); + } + + return 0; +} + +static int proc_titantod_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_titantod_show, NULL); +} + +static const struct file_operations proc_titantod_operations = { + .open = proc_titantod_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init iseries_proc_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return 0; + + proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL, + &proc_titantod_operations); + return 0; +} +__initcall(iseries_proc_init); diff --git a/trunk/arch/powerpc/platforms/iseries/processor_vpd.h b/trunk/arch/powerpc/platforms/iseries/processor_vpd.h new file mode 100644 index 000000000000..7ac5d0d0dbfa --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/processor_vpd.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ISERIES_PROCESSOR_VPD_H +#define _ISERIES_PROCESSOR_VPD_H + +#include + +/* + * This struct maps Processor Vpd that is DMAd to SLIC by CSP + */ +struct IoHriProcessorVpd { + u8 xFormat; // VPD format indicator x00-x00 + u8 xProcStatus:8; // Processor State x01-x01 + u8 xSecondaryThreadCount; // Secondary thread cnt x02-x02 + u8 xSrcType:1; // Src Type x03-x03 + u8 xSrcSoft:1; // Src stay soft ... + u8 xSrcParable:1; // Src parable ... + u8 xRsvd1:5; // Reserved ... + u16 xHvPhysicalProcIndex; // Hypervisor physical proc index04-x05 + u16 xRsvd2; // Reserved x06-x07 + u32 xHwNodeId; // Hardware node id x08-x0B + u32 xHwProcId; // Hardware processor id x0C-x0F + + u32 xTypeNum; // Card Type/CCIN number x10-x13 + u32 xModelNum; // Model/Feature number x14-x17 + u64 xSerialNum; // Serial number x18-x1F + char xPartNum[12]; // Book Part or FPU number x20-x2B + char xMfgID[4]; // Manufacturing ID x2C-x2F + + u32 xProcFreq; // Processor Frequency x30-x33 + u32 xTimeBaseFreq; // Time Base Frequency x34-x37 + + u32 xChipEcLevel; // Chip EC Levels x38-x3B + u32 xProcIdReg; // PIR SPR value x3C-x3F + u32 xPVR; // PVR value x40-x43 + u8 xRsvd3[12]; // Reserved x44-x4F + + u32 xInstCacheSize; // Instruction cache size in KB x50-x53 + u32 xInstBlockSize; // Instruction cache block size x54-x57 + u32 xDataCacheOperandSize; // Data cache operand size x58-x5B + u32 xInstCacheOperandSize; // Inst cache operand size x5C-x5F + + u32 xDataL1CacheSizeKB; // L1 data cache size in KB x60-x63 + u32 xDataL1CacheLineSize; // L1 data cache block size x64-x67 + u64 xRsvd4; // Reserved x68-x6F + + u32 xDataL2CacheSizeKB; // L2 data cache size in KB x70-x73 + u32 xDataL2CacheLineSize; // L2 data cache block size x74-x77 + u64 xRsvd5; // Reserved x78-x7F + + u32 xDataL3CacheSizeKB; // L3 data cache size in KB x80-x83 + u32 xDataL3CacheLineSize; // L3 data cache block size x84-x87 + u64 xRsvd6; // Reserved x88-x8F + + u64 xFruLabel; // Card Location Label x90-x97 + u8 xSlotsOnCard; // Slots on card (0=no slots) x98-x98 + u8 xPartLocFlag; // Location flag (0-pluggable 1-imbedded) x99-x99 + u16 xSlotMapIndex; // Index in slot map table x9A-x9B + u8 xSmartCardPortNo; // Smart card port number x9C-x9C + u8 xRsvd7; // Reserved x9D-x9D + u16 xFrameIdAndRackUnit; // Frame ID and rack unit adr x9E-x9F + + u8 xRsvd8[24]; // Reserved xA0-xB7 + + char xProcSrc[72]; // CSP format SRC xB8-xFF +}; + +extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; + +#endif /* _ISERIES_PROCESSOR_VPD_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/release_data.h b/trunk/arch/powerpc/platforms/iseries/release_data.h new file mode 100644 index 000000000000..6ad7d843e8fc --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/release_data.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ISERIES_RELEASE_DATA_H +#define _ISERIES_RELEASE_DATA_H + +/* + * This control block contains the critical information about the + * release so that it can be changed in the future (ie, the virtual + * address of the OS's NACA). + */ +#include +#include "naca.h" + +/* + * When we IPL a secondary partition, we will check if if the + * secondary xMinPlicVrmIndex > the primary xVrmIndex. + * If it is then this tells PLIC that this secondary is not + * supported running on this "old" of a level of PLIC. + * + * Likewise, we will compare the primary xMinSlicVrmIndex to + * the secondary xVrmIndex. + * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we + * know that this PLIC does not support running an OS "that old". + */ + +#define HVREL_TAGSINACTIVE 0x8000 +#define HVREL_32BIT 0x4000 +#define HVREL_NOSHAREDPROCS 0x2000 +#define HVREL_NOHMT 0x1000 + +struct HvReleaseData { + u32 xDesc; /* Descriptor "HvRD" ebcdic x00-x03 */ + u16 xSize; /* Size of this control block x04-x05 */ + u16 xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */ + struct naca_struct *xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */ + u32 xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */ + u32 xRsvd1; /* Reserved x14-x17 */ + u16 xFlags; + u16 xVrmIndex; /* VRM Index of OS image x1A-x1B */ + u16 xMinSupportedPlicVrmIndex; /* Min PLIC level (soft) x1C-x1D */ + u16 xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */ + char xVrmName[12]; /* Displayable name x20-x2B */ + char xRsvd3[20]; /* Reserved x2C-x3F */ +}; + +extern const struct HvReleaseData hvReleaseData; + +#endif /* _ISERIES_RELEASE_DATA_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/setup.c b/trunk/arch/powerpc/platforms/iseries/setup.c new file mode 100644 index 000000000000..a5fbf4cb6329 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/setup.c @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2000 Mike Corrigan + * Copyright (c) 1999-2000 Grant Erickson + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM iSeries LPAR. Adapted from original code by Grant Erickson and + * code by Gary Thomas, Cort Dougan , and Dan Malek + * . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "naca.h" +#include "setup.h" +#include "irq.h" +#include "vpd_areas.h" +#include "processor_vpd.h" +#include "it_lp_naca.h" +#include "main_store.h" +#include "call_sm.h" +#include "call_hpt.h" +#include "pci.h" + +#ifdef DEBUG +#define DBG(fmt...) udbg_printf(fmt) +#else +#define DBG(fmt...) +#endif + +/* Function Prototypes */ +static unsigned long build_iSeries_Memory_Map(void); +static void iseries_shared_idle(void); +static void iseries_dedicated_idle(void); + + +struct MemoryBlock { + unsigned long absStart; + unsigned long absEnd; + unsigned long logicalStart; + unsigned long logicalEnd; +}; + +/* + * Process the main store vpd to determine where the holes in memory are + * and return the number of physical blocks and fill in the array of + * block data. + */ +static unsigned long iSeries_process_Condor_mainstore_vpd( + struct MemoryBlock *mb_array, unsigned long max_entries) +{ + unsigned long holeFirstChunk, holeSizeChunks; + unsigned long numMemoryBlocks = 1; + struct IoHriMainStoreSegment4 *msVpd = + (struct IoHriMainStoreSegment4 *)xMsVpd; + unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr; + unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr; + unsigned long holeSize = holeEnd - holeStart; + + printk("Mainstore_VPD: Condor\n"); + /* + * Determine if absolute memory has any + * holes so that we can interpret the + * access map we get back from the hypervisor + * correctly. + */ + mb_array[0].logicalStart = 0; + mb_array[0].logicalEnd = 0x100000000UL; + mb_array[0].absStart = 0; + mb_array[0].absEnd = 0x100000000UL; + + if (holeSize) { + numMemoryBlocks = 2; + holeStart = holeStart & 0x000fffffffffffffUL; + holeStart = addr_to_chunk(holeStart); + holeFirstChunk = holeStart; + holeSize = addr_to_chunk(holeSize); + holeSizeChunks = holeSize; + printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n", + holeFirstChunk, holeSizeChunks ); + mb_array[0].logicalEnd = holeFirstChunk; + mb_array[0].absEnd = holeFirstChunk; + mb_array[1].logicalStart = holeFirstChunk; + mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks; + mb_array[1].absStart = holeFirstChunk + holeSizeChunks; + mb_array[1].absEnd = 0x100000000UL; + } + return numMemoryBlocks; +} + +#define MaxSegmentAreas 32 +#define MaxSegmentAdrRangeBlocks 128 +#define MaxAreaRangeBlocks 4 + +static unsigned long iSeries_process_Regatta_mainstore_vpd( + struct MemoryBlock *mb_array, unsigned long max_entries) +{ + struct IoHriMainStoreSegment5 *msVpdP = + (struct IoHriMainStoreSegment5 *)xMsVpd; + unsigned long numSegmentBlocks = 0; + u32 existsBits = msVpdP->msAreaExists; + unsigned long area_num; + + printk("Mainstore_VPD: Regatta\n"); + + for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) { + unsigned long numAreaBlocks; + struct IoHriMainStoreArea4 *currentArea; + + if (existsBits & 0x80000000) { + unsigned long block_num; + + currentArea = &msVpdP->msAreaArray[area_num]; + numAreaBlocks = currentArea->numAdrRangeBlocks; + printk("ms_vpd: processing area %2ld blocks=%ld", + area_num, numAreaBlocks); + for (block_num = 0; block_num < numAreaBlocks; + ++block_num ) { + /* Process an address range block */ + struct MemoryBlock tempBlock; + unsigned long i; + + tempBlock.absStart = + (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart; + tempBlock.absEnd = + (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd; + tempBlock.logicalStart = 0; + tempBlock.logicalEnd = 0; + printk("\n block %ld absStart=%016lx absEnd=%016lx", + block_num, tempBlock.absStart, + tempBlock.absEnd); + + for (i = 0; i < numSegmentBlocks; ++i) { + if (mb_array[i].absStart == + tempBlock.absStart) + break; + } + if (i == numSegmentBlocks) { + if (numSegmentBlocks == max_entries) + panic("iSeries_process_mainstore_vpd: too many memory blocks"); + mb_array[numSegmentBlocks] = tempBlock; + ++numSegmentBlocks; + } else + printk(" (duplicate)"); + } + printk("\n"); + } + existsBits <<= 1; + } + /* Now sort the blocks found into ascending sequence */ + if (numSegmentBlocks > 1) { + unsigned long m, n; + + for (m = 0; m < numSegmentBlocks - 1; ++m) { + for (n = numSegmentBlocks - 1; m < n; --n) { + if (mb_array[n].absStart < + mb_array[n-1].absStart) { + struct MemoryBlock tempBlock; + + tempBlock = mb_array[n]; + mb_array[n] = mb_array[n-1]; + mb_array[n-1] = tempBlock; + } + } + } + } + /* + * Assign "logical" addresses to each block. These + * addresses correspond to the hypervisor "bitmap" space. + * Convert all addresses into units of 256K chunks. + */ + { + unsigned long i, nextBitmapAddress; + + printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks); + nextBitmapAddress = 0; + for (i = 0; i < numSegmentBlocks; ++i) { + unsigned long length = mb_array[i].absEnd - + mb_array[i].absStart; + + mb_array[i].logicalStart = nextBitmapAddress; + mb_array[i].logicalEnd = nextBitmapAddress + length; + nextBitmapAddress += length; + printk(" Bitmap range: %016lx - %016lx\n" + " Absolute range: %016lx - %016lx\n", + mb_array[i].logicalStart, + mb_array[i].logicalEnd, + mb_array[i].absStart, mb_array[i].absEnd); + mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart & + 0x000fffffffffffffUL); + mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd & + 0x000fffffffffffffUL); + mb_array[i].logicalStart = + addr_to_chunk(mb_array[i].logicalStart); + mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd); + } + } + + return numSegmentBlocks; +} + +static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, + unsigned long max_entries) +{ + unsigned long i; + unsigned long mem_blocks = 0; + + if (mmu_has_feature(MMU_FTR_SLB)) + mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, + max_entries); + else + mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array, + max_entries); + + printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks); + for (i = 0; i < mem_blocks; ++i) { + printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n" + " abs chunks %016lx - %016lx\n", + i, mb_array[i].logicalStart, mb_array[i].logicalEnd, + mb_array[i].absStart, mb_array[i].absEnd); + } + return mem_blocks; +} + +static void __init iSeries_get_cmdline(void) +{ + char *p, *q; + + /* copy the command line parameter from the primary VSP */ + HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256, + HvLpDma_Direction_RemoteToLocal); + + p = cmd_line; + q = cmd_line + 255; + while(p < q) { + if (!*p || *p == '\n') + break; + ++p; + } + *p = 0; +} + +static void __init iSeries_init_early(void) +{ + DBG(" -> iSeries_init_early()\n"); + + /* Snapshot the timebase, for use in later recalibration */ + iSeries_time_init_early(); + + /* + * Initialize the DMA/TCE management + */ + iommu_init_early_iSeries(); + + /* Initialize machine-dependency vectors */ +#ifdef CONFIG_SMP + smp_init_iSeries(); +#endif + + /* Associate Lp Event Queue 0 with processor 0 */ + HvCallEvent_setLpEventQueueInterruptProc(0, 0); + + mf_init(); + + DBG(" <- iSeries_init_early()\n"); +} + +struct mschunks_map mschunks_map = { + /* XXX We don't use these, but Piranha might need them. */ + .chunk_size = MSCHUNKS_CHUNK_SIZE, + .chunk_shift = MSCHUNKS_CHUNK_SHIFT, + .chunk_mask = MSCHUNKS_OFFSET_MASK, +}; +EXPORT_SYMBOL(mschunks_map); + +static void mschunks_alloc(unsigned long num_chunks) +{ + klimit = _ALIGN(klimit, sizeof(u32)); + mschunks_map.mapping = (u32 *)klimit; + klimit += num_chunks * sizeof(u32); + mschunks_map.num_chunks = num_chunks; +} + +/* + * The iSeries may have very large memories ( > 128 GB ) and a partition + * may get memory in "chunks" that may be anywhere in the 2**52 real + * address space. The chunks are 256K in size. To map this to the + * memory model Linux expects, the AS/400 specific code builds a + * translation table to translate what Linux thinks are "physical" + * addresses to the actual real addresses. This allows us to make + * it appear to Linux that we have contiguous memory starting at + * physical address zero while in fact this could be far from the truth. + * To avoid confusion, I'll let the words physical and/or real address + * apply to the Linux addresses while I'll use "absolute address" to + * refer to the actual hardware real address. + * + * build_iSeries_Memory_Map gets information from the Hypervisor and + * looks at the Main Store VPD to determine the absolute addresses + * of the memory that has been assigned to our partition and builds + * a table used to translate Linux's physical addresses to these + * absolute addresses. Absolute addresses are needed when + * communicating with the hypervisor (e.g. to build HPT entries) + * + * Returns the physical memory size + */ + +static unsigned long __init build_iSeries_Memory_Map(void) +{ + u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; + u32 nextPhysChunk; + u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages; + u32 totalChunks,moreChunks; + u32 currChunk, thisChunk, absChunk; + u32 currDword; + u32 chunkBit; + u64 map; + struct MemoryBlock mb[32]; + unsigned long numMemoryBlocks, curBlock; + + /* Chunk size on iSeries is 256K bytes */ + totalChunks = (u32)HvLpConfig_getMsChunks(); + mschunks_alloc(totalChunks); + + /* + * Get absolute address of our load area + * and map it to physical address 0 + * This guarantees that the loadarea ends up at physical 0 + * otherwise, it might not be returned by PLIC as the first + * chunks + */ + + loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr); + loadAreaSize = itLpNaca.xLoadAreaChunks; + + /* + * Only add the pages already mapped here. + * Otherwise we might add the hpt pages + * The rest of the pages of the load area + * aren't in the HPT yet and can still + * be assigned an arbitrary physical address + */ + if ((loadAreaSize * 64) > HvPagesToMap) + loadAreaSize = HvPagesToMap / 64; + + loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1; + + /* + * TODO Do we need to do something if the HPT is in the 64MB load area? + * This would be required if the itLpNaca.xLoadAreaChunks includes + * the HPT size + */ + + printk("Mapping load area - physical addr = 0000000000000000\n" + " absolute addr = %016lx\n", + chunk_to_addr(loadAreaFirstChunk)); + printk("Load area size %dK\n", loadAreaSize * 256); + + for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk) + mschunks_map.mapping[nextPhysChunk] = + loadAreaFirstChunk + nextPhysChunk; + + /* + * Get absolute address of our HPT and remember it so + * we won't map it to any physical address + */ + hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); + hptSizePages = (u32)HvCallHpt_getHptPages(); + hptSizeChunks = hptSizePages >> + (MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT); + hptLastChunk = hptFirstChunk + hptSizeChunks - 1; + + printk("HPT absolute addr = %016lx, size = %dK\n", + chunk_to_addr(hptFirstChunk), hptSizeChunks * 256); + + /* + * Determine if absolute memory has any + * holes so that we can interpret the + * access map we get back from the hypervisor + * correctly. + */ + numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32); + + /* + * Process the main store access map from the hypervisor + * to build up our physical -> absolute translation table + */ + curBlock = 0; + currChunk = 0; + currDword = 0; + moreChunks = totalChunks; + + while (moreChunks) { + map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex, + currDword); + thisChunk = currChunk; + while (map) { + chunkBit = map >> 63; + map <<= 1; + if (chunkBit) { + --moreChunks; + while (thisChunk >= mb[curBlock].logicalEnd) { + ++curBlock; + if (curBlock >= numMemoryBlocks) + panic("out of memory blocks"); + } + if (thisChunk < mb[curBlock].logicalStart) + panic("memory block error"); + + absChunk = mb[curBlock].absStart + + (thisChunk - mb[curBlock].logicalStart); + if (((absChunk < hptFirstChunk) || + (absChunk > hptLastChunk)) && + ((absChunk < loadAreaFirstChunk) || + (absChunk > loadAreaLastChunk))) { + mschunks_map.mapping[nextPhysChunk] = + absChunk; + ++nextPhysChunk; + } + } + ++thisChunk; + } + ++currDword; + currChunk += 64; + } + + /* + * main store size (in chunks) is + * totalChunks - hptSizeChunks + * which should be equal to + * nextPhysChunk + */ + return chunk_to_addr(nextPhysChunk); +} + +/* + * Document me. + */ +static void __init iSeries_setup_arch(void) +{ + if (get_lppaca()->shared_proc) { + ppc_md.idle_loop = iseries_shared_idle; + printk(KERN_DEBUG "Using shared processor idle loop\n"); + } else { + ppc_md.idle_loop = iseries_dedicated_idle; + printk(KERN_DEBUG "Using dedicated idle loop\n"); + } + + /* Setup the Lp Event Queue */ + setup_hvlpevent_queue(); + + printk("Max logical processors = %d\n", + itVpdAreas.xSlicMaxLogicalProcs); + printk("Max physical processors = %d\n", + itVpdAreas.xSlicMaxPhysicalProcs); + + iSeries_pcibios_init(); +} + +static void iSeries_show_cpuinfo(struct seq_file *m) +{ + seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n"); +} + +static void __init iSeries_progress(char * st, unsigned short code) +{ + printk("Progress: [%04x] - %s\n", (unsigned)code, st); + mf_display_progress(code); +} + +static void __init iSeries_fixup_klimit(void) +{ + /* + * Change klimit to take into account any ram disk + * that may be included + */ + if (naca.xRamDisk) + klimit = KERNELBASE + (u64)naca.xRamDisk + + (naca.xRamDiskSize * HW_PAGE_SIZE); +} + +static int __init iSeries_src_init(void) +{ + /* clear the progress line */ + if (firmware_has_feature(FW_FEATURE_ISERIES)) + ppc_md.progress(" ", 0xffff); + return 0; +} + +late_initcall(iSeries_src_init); + +static inline void process_iSeries_events(void) +{ + asm volatile ("li 0,0x5555; sc" : : : "r0", "r3"); +} + +static void yield_shared_processor(void) +{ + unsigned long tb; + + HvCall_setEnabledInterrupts(HvCall_MaskIPI | + HvCall_MaskLpEvent | + HvCall_MaskLpProd | + HvCall_MaskTimeout); + + tb = get_tb(); + /* Compute future tb value when yield should expire */ + HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy); + + /* + * The decrementer stops during the yield. Force a fake decrementer + * here and let the timer_interrupt code sort out the actual time. + */ + get_lppaca()->int_dword.fields.decr_int = 1; + ppc64_runlatch_on(); + process_iSeries_events(); +} + +static void iseries_shared_idle(void) +{ + while (1) { + tick_nohz_idle_enter(); + rcu_idle_enter(); + while (!need_resched() && !hvlpevent_is_pending()) { + local_irq_disable(); + ppc64_runlatch_off(); + + /* Recheck with irqs off */ + if (!need_resched() && !hvlpevent_is_pending()) + yield_shared_processor(); + + HMT_medium(); + local_irq_enable(); + } + + ppc64_runlatch_on(); + rcu_idle_exit(); + tick_nohz_idle_exit(); + + if (hvlpevent_is_pending()) + process_iSeries_events(); + + schedule_preempt_disabled(); + } +} + +static void iseries_dedicated_idle(void) +{ + set_thread_flag(TIF_POLLING_NRFLAG); + + while (1) { + tick_nohz_idle_enter(); + rcu_idle_enter(); + if (!need_resched()) { + while (!need_resched()) { + ppc64_runlatch_off(); + HMT_low(); + + if (hvlpevent_is_pending()) { + HMT_medium(); + ppc64_runlatch_on(); + process_iSeries_events(); + } + } + + HMT_medium(); + } + + ppc64_runlatch_on(); + rcu_idle_exit(); + tick_nohz_idle_exit(); + schedule_preempt_disabled(); + } +} + +static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size, + unsigned long flags, void *caller) +{ + return (void __iomem *)address; +} + +static void iseries_iounmap(volatile void __iomem *token) +{ +} + +static int __init iseries_probe(void) +{ + unsigned long root = of_get_flat_dt_root(); + if (!of_flat_dt_is_compatible(root, "IBM,iSeries")) + return 0; + + hpte_init_iSeries(); + /* iSeries does not support 16M pages */ + cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE; + + return 1; +} + +#ifdef CONFIG_KEXEC +static int iseries_kexec_prepare(struct kimage *image) +{ + return -ENOSYS; +} +#endif + +define_machine(iseries) { + .name = "iSeries", + .setup_arch = iSeries_setup_arch, + .show_cpuinfo = iSeries_show_cpuinfo, + .init_IRQ = iSeries_init_IRQ, + .get_irq = iSeries_get_irq, + .init_early = iSeries_init_early, + .pcibios_fixup = iSeries_pci_final_fixup, + .pcibios_fixup_resources= iSeries_pcibios_fixup_resources, + .restart = mf_reboot, + .power_off = mf_power_off, + .halt = mf_power_off, + .get_boot_time = iSeries_get_boot_time, + .set_rtc_time = iSeries_set_rtc_time, + .get_rtc_time = iSeries_get_rtc_time, + .calibrate_decr = generic_calibrate_decr, + .progress = iSeries_progress, + .probe = iseries_probe, + .ioremap = iseries_ioremap, + .iounmap = iseries_iounmap, +#ifdef CONFIG_KEXEC + .machine_kexec_prepare = iseries_kexec_prepare, +#endif + /* XXX Implement enable_pmcs for iSeries */ +}; + +void * __init iSeries_early_setup(void) +{ + unsigned long phys_mem_size; + + /* Identify CPU type. This is done again by the common code later + * on but calling this function multiple times is fine. + */ + identify_cpu(0, mfspr(SPRN_PVR)); + initialise_paca(&boot_paca, 0); + + powerpc_firmware_features |= FW_FEATURE_ISERIES; + powerpc_firmware_features |= FW_FEATURE_LPAR; + +#ifdef CONFIG_SMP + /* On iSeries we know we can never have more than 64 cpus */ + nr_cpu_ids = max(nr_cpu_ids, 64); +#endif + + iSeries_fixup_klimit(); + + /* + * Initialize the table which translate Linux physical addresses to + * AS/400 absolute addresses + */ + phys_mem_size = build_iSeries_Memory_Map(); + + iSeries_get_cmdline(); + + return (void *) __pa(build_flat_dt(phys_mem_size)); +} + +static void hvputc(char c) +{ + if (c == '\n') + hvputc('\r'); + + HvCall_writeLogBuffer(&c, 1); +} + +void __init udbg_init_iseries(void) +{ + udbg_putc = hvputc; +} diff --git a/trunk/arch/powerpc/platforms/iseries/setup.h b/trunk/arch/powerpc/platforms/iseries/setup.h new file mode 100644 index 000000000000..729754bbb018 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/setup.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2000 Mike Corrigan + * Copyright (c) 1999-2000 Grant Erickson + * + * Description: + * Architecture- / platform-specific boot-time initialization code for + * the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and + * code by Gary Thomas, Cort Dougan , and Dan Malek + * . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __ISERIES_SETUP_H__ +#define __ISERIES_SETUP_H__ + +extern void *iSeries_early_setup(void); +extern unsigned long iSeries_get_boot_time(void); +extern int iSeries_set_rtc_time(struct rtc_time *tm); +extern void iSeries_get_rtc_time(struct rtc_time *tm); + +extern void *build_flat_dt(unsigned long phys_mem_size); + +#endif /* __ISERIES_SETUP_H__ */ diff --git a/trunk/arch/powerpc/platforms/iseries/smp.c b/trunk/arch/powerpc/platforms/iseries/smp.c new file mode 100644 index 000000000000..02df49fb59f0 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/smp.c @@ -0,0 +1,88 @@ +/* + * SMP support for iSeries machines. + * + * Dave Engebretsen, Peter Bergner, and + * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com + * + * Plus various changes from other IBM teams... + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void smp_iSeries_cause_ipi(int cpu, unsigned long data) +{ + HvCall_sendIPI(&(paca[cpu])); +} + +static int smp_iSeries_probe(void) +{ + return cpumask_weight(cpu_possible_mask); +} + +static int smp_iSeries_kick_cpu(int nr) +{ + BUG_ON((nr < 0) || (nr >= NR_CPUS)); + + /* Verify that our partition has a processor nr */ + if (lppaca_of(nr).dyn_proc_status >= 2) + return -ENOENT; + + /* The processor is currently spinning, waiting + * for the cpu_start field to become non-zero + * After we set cpu_start, the processor will + * continue on to secondary_start in iSeries_head.S + */ + paca[nr].cpu_start = 1; + + return 0; +} + +static void __devinit smp_iSeries_setup_cpu(int nr) +{ +} + +static struct smp_ops_t iSeries_smp_ops = { + .message_pass = NULL, /* Use smp_muxed_ipi_message_pass */ + .cause_ipi = smp_iSeries_cause_ipi, + .probe = smp_iSeries_probe, + .kick_cpu = smp_iSeries_kick_cpu, + .setup_cpu = smp_iSeries_setup_cpu, +}; + +/* This is called very early. */ +void __init smp_init_iSeries(void) +{ + smp_ops = &iSeries_smp_ops; +} diff --git a/trunk/arch/powerpc/platforms/iseries/spcomm_area.h b/trunk/arch/powerpc/platforms/iseries/spcomm_area.h new file mode 100644 index 000000000000..598b7c14573a --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/spcomm_area.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _ISERIES_SPCOMM_AREA_H +#define _ISERIES_SPCOMM_AREA_H + + +struct SpCommArea { + u32 xDesc; // Descriptor (only in new formats) 000-003 + u8 xFormat; // Format (only in new formats) 004-004 + u8 xRsvd1[11]; // Reserved 005-00F + u64 xRawTbAtIplStart; // Raw HW TB value when IPL is started 010-017 + u64 xRawTodAtIplStart; // Raw HW TOD value when IPL is started 018-01F + u64 xBcdTimeAtIplStart; // BCD time when IPL is started 020-027 + u64 xBcdTimeAtOsStart; // BCD time when OS passed control 028-02F + u8 xRsvd2[80]; // Reserved 030-07F +}; + +#endif /* _ISERIES_SPCOMM_AREA_H */ diff --git a/trunk/arch/powerpc/platforms/iseries/vio.c b/trunk/arch/powerpc/platforms/iseries/vio.c new file mode 100644 index 000000000000..04be62d368a6 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/vio.c @@ -0,0 +1,556 @@ +/* + * Legacy iSeries specific vio initialisation + * that needs to be built in (not a module). + * + * © Copyright 2007 IBM Corporation + * Author: Stephen Rothwell + * Some parts collected from various other files + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define FIRST_VTY 0 +#define NUM_VTYS 1 +#define FIRST_VSCSI (FIRST_VTY + NUM_VTYS) +#define NUM_VSCSIS 1 +#define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS) +#define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS +#define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS) +#define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS +#define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS) +#define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS +#define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS) +#define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES + +struct vio_waitevent { + struct completion com; + int rc; + u16 sub_result; +}; + +struct vio_resource { + char rsrcname[10]; + char type[4]; + char model[3]; +}; + +static struct property *new_property(const char *name, int length, + const void *value) +{ + struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, + GFP_KERNEL); + + if (!np) + return NULL; + np->name = (char *)(np + 1); + np->value = np->name + strlen(name) + 1; + strcpy(np->name, name); + memcpy(np->value, value, length); + np->length = length; + return np; +} + +static void free_property(struct property *np) +{ + kfree(np); +} + +static struct device_node *new_node(const char *path, + struct device_node *parent) +{ + struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); + + if (!np) + return NULL; + np->full_name = kstrdup(path, GFP_KERNEL); + if (!np->full_name) { + kfree(np); + return NULL; + } + of_node_set_flag(np, OF_DYNAMIC); + kref_init(&np->kref); + np->parent = of_node_get(parent); + return np; +} + +static void free_node(struct device_node *np) +{ + struct property *next; + struct property *prop; + + next = np->properties; + while (next) { + prop = next; + next = prop->next; + free_property(prop); + } + of_node_put(np->parent); + kfree(np->full_name); + kfree(np); +} + +static int add_string_property(struct device_node *np, const char *name, + const char *value) +{ + struct property *nprop = new_property(name, strlen(value) + 1, value); + + if (!nprop) + return 0; + prom_add_property(np, nprop); + return 1; +} + +static int add_raw_property(struct device_node *np, const char *name, + int length, const void *value) +{ + struct property *nprop = new_property(name, length, value); + + if (!nprop) + return 0; + prom_add_property(np, nprop); + return 1; +} + +static struct device_node *do_device_node(struct device_node *parent, + const char *name, u32 reg, u32 unit, const char *type, + const char *compat, struct vio_resource *res) +{ + struct device_node *np; + char path[32]; + + snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg); + np = new_node(path, parent); + if (!np) + return NULL; + if (!add_string_property(np, "name", name) || + !add_string_property(np, "device_type", type) || + !add_string_property(np, "compatible", compat) || + !add_raw_property(np, "reg", sizeof(reg), ®) || + !add_raw_property(np, "linux,unit_address", + sizeof(unit), &unit)) { + goto node_free; + } + if (res) { + if (!add_raw_property(np, "linux,vio_rsrcname", + sizeof(res->rsrcname), res->rsrcname) || + !add_raw_property(np, "linux,vio_type", + sizeof(res->type), res->type) || + !add_raw_property(np, "linux,vio_model", + sizeof(res->model), res->model)) + goto node_free; + } + np->name = of_get_property(np, "name", NULL); + np->type = of_get_property(np, "device_type", NULL); + of_attach_node(np); +#ifdef CONFIG_PROC_DEVICETREE + if (parent->pde) { + struct proc_dir_entry *ent; + + ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde); + if (ent) + proc_device_tree_add_node(np, ent); + } +#endif + return np; + + node_free: + free_node(np); + return NULL; +} + +/* + * This is here so that we can dynamically add viodasd + * devices without exposing all the above infrastructure. + */ +struct vio_dev *vio_create_viodasd(u32 unit) +{ + struct device_node *vio_root; + struct device_node *np; + struct vio_dev *vdev = NULL; + + vio_root = of_find_node_by_path("/vdevice"); + if (!vio_root) + return NULL; + np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, + "block", "IBM,iSeries-viodasd", NULL); + of_node_put(vio_root); + if (np) { + vdev = vio_register_device_node(np); + if (!vdev) + free_node(np); + } + return vdev; +} +EXPORT_SYMBOL_GPL(vio_create_viodasd); + +static void __init handle_block_event(struct HvLpEvent *event) +{ + struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; + struct vio_waitevent *pwe; + + if (event == NULL) + /* Notification that a partition went away! */ + return; + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + printk(KERN_WARNING "handle_viod_request: " + "Yikes! got an int in viodasd event handler!\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case vioblockopen: + /* + * Handle a response to an open request. We get all the + * disk information in the response, so update it. The + * correlation token contains a pointer to a waitevent + * structure that has a completion in it. update the + * return code in the waitevent structure and post the + * completion to wake up the guy who sent the request + */ + pwe = (struct vio_waitevent *)event->xCorrelationToken; + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + case vioblockclose: + break; + default: + printk(KERN_WARNING "handle_viod_request: unexpected subtype!"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static void __init probe_disk(struct device_node *vio_root, u32 unit) +{ + HvLpEvent_Rc hvrc; + struct vio_waitevent we; + u16 flags = 0; + +retry: + init_completion(&we.com); + + /* Send the open event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + ((u64)unit << 48) | ((u64)flags<< 32), + 0, 0, 0); + if (hvrc != 0) { + printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n", + (int)hvrc); + return; + } + + wait_for_completion(&we.com); + + if (we.rc != 0) { + if (flags != 0) + return; + /* try again with read only flag set */ + flags = vioblockflags_ro; + goto retry; + } + + /* Send the close event to OS/400. We DON'T expect a response */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockclose, + HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + 0, VIOVERSION << 16, + ((u64)unit << 48) | ((u64)flags << 32), + 0, 0, 0); + if (hvrc != 0) { + printk(KERN_WARNING "probe_disk: " + "bad rc sending event to OS/400 %d\n", (int)hvrc); + return; + } + + do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, + "block", "IBM,iSeries-viodasd", NULL); +} + +static void __init get_viodasd_info(struct device_node *vio_root) +{ + int rc; + u32 unit; + + rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2); + if (rc) { + printk(KERN_WARNING "get_viodasd_info: " + "error opening path to host partition %d\n", + viopath_hostLp); + return; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_blockio, handle_block_event); + + for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++) + probe_disk(vio_root, unit); + + vio_clearHandler(viomajorsubtype_blockio); + viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2); +} + +static void __init handle_cd_event(struct HvLpEvent *event) +{ + struct viocdlpevent *bevent; + struct vio_waitevent *pwe; + + if (!event) + /* Notification that a partition went away! */ + return; + + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + printk(KERN_WARNING "handle_cd_event: got an unexpected int\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + bevent = (struct viocdlpevent *)event; + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viocdgetinfo: + pwe = (struct vio_waitevent *)event->xCorrelationToken; + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + + default: + printk(KERN_WARNING "handle_cd_event: " + "message with unexpected subtype %0x04X!\n", + event->xSubtype & VIOMINOR_SUBTYPE_MASK); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static void __init get_viocd_info(struct device_node *vio_root) +{ + HvLpEvent_Rc hvrc; + u32 unit; + struct vio_waitevent we; + struct vio_resource *unitinfo; + dma_addr_t unitinfo_dmaaddr; + int ret; + + ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2); + if (ret) { + printk(KERN_WARNING + "get_viocd_info: error opening path to host partition %d\n", + viopath_hostLp); + return; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_cdio, handle_cd_event); + + unitinfo = iseries_hv_alloc( + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, + &unitinfo_dmaaddr, GFP_ATOMIC); + if (!unitinfo) { + printk(KERN_WARNING + "get_viocd_info: error allocating unitinfo\n"); + goto clear_handler; + } + + memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS); + + init_completion(&we.com); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdgetinfo, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, + sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(KERN_WARNING + "get_viocd_info: cdrom error sending event. rc %d\n", + (int)hvrc); + goto hv_free; + } + + wait_for_completion(&we.com); + + if (we.rc) { + printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n", + we.rc, we.sub_result); + goto hv_free; + } + + for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && + unitinfo[unit].rsrcname[0]; unit++) { + if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit, + "block", "IBM,iSeries-viocd", &unitinfo[unit])) + break; + } + + hv_free: + iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, + unitinfo, unitinfo_dmaaddr); + clear_handler: + vio_clearHandler(viomajorsubtype_cdio); + viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); +} + +/* Handle interrupt events for tape */ +static void __init handle_tape_event(struct HvLpEvent *event) +{ + struct vio_waitevent *we; + struct viotapelpevent *tevent = (struct viotapelpevent *)event; + + if (event == NULL) + /* Notification that a partition went away! */ + return; + + we = (struct vio_waitevent *)event->xCorrelationToken; + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viotapegetinfo: + we->rc = tevent->sub_type_result; + complete(&we->com); + break; + default: + printk(KERN_WARNING "handle_tape_event: weird ack\n"); + } +} + +static void __init get_viotape_info(struct device_node *vio_root) +{ + HvLpEvent_Rc hvrc; + u32 unit; + struct vio_resource *unitinfo; + dma_addr_t unitinfo_dmaaddr; + size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES; + struct vio_waitevent we; + int ret; + + init_completion(&we.com); + + ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2); + if (ret) { + printk(KERN_WARNING "get_viotape_info: " + "error on viopath_open to hostlp %d\n", ret); + return; + } + + vio_setHandler(viomajorsubtype_tape, handle_tape_event); + + unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC); + if (!unitinfo) + goto clear_handler; + + memset(unitinfo, 0, len); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapegetinfo, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + unitinfo_dmaaddr, len, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(KERN_WARNING "get_viotape_info: hv error on op %d\n", + (int)hvrc); + goto hv_free; + } + + wait_for_completion(&we.com); + + for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && + unitinfo[unit].rsrcname[0]; unit++) { + if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit, + unit, "byte", "IBM,iSeries-viotape", + &unitinfo[unit])) + break; + } + + hv_free: + iseries_hv_free(len, unitinfo, unitinfo_dmaaddr); + clear_handler: + vio_clearHandler(viomajorsubtype_tape); + viopath_close(viopath_hostLp, viomajorsubtype_tape, 2); +} + +static int __init iseries_vio_init(void) +{ + struct device_node *vio_root; + int ret = -ENODEV; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + goto out; + + iommu_vio_init(); + + vio_root = of_find_node_by_path("/vdevice"); + if (!vio_root) + goto out; + + if (viopath_hostLp == HvLpIndexInvalid) { + vio_set_hostlp(); + /* If we don't have a host, bail out */ + if (viopath_hostLp == HvLpIndexInvalid) + goto put_node; + } + + get_viodasd_info(vio_root); + get_viocd_info(vio_root); + get_viotape_info(vio_root); + + ret = 0; + + put_node: + of_node_put(vio_root); + out: + return ret; +} +arch_initcall(iseries_vio_init); diff --git a/trunk/arch/powerpc/platforms/iseries/viopath.c b/trunk/arch/powerpc/platforms/iseries/viopath.c new file mode 100644 index 000000000000..40dad0840eb3 --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/viopath.c @@ -0,0 +1,677 @@ +/* -*- linux-c -*- + * + * iSeries Virtual I/O Message Path code + * + * Authors: Dave Boutcher + * Ryan Arnold + * Colin Devilbiss + * + * (C) Copyright 2000-2005 IBM Corporation + * + * This code is used by the iSeries virtual disk, cd, + * tape, and console to communicate with OS/400 in another + * partition. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) anyu later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Status of the path to each other partition in the system. + * This is overkill, since we will only ever establish connections + * to our hosting partition and the primary partition on the system. + * But this allows for other support in the future. + */ +static struct viopathStatus { + int isOpen; /* Did we open the path? */ + int isActive; /* Do we have a mon msg outstanding */ + int users[VIO_MAX_SUBTYPES]; + HvLpInstanceId mSourceInst; + HvLpInstanceId mTargetInst; + int numberAllocated; +} viopathStatus[HVMAXARCHITECTEDLPS]; + +static DEFINE_SPINLOCK(statuslock); + +/* + * For each kind of event we allocate a buffer that is + * guaranteed not to cross a page boundary + */ +static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256] + __attribute__((__aligned__(4096))); +static atomic_t event_buffer_available[VIO_MAX_SUBTYPES]; +static int event_buffer_initialised; + +static void handleMonitorEvent(struct HvLpEvent *event); + +/* + * We use this structure to handle asynchronous responses. The caller + * blocks on the semaphore and the handler posts the semaphore. However, + * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ... + */ +struct alloc_parms { + struct completion done; + int number; + atomic_t wait_atomic; + int used_wait_atomic; +}; + +/* Put a sequence number in each mon msg. The value is not + * important. Start at something other than 0 just for + * readability. wrapping this is ok. + */ +static u8 viomonseq = 22; + +/* Our hosting logical partition. We get this at startup + * time, and different modules access this variable directly. + */ +HvLpIndex viopath_hostLp = HvLpIndexInvalid; +EXPORT_SYMBOL(viopath_hostLp); +HvLpIndex viopath_ourLp = HvLpIndexInvalid; +EXPORT_SYMBOL(viopath_ourLp); + +/* For each kind of incoming event we set a pointer to a + * routine to call. + */ +static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES]; + +#define VIOPATH_KERN_WARN KERN_WARNING "viopath: " +#define VIOPATH_KERN_INFO KERN_INFO "viopath: " + +static int proc_viopath_show(struct seq_file *m, void *v) +{ + char *buf; + u16 vlanMap; + dma_addr_t handle; + HvLpEvent_Rc hvrc; + DECLARE_COMPLETION_ONSTACK(done); + struct device_node *node; + const char *sysid; + + buf = kzalloc(HW_PAGE_SIZE, GFP_KERNEL); + if (!buf) + return 0; + + handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_config | vioconfigget, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&done, VIOVERSION << 16, + ((u64)handle) << 32, HW_PAGE_SIZE, 0, 0); + + if (hvrc != HvLpEvent_Rc_Good) + printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc); + + wait_for_completion(&done); + + vlanMap = HvLpConfig_getVirtualLanIndexMap(); + + buf[HW_PAGE_SIZE-1] = '\0'; + seq_printf(m, "%s", buf); + + iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE); + kfree(buf); + + seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); + + node = of_find_node_by_path("/"); + sysid = NULL; + if (node != NULL) + sysid = of_get_property(node, "system-id", NULL); + + if (sysid == NULL) + seq_printf(m, "SRLNBR=\n"); + else + /* Skip "IBM," on front of serial number, see dt.c */ + seq_printf(m, "SRLNBR=%s\n", sysid + 4); + + of_node_put(node); + + return 0; +} + +static int proc_viopath_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_viopath_show, NULL); +} + +static const struct file_operations proc_viopath_operations = { + .open = proc_viopath_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int __init vio_proc_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return 0; + + proc_create("iSeries/config", 0, NULL, &proc_viopath_operations); + return 0; +} +__initcall(vio_proc_init); + +/* See if a given LP is active. Allow for invalid lps to be passed in + * and just return invalid + */ +int viopath_isactive(HvLpIndex lp) +{ + if (lp == HvLpIndexInvalid) + return 0; + if (lp < HVMAXARCHITECTEDLPS) + return viopathStatus[lp].isActive; + else + return 0; +} +EXPORT_SYMBOL(viopath_isactive); + +/* + * We cache the source and target instance ids for each + * partition. + */ +HvLpInstanceId viopath_sourceinst(HvLpIndex lp) +{ + return viopathStatus[lp].mSourceInst; +} +EXPORT_SYMBOL(viopath_sourceinst); + +HvLpInstanceId viopath_targetinst(HvLpIndex lp) +{ + return viopathStatus[lp].mTargetInst; +} +EXPORT_SYMBOL(viopath_targetinst); + +/* + * Send a monitor message. This is a message with the acknowledge + * bit on that the other side will NOT explicitly acknowledge. When + * the other side goes down, the hypervisor will acknowledge any + * outstanding messages....so we will know when the other side dies. + */ +static void sendMonMsg(HvLpIndex remoteLp) +{ + HvLpEvent_Rc hvrc; + + viopathStatus[remoteLp].mSourceInst = + HvCallEvent_getSourceLpInstanceId(remoteLp, + HvLpEvent_Type_VirtualIo); + viopathStatus[remoteLp].mTargetInst = + HvCallEvent_getTargetLpInstanceId(remoteLp, + HvLpEvent_Type_VirtualIo); + + /* + * Deliberately ignore the return code here. if we call this + * more than once, we don't care. + */ + vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent); + + hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo, + viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_DeferredAck, + viopathStatus[remoteLp].mSourceInst, + viopathStatus[remoteLp].mTargetInst, + viomonseq++, 0, 0, 0, 0, 0); + + if (hvrc == HvLpEvent_Rc_Good) + viopathStatus[remoteLp].isActive = 1; + else { + printk(VIOPATH_KERN_WARN "could not connect to partition %d\n", + remoteLp); + viopathStatus[remoteLp].isActive = 0; + } +} + +static void handleMonitorEvent(struct HvLpEvent *event) +{ + HvLpIndex remoteLp; + int i; + + /* + * This handler is _also_ called as part of the loop + * at the end of this routine, so it must be able to + * ignore NULL events... + */ + if (!event) + return; + + /* + * First see if this is just a normal monitor message from the + * other partition + */ + if (hvlpevent_is_int(event)) { + remoteLp = event->xSourceLp; + if (!viopathStatus[remoteLp].isActive) + sendMonMsg(remoteLp); + return; + } + + /* + * This path is for an acknowledgement; the other partition + * died + */ + remoteLp = event->xTargetLp; + if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) || + (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) { + printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n"); + return; + } + + printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp); + + viopathStatus[remoteLp].isActive = 0; + + /* + * For each active handler, pass them a NULL + * message to indicate that the other partition + * died + */ + for (i = 0; i < VIO_MAX_SUBTYPES; i++) { + if (vio_handler[i] != NULL) + (*vio_handler[i])(NULL); + } +} + +int vio_setHandler(int subtype, vio_event_handler_t *beh) +{ + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return -EINVAL; + if (vio_handler[subtype] != NULL) + return -EBUSY; + vio_handler[subtype] = beh; + return 0; +} +EXPORT_SYMBOL(vio_setHandler); + +int vio_clearHandler(int subtype) +{ + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return -EINVAL; + if (vio_handler[subtype] == NULL) + return -EAGAIN; + vio_handler[subtype] = NULL; + return 0; +} +EXPORT_SYMBOL(vio_clearHandler); + +static void handleConfig(struct HvLpEvent *event) +{ + if (!event) + return; + if (hvlpevent_is_int(event)) { + printk(VIOPATH_KERN_WARN + "unexpected config request from partition %d", + event->xSourceLp); + + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + complete((struct completion *)event->xCorrelationToken); +} + +/* + * Initialization of the hosting partition + */ +void vio_set_hostlp(void) +{ + /* + * If this has already been set then we DON'T want to either change + * it or re-register the proc file system + */ + if (viopath_hostLp != HvLpIndexInvalid) + return; + + /* + * Figure out our hosting partition. This isn't allowed to change + * while we're active + */ + viopath_ourLp = HvLpConfig_getLpIndex(); + viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp); + + if (viopath_hostLp != HvLpIndexInvalid) + vio_setHandler(viomajorsubtype_config, handleConfig); +} +EXPORT_SYMBOL(vio_set_hostlp); + +static void vio_handleEvent(struct HvLpEvent *event) +{ + HvLpIndex remoteLp; + int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK) + >> VIOMAJOR_SUBTYPE_SHIFT; + + if (hvlpevent_is_int(event)) { + remoteLp = event->xSourceLp; + /* + * The isActive is checked because if the hosting partition + * went down and came back up it would not be active but it + * would have different source and target instances, in which + * case we'd want to reset them. This case really protects + * against an unauthorized active partition sending interrupts + * or acks to this linux partition. + */ + if (viopathStatus[remoteLp].isActive + && (event->xSourceInstanceId != + viopathStatus[remoteLp].mTargetInst)) { + printk(VIOPATH_KERN_WARN + "message from invalid partition. " + "int msg rcvd, source inst (%d) doesn't match (%d)\n", + viopathStatus[remoteLp].mTargetInst, + event->xSourceInstanceId); + return; + } + + if (viopathStatus[remoteLp].isActive + && (event->xTargetInstanceId != + viopathStatus[remoteLp].mSourceInst)) { + printk(VIOPATH_KERN_WARN + "message from invalid partition. " + "int msg rcvd, target inst (%d) doesn't match (%d)\n", + viopathStatus[remoteLp].mSourceInst, + event->xTargetInstanceId); + return; + } + } else { + remoteLp = event->xTargetLp; + if (event->xSourceInstanceId != + viopathStatus[remoteLp].mSourceInst) { + printk(VIOPATH_KERN_WARN + "message from invalid partition. " + "ack msg rcvd, source inst (%d) doesn't match (%d)\n", + viopathStatus[remoteLp].mSourceInst, + event->xSourceInstanceId); + return; + } + + if (event->xTargetInstanceId != + viopathStatus[remoteLp].mTargetInst) { + printk(VIOPATH_KERN_WARN + "message from invalid partition. " + "viopath: ack msg rcvd, target inst (%d) doesn't match (%d)\n", + viopathStatus[remoteLp].mTargetInst, + event->xTargetInstanceId); + return; + } + } + + if (vio_handler[subtype] == NULL) { + printk(VIOPATH_KERN_WARN + "unexpected virtual io event subtype %d from partition %d\n", + event->xSubtype, remoteLp); + /* No handler. Ack if necessary */ + if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + return; + } + + /* This innocuous little line is where all the real work happens */ + (*vio_handler[subtype])(event); +} + +static void viopath_donealloc(void *parm, int number) +{ + struct alloc_parms *parmsp = parm; + + parmsp->number = number; + if (parmsp->used_wait_atomic) + atomic_set(&parmsp->wait_atomic, 0); + else + complete(&parmsp->done); +} + +static int allocateEvents(HvLpIndex remoteLp, int numEvents) +{ + struct alloc_parms parms; + + if (system_state != SYSTEM_RUNNING) { + parms.used_wait_atomic = 1; + atomic_set(&parms.wait_atomic, 1); + } else { + parms.used_wait_atomic = 0; + init_completion(&parms.done); + } + mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250, /* It would be nice to put a real number here! */ + numEvents, &viopath_donealloc, &parms); + if (system_state != SYSTEM_RUNNING) { + while (atomic_read(&parms.wait_atomic)) + mb(); + } else + wait_for_completion(&parms.done); + return parms.number; +} + +int viopath_open(HvLpIndex remoteLp, int subtype, int numReq) +{ + int i; + unsigned long flags; + int tempNumAllocated; + + if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) + return -EINVAL; + + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return -EINVAL; + + spin_lock_irqsave(&statuslock, flags); + + if (!event_buffer_initialised) { + for (i = 0; i < VIO_MAX_SUBTYPES; i++) + atomic_set(&event_buffer_available[i], 1); + event_buffer_initialised = 1; + } + + viopathStatus[remoteLp].users[subtype]++; + + if (!viopathStatus[remoteLp].isOpen) { + viopathStatus[remoteLp].isOpen = 1; + HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo); + + /* + * Don't hold the spinlock during an operation that + * can sleep. + */ + spin_unlock_irqrestore(&statuslock, flags); + tempNumAllocated = allocateEvents(remoteLp, 1); + spin_lock_irqsave(&statuslock, flags); + + viopathStatus[remoteLp].numberAllocated += tempNumAllocated; + + if (viopathStatus[remoteLp].numberAllocated == 0) { + HvCallEvent_closeLpEventPath(remoteLp, + HvLpEvent_Type_VirtualIo); + + spin_unlock_irqrestore(&statuslock, flags); + return -ENOMEM; + } + + viopathStatus[remoteLp].mSourceInst = + HvCallEvent_getSourceLpInstanceId(remoteLp, + HvLpEvent_Type_VirtualIo); + viopathStatus[remoteLp].mTargetInst = + HvCallEvent_getTargetLpInstanceId(remoteLp, + HvLpEvent_Type_VirtualIo); + HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo, + &vio_handleEvent); + sendMonMsg(remoteLp); + printk(VIOPATH_KERN_INFO "opening connection to partition %d, " + "setting sinst %d, tinst %d\n", + remoteLp, viopathStatus[remoteLp].mSourceInst, + viopathStatus[remoteLp].mTargetInst); + } + + spin_unlock_irqrestore(&statuslock, flags); + tempNumAllocated = allocateEvents(remoteLp, numReq); + spin_lock_irqsave(&statuslock, flags); + viopathStatus[remoteLp].numberAllocated += tempNumAllocated; + spin_unlock_irqrestore(&statuslock, flags); + + return 0; +} +EXPORT_SYMBOL(viopath_open); + +int viopath_close(HvLpIndex remoteLp, int subtype, int numReq) +{ + unsigned long flags; + int i; + int numOpen; + struct alloc_parms parms; + + if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) + return -EINVAL; + + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return -EINVAL; + + spin_lock_irqsave(&statuslock, flags); + /* + * If the viopath_close somehow gets called before a + * viopath_open it could decrement to -1 which is a non + * recoverable state so we'll prevent this from + * happening. + */ + if (viopathStatus[remoteLp].users[subtype] > 0) + viopathStatus[remoteLp].users[subtype]--; + + spin_unlock_irqrestore(&statuslock, flags); + + parms.used_wait_atomic = 0; + init_completion(&parms.done); + mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, + numReq, &viopath_donealloc, &parms); + wait_for_completion(&parms.done); + + spin_lock_irqsave(&statuslock, flags); + for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++) + numOpen += viopathStatus[remoteLp].users[i]; + + if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) { + printk(VIOPATH_KERN_INFO "closing connection to partition %d\n", + remoteLp); + + HvCallEvent_closeLpEventPath(remoteLp, + HvLpEvent_Type_VirtualIo); + viopathStatus[remoteLp].isOpen = 0; + viopathStatus[remoteLp].isActive = 0; + + for (i = 0; i < VIO_MAX_SUBTYPES; i++) + atomic_set(&event_buffer_available[i], 0); + event_buffer_initialised = 0; + } + spin_unlock_irqrestore(&statuslock, flags); + return 0; +} +EXPORT_SYMBOL(viopath_close); + +void *vio_get_event_buffer(int subtype) +{ + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) + return NULL; + + if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0) + return &event_buffer[subtype * 256]; + else + return NULL; +} +EXPORT_SYMBOL(vio_get_event_buffer); + +void vio_free_event_buffer(int subtype, void *buffer) +{ + subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; + if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) { + printk(VIOPATH_KERN_WARN + "unexpected subtype %d freeing event buffer\n", subtype); + return; + } + + if (atomic_read(&event_buffer_available[subtype]) != 0) { + printk(VIOPATH_KERN_WARN + "freeing unallocated event buffer, subtype %d\n", + subtype); + return; + } + + if (buffer != &event_buffer[subtype * 256]) { + printk(VIOPATH_KERN_WARN + "freeing invalid event buffer, subtype %d\n", subtype); + } + + atomic_set(&event_buffer_available[subtype], 1); +} +EXPORT_SYMBOL(vio_free_event_buffer); + +static const struct vio_error_entry vio_no_error = + { 0, 0, "Non-VIO Error" }; +static const struct vio_error_entry vio_unknown_error = + { 0, EIO, "Unknown Error" }; + +static const struct vio_error_entry vio_default_errors[] = { + {0x0001, EIO, "No Connection"}, + {0x0002, EIO, "No Receiver"}, + {0x0003, EIO, "No Buffer Available"}, + {0x0004, EBADRQC, "Invalid Message Type"}, + {0x0000, 0, NULL}, +}; + +const struct vio_error_entry *vio_lookup_rc( + const struct vio_error_entry *local_table, u16 rc) +{ + const struct vio_error_entry *cur; + + if (!rc) + return &vio_no_error; + if (local_table) + for (cur = local_table; cur->rc; ++cur) + if (cur->rc == rc) + return cur; + for (cur = vio_default_errors; cur->rc; ++cur) + if (cur->rc == rc) + return cur; + return &vio_unknown_error; +} +EXPORT_SYMBOL(vio_lookup_rc); diff --git a/trunk/arch/powerpc/platforms/iseries/vpd_areas.h b/trunk/arch/powerpc/platforms/iseries/vpd_areas.h new file mode 100644 index 000000000000..feb001f3a5fe --- /dev/null +++ b/trunk/arch/powerpc/platforms/iseries/vpd_areas.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2001 Mike Corrigan IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#ifndef _ISERIES_VPD_AREAS_H +#define _ISERIES_VPD_AREAS_H + +/* + * This file defines the address and length of all of the VPD area passed to + * the OS from PLIC (most of which start from the SP). + */ + +#include + +/* VPD Entry index is carved in stone - cannot be changed (easily). */ +#define ItVpdCecVpd 0 +#define ItVpdDynamicSpace 1 +#define ItVpdExtVpd 2 +#define ItVpdExtVpdOnPanel 3 +#define ItVpdFirstPaca 4 +#define ItVpdIoVpd 5 +#define ItVpdIplParms 6 +#define ItVpdMsVpd 7 +#define ItVpdPanelVpd 8 +#define ItVpdLpNaca 9 +#define ItVpdBackplaneAndMaybeClockCardVpd 10 +#define ItVpdRecoveryLogBuffer 11 +#define ItVpdSpCommArea 12 +#define ItVpdSpLogBuffer 13 +#define ItVpdSpLogBufferSave 14 +#define ItVpdSpCardVpd 15 +#define ItVpdFirstProcVpd 16 +#define ItVpdApModelVpd 17 +#define ItVpdClockCardVpd 18 +#define ItVpdBusExtCardVpd 19 +#define ItVpdProcCapacityVpd 20 +#define ItVpdInteractiveCapacityVpd 21 +#define ItVpdFirstSlotLabel 22 +#define ItVpdFirstLpQueue 23 +#define ItVpdFirstL3CacheVpd 24 +#define ItVpdFirstProcFruVpd 25 + +#define ItVpdMaxEntries 26 + +#define ItDmaMaxEntries 10 + +#define ItVpdAreasMaxSlotLabels 192 + + +struct ItVpdAreas { + u32 xSlicDesc; // Descriptor 000-003 + u16 xSlicSize; // Size of this control block 004-005 + u16 xPlicAdjustVpdLens:1; // Flag to indicate new interface006-007 + u16 xRsvd1:15; // Reserved bits ... + u16 xSlicVpdEntries; // Number of VPD entries 008-009 + u16 xSlicDmaEntries; // Number of DMA entries 00A-00B + u16 xSlicMaxLogicalProcs; // Maximum logical processors 00C-00D + u16 xSlicMaxPhysicalProcs; // Maximum physical processors 00E-00F + u16 xSlicDmaToksOffset; // Offset into this of array 010-011 + u16 xSlicVpdAdrsOffset; // Offset into this of array 012-013 + u16 xSlicDmaLensOffset; // Offset into this of array 014-015 + u16 xSlicVpdLensOffset; // Offset into this of array 016-017 + u16 xSlicMaxSlotLabels; // Maximum number of slot labels018-019 + u16 xSlicMaxLpQueues; // Maximum number of LP Queues 01A-01B + u8 xRsvd2[4]; // Reserved 01C-01F + u64 xRsvd3[12]; // Reserved 020-07F + u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A7 + u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF + u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F + const void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF +}; + +extern const struct ItVpdAreas itVpdAreas; + +#endif /* _ISERIES_VPD_AREAS_H */ diff --git a/trunk/arch/powerpc/platforms/maple/setup.c b/trunk/arch/powerpc/platforms/maple/setup.c index 3b7545a51aa9..0bcbfe7b2c55 100644 --- a/trunk/arch/powerpc/platforms/maple/setup.c +++ b/trunk/arch/powerpc/platforms/maple/setup.c @@ -262,7 +262,7 @@ static void __init maple_init_IRQ(void) flags |= MPIC_BIG_ENDIAN; /* XXX Maple specific bits */ - flags |= MPIC_U3_HT_IRQS; + flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET; /* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */ flags |= MPIC_BIG_ENDIAN; diff --git a/trunk/arch/powerpc/platforms/pasemi/setup.c b/trunk/arch/powerpc/platforms/pasemi/setup.c index e777ad471a48..98b7a7c13176 100644 --- a/trunk/arch/powerpc/platforms/pasemi/setup.c +++ b/trunk/arch/powerpc/platforms/pasemi/setup.c @@ -224,7 +224,7 @@ static __init void pas_init_IRQ(void) openpic_addr = of_read_number(opprop, naddr); printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); - mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS | MPIC_NO_RESET; + mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS; nmiprop = of_get_property(mpic_node, "nmi-source", NULL); if (nmiprop) diff --git a/trunk/arch/powerpc/platforms/powermac/nvram.c b/trunk/arch/powerpc/platforms/powermac/nvram.c index da18b26dcc6f..54d227127c9f 100644 --- a/trunk/arch/powerpc/platforms/powermac/nvram.c +++ b/trunk/arch/powerpc/platforms/powermac/nvram.c @@ -279,7 +279,7 @@ static u32 core99_check(u8* datas) static int sm_erase_bank(int bank) { - int stat; + int stat, i; unsigned long timeout; u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; @@ -301,10 +301,11 @@ static int sm_erase_bank(int bank) out_8(base, SM_FLASH_CMD_CLEAR_STATUS); out_8(base, SM_FLASH_CMD_RESET); - if (memchr_inv(base, 0xff, NVRAM_SIZE)) { - printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); - return -ENXIO; - } + for (i=0; i #include #include -#include #include "powernv.h" #include "pci.h" diff --git a/trunk/arch/powerpc/platforms/powernv/setup.c b/trunk/arch/powerpc/platforms/powernv/setup.c index db1ad1c8f68f..467bd4ac6824 100644 --- a/trunk/arch/powerpc/platforms/powernv/setup.c +++ b/trunk/arch/powerpc/platforms/powernv/setup.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "powernv.h" diff --git a/trunk/arch/powerpc/platforms/pseries/Kconfig b/trunk/arch/powerpc/platforms/pseries/Kconfig index aadbe4f6d537..f2556257bbdc 100644 --- a/trunk/arch/powerpc/platforms/pseries/Kconfig +++ b/trunk/arch/powerpc/platforms/pseries/Kconfig @@ -73,7 +73,7 @@ config IO_EVENT_IRQ config LPARCFG bool "LPAR Configuration Data" - depends on PPC_PSERIES + depends on PPC_PSERIES || PPC_ISERIES help Provide system capacity information via human readable = pairs through a /proc/ppc64/lparcfg interface. diff --git a/trunk/arch/powerpc/platforms/pseries/Makefile b/trunk/arch/powerpc/platforms/pseries/Makefile index c222189f5bb2..236db46b4078 100644 --- a/trunk/arch/powerpc/platforms/pseries/Makefile +++ b/trunk/arch/powerpc/platforms/pseries/Makefile @@ -6,8 +6,7 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ firmware.o power.o dlpar.o mobility.o obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SCANLOG) += scanlog.o -obj-$(CONFIG_EEH) += eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \ - eeh_event.o eeh_sysfs.o eeh_pseries.o +obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_PCI) += pci.o pci_dlpar.o obj-$(CONFIG_PSERIES_MSI) += msi.o @@ -19,6 +18,7 @@ obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o obj-$(CONFIG_HVCS) += hvcserver.o obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o +obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o obj-$(CONFIG_CMM) += cmm.o obj-$(CONFIG_DTL) += dtl.o obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o diff --git a/trunk/arch/powerpc/platforms/pseries/eeh.c b/trunk/arch/powerpc/platforms/pseries/eeh.c index 8011088392d3..c0b40af4ce4f 100644 --- a/trunk/arch/powerpc/platforms/pseries/eeh.c +++ b/trunk/arch/powerpc/platforms/pseries/eeh.c @@ -1,8 +1,8 @@ /* + * eeh.c * Copyright IBM Corporation 2001, 2005, 2006 * Copyright Dave Engebretsen & Todd Inglett 2001 * Copyright Linas Vepstas 2005, 2006 - * Copyright 2001-2012 IBM Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,7 +22,7 @@ */ #include -#include +#include /* for init_mm */ #include #include #include @@ -86,8 +86,16 @@ /* Time to wait for a PCI slot to report status, in milliseconds */ #define PCI_BUS_RESET_WAIT_MSEC (60*1000) -/* Platform dependent EEH operations */ -struct eeh_ops *eeh_ops = NULL; +/* RTAS tokens */ +static int ibm_set_eeh_option; +static int ibm_set_slot_reset; +static int ibm_read_slot_reset_state; +static int ibm_read_slot_reset_state2; +static int ibm_slot_error_detail; +static int ibm_get_config_addr_info; +static int ibm_get_config_addr_info2; +static int ibm_configure_bridge; +static int ibm_configure_pe; int eeh_subsystem_enabled; EXPORT_SYMBOL(eeh_subsystem_enabled); @@ -95,6 +103,14 @@ EXPORT_SYMBOL(eeh_subsystem_enabled); /* Lock to avoid races due to multiple reports of an error */ static DEFINE_RAW_SPINLOCK(confirm_error_lock); +/* Buffer for reporting slot-error-detail rtas calls. Its here + * in BSS, and not dynamically alloced, so that it ends up in + * RMO where RTAS can access it. + */ +static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; +static DEFINE_SPINLOCK(slot_errbuf_lock); +static int eeh_error_buf_size; + /* Buffer for reporting pci register dumps. Its here in BSS, and * not dynamically alloced, so that it ends up in RMO where RTAS * can access it. @@ -102,50 +118,74 @@ static DEFINE_RAW_SPINLOCK(confirm_error_lock); #define EEH_PCI_REGS_LOG_LEN 4096 static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN]; -/* - * The struct is used to maintain the EEH global statistic - * information. Besides, the EEH global statistics will be - * exported to user space through procfs - */ -struct eeh_stats { - u64 no_device; /* PCI device not found */ - u64 no_dn; /* OF node not found */ - u64 no_cfg_addr; /* Config address not found */ - u64 ignored_check; /* EEH check skipped */ - u64 total_mmio_ffs; /* Total EEH checks */ - u64 false_positives; /* Unnecessary EEH checks */ - u64 slot_resets; /* PE reset */ -}; - -static struct eeh_stats eeh_stats; +/* System monitoring statistics */ +static unsigned long no_device; +static unsigned long no_dn; +static unsigned long no_cfg_addr; +static unsigned long ignored_check; +static unsigned long total_mmio_ffs; +static unsigned long false_positives; +static unsigned long slot_resets; #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) +/* --------------------------------------------------------------- */ +/* Below lies the EEH event infrastructure */ + +static void rtas_slot_error_detail(struct pci_dn *pdn, int severity, + char *driver_log, size_t loglen) +{ + int config_addr; + unsigned long flags; + int rc; + + /* Log the error with the rtas logger */ + spin_lock_irqsave(&slot_errbuf_lock, flags); + memset(slot_errbuf, 0, eeh_error_buf_size); + + /* Use PE configuration address, if present */ + config_addr = pdn->eeh_config_addr; + if (pdn->eeh_pe_config_addr) + config_addr = pdn->eeh_pe_config_addr; + + rc = rtas_call(ibm_slot_error_detail, + 8, 1, NULL, config_addr, + BUID_HI(pdn->phb->buid), + BUID_LO(pdn->phb->buid), + virt_to_phys(driver_log), loglen, + virt_to_phys(slot_errbuf), + eeh_error_buf_size, + severity); + + if (rc == 0) + log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); + spin_unlock_irqrestore(&slot_errbuf_lock, flags); +} + /** - * eeh_gather_pci_data - Copy assorted PCI config space registers to buff - * @edev: device to report data for + * gather_pci_data - copy assorted PCI config space registers to buff + * @pdn: device to report data for * @buf: point to buffer in which to log * @len: amount of room in buffer * * This routine captures assorted PCI configuration space data, * and puts them into a buffer for RTAS error logging. */ -static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) +static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) { - struct device_node *dn = eeh_dev_to_of_node(edev); - struct pci_dev *dev = eeh_dev_to_pci_dev(edev); + struct pci_dev *dev = pdn->pcidev; u32 cfg; int cap, i; int n = 0; - n += scnprintf(buf+n, len-n, "%s\n", dn->full_name); - printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name); + n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name); + printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name); - eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg); + rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg); n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg); printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg); - eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg); + rtas_read_config(pdn, PCI_COMMAND, 4, &cfg); n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); @@ -156,11 +196,11 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) /* Gather bridge-specific registers */ if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { - eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg); + rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg); n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); - eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg); + rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg); n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); } @@ -168,11 +208,11 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) /* Dump out the PCI-X command and status regs */ cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); if (cap) { - eeh_ops->read_config(dn, cap, 4, &cfg); + rtas_read_config(pdn, cap, 4, &cfg); n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg); printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); - eeh_ops->read_config(dn, cap+4, 4, &cfg); + rtas_read_config(pdn, cap+4, 4, &cfg); n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg); printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg); } @@ -185,7 +225,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) "EEH: PCI-E capabilities and status follow:\n"); for (i=0; i<=8; i++) { - eeh_ops->read_config(dn, cap+4*i, 4, &cfg); + rtas_read_config(pdn, cap+4*i, 4, &cfg); n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); } @@ -197,7 +237,7 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) "EEH: PCI-E AER capability register set follows:\n"); for (i=0; i<14; i++) { - eeh_ops->read_config(dn, cap+4*i, 4, &cfg); + rtas_read_config(pdn, cap+4*i, 4, &cfg); n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg); } @@ -206,46 +246,111 @@ static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) /* Gather status on devices under the bridge */ if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { - struct device_node *child; + struct device_node *dn; - for_each_child_of_node(dn, child) { - if (of_node_to_eeh_dev(child)) - n += eeh_gather_pci_data(of_node_to_eeh_dev(child), buf+n, len-n); + for_each_child_of_node(pdn->node, dn) { + pdn = PCI_DN(dn); + if (pdn) + n += gather_pci_data(pdn, buf+n, len-n); } } return n; } -/** - * eeh_slot_error_detail - Generate combined log including driver log and error log - * @edev: device to report error log for - * @severity: temporary or permanent error log - * - * This routine should be called to generate the combined log, which - * is comprised of driver log and error log. The driver log is figured - * out from the config space of the corresponding PCI device, while - * the error log is fetched through platform dependent function call. - */ -void eeh_slot_error_detail(struct eeh_dev *edev, int severity) +void eeh_slot_error_detail(struct pci_dn *pdn, int severity) { size_t loglen = 0; pci_regs_buf[0] = 0; - eeh_pci_enable(edev, EEH_OPT_THAW_MMIO); - eeh_ops->configure_bridge(eeh_dev_to_of_node(edev)); - eeh_restore_bars(edev); - loglen = eeh_gather_pci_data(edev, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); + rtas_pci_enable(pdn, EEH_THAW_MMIO); + rtas_configure_bridge(pdn); + eeh_restore_bars(pdn); + loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); - eeh_ops->get_log(eeh_dev_to_of_node(edev), severity, pci_regs_buf, loglen); + rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); } /** - * eeh_token_to_phys - Convert EEH address token to phys address - * @token: I/O token, should be address in the form 0xA.... + * read_slot_reset_state - Read the reset state of a device node's slot + * @dn: device node to read + * @rets: array to return results in + */ +static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) +{ + int token, outputs; + int config_addr; + + if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { + token = ibm_read_slot_reset_state2; + outputs = 4; + } else { + token = ibm_read_slot_reset_state; + rets[2] = 0; /* fake PE Unavailable info */ + outputs = 3; + } + + /* Use PE configuration address, if present */ + config_addr = pdn->eeh_config_addr; + if (pdn->eeh_pe_config_addr) + config_addr = pdn->eeh_pe_config_addr; + + return rtas_call(token, 3, outputs, rets, config_addr, + BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); +} + +/** + * eeh_wait_for_slot_status - returns error status of slot + * @pdn pci device node + * @max_wait_msecs maximum number to millisecs to wait * - * This routine should be called to convert virtual I/O address - * to physical one. + * Return negative value if a permanent error, else return + * Partition Endpoint (PE) status value. + * + * If @max_wait_msecs is positive, then this routine will + * sleep until a valid status can be obtained, or until + * the max allowed wait time is exceeded, in which case + * a -2 is returned. + */ +int +eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs) +{ + int rc; + int rets[3]; + int mwait; + + while (1) { + rc = read_slot_reset_state(pdn, rets); + if (rc) return rc; + if (rets[1] == 0) return -1; /* EEH is not supported */ + + if (rets[0] != 5) return rets[0]; /* return actual status */ + + if (rets[2] == 0) return -1; /* permanently unavailable */ + + if (max_wait_msecs <= 0) break; + + mwait = rets[2]; + if (mwait <= 0) { + printk (KERN_WARNING + "EEH: Firmware returned bad wait value=%d\n", mwait); + mwait = 1000; + } else if (mwait > 300*1000) { + printk (KERN_WARNING + "EEH: Firmware is taking too long, time=%d\n", mwait); + mwait = 300*1000; + } + max_wait_msecs -= mwait; + msleep (mwait); + } + + printk(KERN_WARNING "EEH: Timed out waiting for slot status\n"); + return -2; +} + +/** + * eeh_token_to_phys - convert EEH address token to phys address + * @token i/o token, should be address in the form 0xA.... */ static inline unsigned long eeh_token_to_phys(unsigned long token) { @@ -260,43 +365,36 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) return pa | (token & (PAGE_SIZE-1)); } -/** - * eeh_find_device_pe - Retrieve the PE for the given device - * @dn: device node - * - * Return the PE under which this device lies +/** + * Return the "partitionable endpoint" (pe) under which this device lies */ -struct device_node *eeh_find_device_pe(struct device_node *dn) +struct device_node * find_device_pe(struct device_node *dn) { - while (dn->parent && of_node_to_eeh_dev(dn->parent) && - (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { + while ((dn->parent) && PCI_DN(dn->parent) && + (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { dn = dn->parent; } return dn; } -/** - * __eeh_mark_slot - Mark all child devices as failed - * @parent: parent device - * @mode_flag: failure flag - * - * Mark all devices that are children of this device as failed. - * Mark the device driver too, so that it can see the failure - * immediately; this is critical, since some drivers poll - * status registers in interrupts ... If a driver is polling, - * and the slot is frozen, then the driver can deadlock in - * an interrupt context, which is bad. +/** Mark all devices that are children of this device as failed. + * Mark the device driver too, so that it can see the failure + * immediately; this is critical, since some drivers poll + * status registers in interrupts ... If a driver is polling, + * and the slot is frozen, then the driver can deadlock in + * an interrupt context, which is bad. */ + static void __eeh_mark_slot(struct device_node *parent, int mode_flag) { struct device_node *dn; for_each_child_of_node(parent, dn) { - if (of_node_to_eeh_dev(dn)) { + if (PCI_DN(dn)) { /* Mark the pci device driver too */ - struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; + struct pci_dev *dev = PCI_DN(dn)->pcidev; - of_node_to_eeh_dev(dn)->mode |= mode_flag; + PCI_DN(dn)->eeh_mode |= mode_flag; if (dev && dev->driver) dev->error_state = pci_channel_io_frozen; @@ -306,81 +404,92 @@ static void __eeh_mark_slot(struct device_node *parent, int mode_flag) } } -/** - * eeh_mark_slot - Mark the indicated device and its children as failed - * @dn: parent device - * @mode_flag: failure flag - * - * Mark the indicated device and its child devices as failed. - * The device drivers are marked as failed as well. - */ -void eeh_mark_slot(struct device_node *dn, int mode_flag) +void eeh_mark_slot (struct device_node *dn, int mode_flag) { struct pci_dev *dev; - dn = eeh_find_device_pe(dn); + dn = find_device_pe (dn); /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) + if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) dn = dn->parent; - of_node_to_eeh_dev(dn)->mode |= mode_flag; + PCI_DN(dn)->eeh_mode |= mode_flag; /* Mark the pci device too */ - dev = of_node_to_eeh_dev(dn)->pdev; + dev = PCI_DN(dn)->pcidev; if (dev) dev->error_state = pci_channel_io_frozen; __eeh_mark_slot(dn, mode_flag); } -/** - * __eeh_clear_slot - Clear failure flag for the child devices - * @parent: parent device - * @mode_flag: flag to be cleared - * - * Clear failure flag for the child devices. - */ static void __eeh_clear_slot(struct device_node *parent, int mode_flag) { struct device_node *dn; for_each_child_of_node(parent, dn) { - if (of_node_to_eeh_dev(dn)) { - of_node_to_eeh_dev(dn)->mode &= ~mode_flag; - of_node_to_eeh_dev(dn)->check_count = 0; + if (PCI_DN(dn)) { + PCI_DN(dn)->eeh_mode &= ~mode_flag; + PCI_DN(dn)->eeh_check_count = 0; __eeh_clear_slot(dn, mode_flag); } } } -/** - * eeh_clear_slot - Clear failure flag for the indicated device and its children - * @dn: parent device - * @mode_flag: flag to be cleared - * - * Clear failure flag for the indicated device and its children. - */ -void eeh_clear_slot(struct device_node *dn, int mode_flag) +void eeh_clear_slot (struct device_node *dn, int mode_flag) { unsigned long flags; raw_spin_lock_irqsave(&confirm_error_lock, flags); - dn = eeh_find_device_pe(dn); + dn = find_device_pe (dn); /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) + if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) dn = dn->parent; - of_node_to_eeh_dev(dn)->mode &= ~mode_flag; - of_node_to_eeh_dev(dn)->check_count = 0; + PCI_DN(dn)->eeh_mode &= ~mode_flag; + PCI_DN(dn)->eeh_check_count = 0; __eeh_clear_slot(dn, mode_flag); raw_spin_unlock_irqrestore(&confirm_error_lock, flags); } +void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) +{ + struct device_node *dn; + + for_each_child_of_node(parent, dn) { + if (PCI_DN(dn)) { + + struct pci_dev *dev = PCI_DN(dn)->pcidev; + + if (dev && dev->driver) + *freset |= dev->needs_freset; + + __eeh_set_pe_freset(dn, freset); + } + } +} + +void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) +{ + struct pci_dev *dev; + dn = find_device_pe(dn); + + /* Back up one, since config addrs might be shared */ + if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + dn = dn->parent; + + dev = PCI_DN(dn)->pcidev; + if (dev) + *freset |= dev->needs_freset; + + __eeh_set_pe_freset(dn, freset); +} + /** - * eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze - * @dn: device node - * @dev: pci device, if known + * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze + * @dn device node + * @dev pci device, if known * * Check for an EEH failure for the given device node. Call this * routine if the result of a read was all 0xff's and you want to @@ -395,34 +504,35 @@ void eeh_clear_slot(struct device_node *dn, int mode_flag) int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) { int ret; + int rets[3]; unsigned long flags; - struct eeh_dev *edev; + struct pci_dn *pdn; int rc = 0; const char *location; - eeh_stats.total_mmio_ffs++; + total_mmio_ffs++; if (!eeh_subsystem_enabled) return 0; if (!dn) { - eeh_stats.no_dn++; + no_dn++; return 0; } - dn = eeh_find_device_pe(dn); - edev = of_node_to_eeh_dev(dn); + dn = find_device_pe(dn); + pdn = PCI_DN(dn); /* Access to IO BARs might get this far and still not want checking. */ - if (!(edev->mode & EEH_MODE_SUPPORTED) || - edev->mode & EEH_MODE_NOCHECK) { - eeh_stats.ignored_check++; + if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || + pdn->eeh_mode & EEH_MODE_NOCHECK) { + ignored_check++; pr_debug("EEH: Ignored check (%x) for %s %s\n", - edev->mode, eeh_pci_name(dev), dn->full_name); + pdn->eeh_mode, eeh_pci_name(dev), dn->full_name); return 0; } - if (!edev->config_addr && !edev->pe_config_addr) { - eeh_stats.no_cfg_addr++; + if (!pdn->eeh_config_addr && !pdn->eeh_pe_config_addr) { + no_cfg_addr++; return 0; } @@ -434,15 +544,15 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) */ raw_spin_lock_irqsave(&confirm_error_lock, flags); rc = 1; - if (edev->mode & EEH_MODE_ISOLATED) { - edev->check_count++; - if (edev->check_count % EEH_MAX_FAILS == 0) { + if (pdn->eeh_mode & EEH_MODE_ISOLATED) { + pdn->eeh_check_count ++; + if (pdn->eeh_check_count % EEH_MAX_FAILS == 0) { location = of_get_property(dn, "ibm,loc-code", NULL); - printk(KERN_ERR "EEH: %d reads ignored for recovering device at " + printk (KERN_ERR "EEH: %d reads ignored for recovering device at " "location=%s driver=%s pci addr=%s\n", - edev->check_count, location, + pdn->eeh_check_count, location, eeh_driver_name(dev), eeh_pci_name(dev)); - printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n", + printk (KERN_ERR "EEH: Might be infinite loop in %s driver\n", eeh_driver_name(dev)); dump_stack(); } @@ -456,39 +566,58 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) * function zero of a multi-function device. * In any case they must share a common PHB. */ - ret = eeh_ops->get_state(dn, NULL); + ret = read_slot_reset_state(pdn, rets); + + /* If the call to firmware failed, punt */ + if (ret != 0) { + printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n", + ret, dn->full_name); + false_positives++; + pdn->eeh_false_positives ++; + rc = 0; + goto dn_unlock; + } /* Note that config-io to empty slots may fail; - * they are empty when they don't have children. - * We will punt with the following conditions: Failure to get - * PE's state, EEH not support and Permanently unavailable - * state, PE is in good state. - */ - if ((ret < 0) || - (ret == EEH_STATE_NOT_SUPPORT) || - (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) == - (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) { - eeh_stats.false_positives++; - edev->false_positives ++; + * they are empty when they don't have children. */ + if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) { + false_positives++; + pdn->eeh_false_positives ++; + rc = 0; + goto dn_unlock; + } + + /* If EEH is not supported on this device, punt. */ + if (rets[1] != 1) { + printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", + ret, dn->full_name); + false_positives++; + pdn->eeh_false_positives ++; rc = 0; goto dn_unlock; } - eeh_stats.slot_resets++; + /* If not the kind of error we know about, punt. */ + if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { + false_positives++; + pdn->eeh_false_positives ++; + rc = 0; + goto dn_unlock; + } + + slot_resets++; /* Avoid repeated reports of this failure, including problems * with other functions on this device, and functions under - * bridges. - */ - eeh_mark_slot(dn, EEH_MODE_ISOLATED); + * bridges. */ + eeh_mark_slot (dn, EEH_MODE_ISOLATED); raw_spin_unlock_irqrestore(&confirm_error_lock, flags); - eeh_send_failure_event(edev); + eeh_send_failure_event (dn, dev); /* Most EEH events are due to device driver bugs. Having * a stack trace will help the device-driver authors figure - * out what happened. So print that out. - */ + * out what happened. So print that out. */ dump_stack(); return 1; @@ -500,9 +629,9 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) EXPORT_SYMBOL_GPL(eeh_dn_check_failure); /** - * eeh_check_failure - Check if all 1's data is due to EEH slot freeze - * @token: I/O token, should be address in the form 0xA.... - * @val: value, should be all 1's (XXX why do we need this arg??) + * eeh_check_failure - check if all 1's data is due to EEH slot freeze + * @token i/o token, should be address in the form 0xA.... + * @val value, should be all 1's (XXX why do we need this arg??) * * Check for an EEH failure at the given token address. Call this * routine if the result of a read was all 0xff's and you want to @@ -519,14 +648,14 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon /* Finding the phys addr + pci device; this is pretty quick. */ addr = eeh_token_to_phys((unsigned long __force) token); - dev = pci_addr_cache_get_device(addr); + dev = pci_get_device_by_addr(addr); if (!dev) { - eeh_stats.no_device++; + no_device++; return val; } dn = pci_device_to_OF_node(dev); - eeh_dn_check_failure(dn, dev); + eeh_dn_check_failure (dn, dev); pci_dev_put(dev); return val; @@ -534,54 +663,115 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon EXPORT_SYMBOL(eeh_check_failure); +/* ------------------------------------------------------------- */ +/* The code below deals with error recovery */ /** - * eeh_pci_enable - Enable MMIO or DMA transfers for this slot - * @edev: pci device node - * - * This routine should be called to reenable frozen MMIO or DMA - * so that it would work correctly again. It's useful while doing - * recovery or log collection on the indicated device. + * rtas_pci_enable - enable MMIO or DMA transfers for this slot + * @pdn pci device node */ -int eeh_pci_enable(struct eeh_dev *edev, int function) + +int +rtas_pci_enable(struct pci_dn *pdn, int function) { + int config_addr; int rc; - struct device_node *dn = eeh_dev_to_of_node(edev); - rc = eeh_ops->set_option(dn, function); + /* Use PE configuration address, if present */ + config_addr = pdn->eeh_config_addr; + if (pdn->eeh_pe_config_addr) + config_addr = pdn->eeh_pe_config_addr; + + rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL, + config_addr, + BUID_HI(pdn->phb->buid), + BUID_LO(pdn->phb->buid), + function); + if (rc) printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", - function, rc, dn->full_name); + function, rc, pdn->node->full_name); - rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); - if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) && - (function == EEH_OPT_THAW_MMIO)) + rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC); + if ((rc == 4) && (function == EEH_THAW_MMIO)) return 0; return rc; } +/** + * rtas_pci_slot_reset - raises/lowers the pci #RST line + * @pdn pci device node + * @state: 1/0 to raise/lower the #RST + * + * Clear the EEH-frozen condition on a slot. This routine + * asserts the PCI #RST line if the 'state' argument is '1', + * and drops the #RST line if 'state is '0'. This routine is + * safe to call in an interrupt context. + * + */ + +static void +rtas_pci_slot_reset(struct pci_dn *pdn, int state) +{ + int config_addr; + int rc; + + BUG_ON (pdn==NULL); + + if (!pdn->phb) { + printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n", + pdn->node->full_name); + return; + } + + /* Use PE configuration address, if present */ + config_addr = pdn->eeh_config_addr; + if (pdn->eeh_pe_config_addr) + config_addr = pdn->eeh_pe_config_addr; + + rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, + config_addr, + BUID_HI(pdn->phb->buid), + BUID_LO(pdn->phb->buid), + state); + + /* Fundamental-reset not supported on this PE, try hot-reset */ + if (rc == -8 && state == 3) { + rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, + config_addr, + BUID_HI(pdn->phb->buid), + BUID_LO(pdn->phb->buid), 1); + if (rc) + printk(KERN_WARNING + "EEH: Unable to reset the failed slot," + " #RST=%d dn=%s\n", + rc, pdn->node->full_name); + } +} + /** * pcibios_set_pcie_slot_reset - Set PCI-E reset state - * @dev: pci device struct - * @state: reset state to enter + * @dev: pci device struct + * @state: reset state to enter * * Return value: * 0 if success - */ + **/ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) { struct device_node *dn = pci_device_to_OF_node(dev); + struct pci_dn *pdn = PCI_DN(dn); switch (state) { case pcie_deassert_reset: - eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); + rtas_pci_slot_reset(pdn, 0); break; case pcie_hot_reset: - eeh_ops->reset(dn, EEH_RESET_HOT); + rtas_pci_slot_reset(pdn, 1); break; case pcie_warm_reset: - eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); + rtas_pci_slot_reset(pdn, 3); break; default: return -EINVAL; @@ -591,66 +781,13 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat } /** - * __eeh_set_pe_freset - Check the required reset for child devices - * @parent: parent device - * @freset: return value - * - * Each device might have its preferred reset type: fundamental or - * hot reset. The routine is used to collect the information from - * the child devices so that they could be reset accordingly. - */ -void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) -{ - struct device_node *dn; - - for_each_child_of_node(parent, dn) { - if (of_node_to_eeh_dev(dn)) { - struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; - - if (dev && dev->driver) - *freset |= dev->needs_freset; - - __eeh_set_pe_freset(dn, freset); - } - } -} - -/** - * eeh_set_pe_freset - Check the required reset for the indicated device and its children - * @dn: parent device - * @freset: return value - * - * Each device might have its preferred reset type: fundamental or - * hot reset. The routine is used to collected the information for - * the indicated device and its children so that the bunch of the - * devices could be reset properly. + * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second + * @pdn: pci device node to be reset. */ -void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) -{ - struct pci_dev *dev; - dn = eeh_find_device_pe(dn); - - /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) - dn = dn->parent; - - dev = of_node_to_eeh_dev(dn)->pdev; - if (dev) - *freset |= dev->needs_freset; - __eeh_set_pe_freset(dn, freset); -} - -/** - * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second - * @edev: pci device node to be reset. - * - * Assert the PCI #RST line for 1/4 second. - */ -static void eeh_reset_pe_once(struct eeh_dev *edev) +static void __rtas_set_slot_reset(struct pci_dn *pdn) { unsigned int freset = 0; - struct device_node *dn = eeh_dev_to_of_node(edev); /* Determine type of EEH reset required for * Partitionable Endpoint, a hot-reset (1) @@ -658,68 +795,58 @@ static void eeh_reset_pe_once(struct eeh_dev *edev) * A fundamental reset required by any device under * Partitionable Endpoint trumps hot-reset. */ - eeh_set_pe_freset(dn, &freset); + eeh_set_pe_freset(pdn->node, &freset); if (freset) - eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); + rtas_pci_slot_reset(pdn, 3); else - eeh_ops->reset(dn, EEH_RESET_HOT); + rtas_pci_slot_reset(pdn, 1); /* The PCI bus requires that the reset be held high for at least - * a 100 milliseconds. We wait a bit longer 'just in case'. - */ + * a 100 milliseconds. We wait a bit longer 'just in case'. */ + #define PCI_BUS_RST_HOLD_TIME_MSEC 250 - msleep(PCI_BUS_RST_HOLD_TIME_MSEC); + msleep (PCI_BUS_RST_HOLD_TIME_MSEC); /* We might get hit with another EEH freeze as soon as the * pci slot reset line is dropped. Make sure we don't miss - * these, and clear the flag now. - */ - eeh_clear_slot(dn, EEH_MODE_ISOLATED); + * these, and clear the flag now. */ + eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED); - eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); + rtas_pci_slot_reset (pdn, 0); /* After a PCI slot has been reset, the PCI Express spec requires * a 1.5 second idle time for the bus to stabilize, before starting - * up traffic. - */ + * up traffic. */ #define PCI_BUS_SETTLE_TIME_MSEC 1800 - msleep(PCI_BUS_SETTLE_TIME_MSEC); + msleep (PCI_BUS_SETTLE_TIME_MSEC); } -/** - * eeh_reset_pe - Reset the indicated PE - * @edev: PCI device associated EEH device - * - * This routine should be called to reset indicated device, including - * PE. A PE might include multiple PCI devices and sometimes PCI bridges - * might be involved as well. - */ -int eeh_reset_pe(struct eeh_dev *edev) +int rtas_set_slot_reset(struct pci_dn *pdn) { int i, rc; - struct device_node *dn = eeh_dev_to_of_node(edev); /* Take three shots at resetting the bus */ for (i=0; i<3; i++) { - eeh_reset_pe_once(edev); + __rtas_set_slot_reset(pdn); - rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); - if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) + rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC); + if (rc == 0) return 0; if (rc < 0) { printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", - dn->full_name); + pdn->node->full_name); return -1; } printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", - i+1, dn->full_name, rc); + i+1, pdn->node->full_name, rc); } return -1; } +/* ------------------------------------------------------- */ /** Save and restore of PCI BARs * * Although firmware will set up BARs during boot, it doesn't @@ -729,122 +856,181 @@ int eeh_reset_pe(struct eeh_dev *edev) */ /** - * eeh_restore_one_device_bars - Restore the Base Address Registers for one device - * @edev: PCI device associated EEH device + * __restore_bars - Restore the Base Address Registers + * @pdn: pci device node * * Loads the PCI configuration space base address registers, * the expansion ROM base address, the latency timer, and etc. * from the saved values in the device node. */ -static inline void eeh_restore_one_device_bars(struct eeh_dev *edev) +static inline void __restore_bars (struct pci_dn *pdn) { int i; u32 cmd; - struct device_node *dn = eeh_dev_to_of_node(edev); - - if (!edev->phb) - return; + if (NULL==pdn->phb) return; for (i=4; i<10; i++) { - eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); + rtas_write_config(pdn, i*4, 4, pdn->config_space[i]); } /* 12 == Expansion ROM Address */ - eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); + rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]); #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) -#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) +#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)]) - eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, + rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1, SAVED_BYTE(PCI_CACHE_LINE_SIZE)); - eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, + rtas_write_config (pdn, PCI_LATENCY_TIMER, 1, SAVED_BYTE(PCI_LATENCY_TIMER)); /* max latency, min grant, interrupt pin and line */ - eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); + rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]); /* Restore PERR & SERR bits, some devices require it, - * don't touch the other command bits - */ - eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); - if (edev->config_space[1] & PCI_COMMAND_PARITY) + don't touch the other command bits */ + rtas_read_config(pdn, PCI_COMMAND, 4, &cmd); + if (pdn->config_space[1] & PCI_COMMAND_PARITY) cmd |= PCI_COMMAND_PARITY; else cmd &= ~PCI_COMMAND_PARITY; - if (edev->config_space[1] & PCI_COMMAND_SERR) + if (pdn->config_space[1] & PCI_COMMAND_SERR) cmd |= PCI_COMMAND_SERR; else cmd &= ~PCI_COMMAND_SERR; - eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); + rtas_write_config(pdn, PCI_COMMAND, 4, cmd); } /** - * eeh_restore_bars - Restore the PCI config space info - * @edev: EEH device + * eeh_restore_bars - restore the PCI config space info * * This routine performs a recursive walk to the children * of this device as well. */ -void eeh_restore_bars(struct eeh_dev *edev) +void eeh_restore_bars(struct pci_dn *pdn) { struct device_node *dn; - if (!edev) + if (!pdn) return; - if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code)) - eeh_restore_one_device_bars(edev); + if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code)) + __restore_bars (pdn); - for_each_child_of_node(eeh_dev_to_of_node(edev), dn) - eeh_restore_bars(of_node_to_eeh_dev(dn)); + for_each_child_of_node(pdn->node, dn) + eeh_restore_bars (PCI_DN(dn)); } /** - * eeh_save_bars - Save device bars - * @edev: PCI device associated EEH device + * eeh_save_bars - save device bars * * Save the values of the device bars. Unlike the restore * routine, this routine is *not* recursive. This is because * PCI devices are added individually; but, for the restore, * an entire slot is reset at a time. */ -static void eeh_save_bars(struct eeh_dev *edev) +static void eeh_save_bars(struct pci_dn *pdn) { int i; - struct device_node *dn; - if (!edev) + if (!pdn ) return; - dn = eeh_dev_to_of_node(edev); for (i = 0; i < 16; i++) - eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]); + rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]); } -/** - * eeh_early_enable - Early enable EEH on the indicated device - * @dn: device node - * @data: BUID - * - * Enable EEH functionality on the specified PCI device. The function - * is expected to be called before real PCI probing is done. However, - * the PHBs have been initialized at this point. +void +rtas_configure_bridge(struct pci_dn *pdn) +{ + int config_addr; + int rc; + int token; + + /* Use PE configuration address, if present */ + config_addr = pdn->eeh_config_addr; + if (pdn->eeh_pe_config_addr) + config_addr = pdn->eeh_pe_config_addr; + + /* Use new configure-pe function, if supported */ + if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) + token = ibm_configure_pe; + else + token = ibm_configure_bridge; + + rc = rtas_call(token, 3, 1, NULL, + config_addr, + BUID_HI(pdn->phb->buid), + BUID_LO(pdn->phb->buid)); + if (rc) { + printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", + rc, pdn->node->full_name); + } +} + +/* ------------------------------------------------------------- */ +/* The code below deals with enabling EEH for devices during the + * early boot sequence. EEH must be enabled before any PCI probing + * can be done. */ -static void *eeh_early_enable(struct device_node *dn, void *data) + +#define EEH_ENABLE 1 + +struct eeh_early_enable_info { + unsigned int buid_hi; + unsigned int buid_lo; +}; + +static int get_pe_addr (int config_addr, + struct eeh_early_enable_info *info) { + unsigned int rets[3]; + int ret; + + /* Use latest config-addr token on power6 */ + if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { + /* Make sure we have a PE in hand */ + ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, + config_addr, info->buid_hi, info->buid_lo, 1); + if (ret || (rets[0]==0)) + return 0; + + ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, + config_addr, info->buid_hi, info->buid_lo, 0); + if (ret) + return 0; + return rets[0]; + } + + /* Use older config-addr token on power5 */ + if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { + ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, + config_addr, info->buid_hi, info->buid_lo, 0); + if (ret) + return 0; + return rets[0]; + } + return 0; +} + +/* Enable eeh for the given device node. */ +static void *early_enable_eeh(struct device_node *dn, void *data) +{ + unsigned int rets[3]; + struct eeh_early_enable_info *info = data; int ret; const u32 *class_code = of_get_property(dn, "class-code", NULL); const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); const u32 *device_id = of_get_property(dn, "device-id", NULL); const u32 *regs; int enable; - struct eeh_dev *edev = of_node_to_eeh_dev(dn); + struct pci_dn *pdn = PCI_DN(dn); - edev->class_code = 0; - edev->mode = 0; - edev->check_count = 0; - edev->freeze_count = 0; - edev->false_positives = 0; + pdn->class_code = 0; + pdn->eeh_mode = 0; + pdn->eeh_check_count = 0; + pdn->eeh_freeze_count = 0; + pdn->eeh_false_positives = 0; if (!of_device_is_available(dn)) return NULL; @@ -855,56 +1041,54 @@ static void *eeh_early_enable(struct device_node *dn, void *data) /* There is nothing to check on PCI to ISA bridges */ if (dn->type && !strcmp(dn->type, "isa")) { - edev->mode |= EEH_MODE_NOCHECK; + pdn->eeh_mode |= EEH_MODE_NOCHECK; return NULL; } - edev->class_code = *class_code; + pdn->class_code = *class_code; /* Ok... see if this device supports EEH. Some do, some don't, - * and the only way to find out is to check each and every one. - */ + * and the only way to find out is to check each and every one. */ regs = of_get_property(dn, "reg", NULL); if (regs) { /* First register entry is addr (00BBSS00) */ /* Try to enable eeh */ - ret = eeh_ops->set_option(dn, EEH_OPT_ENABLE); + ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, + regs[0], info->buid_hi, info->buid_lo, + EEH_ENABLE); enable = 0; if (ret == 0) { - edev->config_addr = regs[0]; + pdn->eeh_config_addr = regs[0]; /* If the newer, better, ibm,get-config-addr-info is supported, - * then use that instead. - */ - edev->pe_config_addr = eeh_ops->get_pe_addr(dn); + * then use that instead. */ + pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info); /* Some older systems (Power4) allow the * ibm,set-eeh-option call to succeed even on nodes * where EEH is not supported. Verify support - * explicitly. - */ - ret = eeh_ops->get_state(dn, NULL); - if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT) + * explicitly. */ + ret = read_slot_reset_state(pdn, rets); + if ((ret == 0) && (rets[1] == 1)) enable = 1; } if (enable) { eeh_subsystem_enabled = 1; - edev->mode |= EEH_MODE_SUPPORTED; + pdn->eeh_mode |= EEH_MODE_SUPPORTED; pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", - dn->full_name, edev->config_addr, - edev->pe_config_addr); + dn->full_name, pdn->eeh_config_addr, + pdn->eeh_pe_config_addr); } else { /* This device doesn't support EEH, but it may have an - * EEH parent, in which case we mark it as supported. - */ - if (dn->parent && of_node_to_eeh_dev(dn->parent) && - (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { + * EEH parent, in which case we mark it as supported. */ + if (dn->parent && PCI_DN(dn->parent) + && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { /* Parent supports EEH. */ - edev->mode |= EEH_MODE_SUPPORTED; - edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr; + pdn->eeh_mode |= EEH_MODE_SUPPORTED; + pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr; return NULL; } } @@ -913,63 +1097,11 @@ static void *eeh_early_enable(struct device_node *dn, void *data) dn->full_name); } - eeh_save_bars(edev); + eeh_save_bars(pdn); return NULL; } -/** - * eeh_ops_register - Register platform dependent EEH operations - * @ops: platform dependent EEH operations - * - * Register the platform dependent EEH operation callback - * functions. The platform should call this function before - * any other EEH operations. - */ -int __init eeh_ops_register(struct eeh_ops *ops) -{ - if (!ops->name) { - pr_warning("%s: Invalid EEH ops name for %p\n", - __func__, ops); - return -EINVAL; - } - - if (eeh_ops && eeh_ops != ops) { - pr_warning("%s: EEH ops of platform %s already existing (%s)\n", - __func__, eeh_ops->name, ops->name); - return -EEXIST; - } - - eeh_ops = ops; - - return 0; -} - -/** - * eeh_ops_unregister - Unreigster platform dependent EEH operations - * @name: name of EEH platform operations - * - * Unregister the platform dependent EEH operation callback - * functions. - */ -int __exit eeh_ops_unregister(const char *name) -{ - if (!name || !strlen(name)) { - pr_warning("%s: Invalid EEH ops name\n", - __func__); - return -EINVAL; - } - - if (eeh_ops && !strcmp(eeh_ops->name, name)) { - eeh_ops = NULL; - return 0; - } - - return -EEXIST; -} - -/** - * eeh_init - EEH initialization - * +/* * Initialize EEH by trying to enable it for all of the adapters in the system. * As a side effect we can determine here if eeh is supported at all. * Note that we leave EEH on so failed config cycles won't cause a machine @@ -985,35 +1117,50 @@ int __exit eeh_ops_unregister(const char *name) void __init eeh_init(void) { struct device_node *phb, *np; - int ret; - - /* call platform initialization function */ - if (!eeh_ops) { - pr_warning("%s: Platform EEH operation not found\n", - __func__); - return; - } else if ((ret = eeh_ops->init())) { - pr_warning("%s: Failed to call platform init function (%d)\n", - __func__, ret); - return; - } + struct eeh_early_enable_info info; raw_spin_lock_init(&confirm_error_lock); + spin_lock_init(&slot_errbuf_lock); np = of_find_node_by_path("/rtas"); if (np == NULL) return; + ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); + ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); + ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); + ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); + ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); + ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); + ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); + ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); + ibm_configure_pe = rtas_token("ibm,configure-pe"); + + if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) + return; + + eeh_error_buf_size = rtas_token("rtas-error-log-max"); + if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { + eeh_error_buf_size = 1024; + } + if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { + printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated " + "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX); + eeh_error_buf_size = RTAS_ERROR_LOG_MAX; + } + /* Enable EEH for all adapters. Note that eeh requires buid's */ for (phb = of_find_node_by_name(NULL, "pci"); phb; phb = of_find_node_by_name(phb, "pci")) { unsigned long buid; buid = get_phb_buid(phb); - if (buid == 0 || !of_node_to_eeh_dev(phb)) + if (buid == 0 || PCI_DN(phb) == NULL) continue; - traverse_pci_devices(phb, eeh_early_enable, NULL); + info.buid_lo = BUID_LO(buid); + info.buid_hi = BUID_HI(buid); + traverse_pci_devices(phb, early_enable_eeh, &info); } if (eeh_subsystem_enabled) @@ -1023,7 +1170,7 @@ void __init eeh_init(void) } /** - * eeh_add_device_early - Enable EEH for the indicated device_node + * eeh_add_device_early - enable EEH for the indicated device_node * @dn: device node for which to set up EEH * * This routine must be used to perform EEH initialization for PCI @@ -1037,26 +1184,21 @@ void __init eeh_init(void) static void eeh_add_device_early(struct device_node *dn) { struct pci_controller *phb; + struct eeh_early_enable_info info; - if (!dn || !of_node_to_eeh_dev(dn)) + if (!dn || !PCI_DN(dn)) return; - phb = of_node_to_eeh_dev(dn)->phb; + phb = PCI_DN(dn)->phb; /* USB Bus children of PCI devices will not have BUID's */ if (NULL == phb || 0 == phb->buid) return; - eeh_early_enable(dn, NULL); + info.buid_hi = BUID_HI(phb->buid); + info.buid_lo = BUID_LO(phb->buid); + early_enable_eeh(dn, &info); } -/** - * eeh_add_device_tree_early - Enable EEH for the indicated device - * @dn: device node - * - * This routine must be used to perform EEH initialization for the - * indicated PCI device that was added after system boot (e.g. - * hotplug, dlpar). - */ void eeh_add_device_tree_early(struct device_node *dn) { struct device_node *sib; @@ -1068,7 +1210,7 @@ void eeh_add_device_tree_early(struct device_node *dn) EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); /** - * eeh_add_device_late - Perform EEH initialization for the indicated pci device + * eeh_add_device_late - perform EEH initialization for the indicated pci device * @dev: pci device for which to set up EEH * * This routine must be used to complete EEH initialization for PCI @@ -1077,7 +1219,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); static void eeh_add_device_late(struct pci_dev *dev) { struct device_node *dn; - struct eeh_dev *edev; + struct pci_dn *pdn; if (!dev || !eeh_subsystem_enabled) return; @@ -1085,29 +1227,20 @@ static void eeh_add_device_late(struct pci_dev *dev) pr_debug("EEH: Adding device %s\n", pci_name(dev)); dn = pci_device_to_OF_node(dev); - edev = pci_dev_to_eeh_dev(dev); - if (edev->pdev == dev) { + pdn = PCI_DN(dn); + if (pdn->pcidev == dev) { pr_debug("EEH: Already referenced !\n"); return; } - WARN_ON(edev->pdev); + WARN_ON(pdn->pcidev); - pci_dev_get(dev); - edev->pdev = dev; - dev->dev.archdata.edev = edev; + pci_dev_get (dev); + pdn->pcidev = dev; pci_addr_cache_insert_device(dev); eeh_sysfs_add_device(dev); } -/** - * eeh_add_device_tree_late - Perform EEH initialization for the indicated PCI bus - * @bus: PCI bus - * - * This routine must be used to perform EEH initialization for PCI - * devices which are attached to the indicated PCI bus. The PCI bus - * is added after system boot through hotplug or dlpar. - */ void eeh_add_device_tree_late(struct pci_bus *bus) { struct pci_dev *dev; @@ -1124,7 +1257,7 @@ void eeh_add_device_tree_late(struct pci_bus *bus) EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); /** - * eeh_remove_device - Undo EEH setup for the indicated pci device + * eeh_remove_device - undo EEH setup for the indicated pci device * @dev: pci device to be removed * * This routine should be called when a device is removed from @@ -1135,35 +1268,25 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); */ static void eeh_remove_device(struct pci_dev *dev) { - struct eeh_dev *edev; - + struct device_node *dn; if (!dev || !eeh_subsystem_enabled) return; - edev = pci_dev_to_eeh_dev(dev); /* Unregister the device with the EEH/PCI address search system */ pr_debug("EEH: Removing device %s\n", pci_name(dev)); - if (!edev || !edev->pdev) { + dn = pci_device_to_OF_node(dev); + if (PCI_DN(dn)->pcidev == NULL) { pr_debug("EEH: Not referenced !\n"); return; } - edev->pdev = NULL; - dev->dev.archdata.edev = NULL; - pci_dev_put(dev); + PCI_DN(dn)->pcidev = NULL; + pci_dev_put (dev); pci_addr_cache_remove_device(dev); eeh_sysfs_remove_device(dev); } -/** - * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device - * @dev: PCI device - * - * This routine must be called when a device is removed from the - * running system through hotplug or dlpar. The corresponding - * PCI address cache will be removed. - */ void eeh_remove_bus_device(struct pci_dev *dev) { struct pci_bus *bus = dev->subordinate; @@ -1182,24 +1305,21 @@ static int proc_eeh_show(struct seq_file *m, void *v) { if (0 == eeh_subsystem_enabled) { seq_printf(m, "EEH Subsystem is globally disabled\n"); - seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); + seq_printf(m, "eeh_total_mmio_ffs=%ld\n", total_mmio_ffs); } else { seq_printf(m, "EEH Subsystem is enabled\n"); seq_printf(m, - "no device=%llu\n" - "no device node=%llu\n" - "no config address=%llu\n" - "check not wanted=%llu\n" - "eeh_total_mmio_ffs=%llu\n" - "eeh_false_positives=%llu\n" - "eeh_slot_resets=%llu\n", - eeh_stats.no_device, - eeh_stats.no_dn, - eeh_stats.no_cfg_addr, - eeh_stats.ignored_check, - eeh_stats.total_mmio_ffs, - eeh_stats.false_positives, - eeh_stats.slot_resets); + "no device=%ld\n" + "no device node=%ld\n" + "no config address=%ld\n" + "check not wanted=%ld\n" + "eeh_total_mmio_ffs=%ld\n" + "eeh_false_positives=%ld\n" + "eeh_slot_resets=%ld\n", + no_device, no_dn, no_cfg_addr, + ignored_check, total_mmio_ffs, + false_positives, + slot_resets); } return 0; diff --git a/trunk/arch/powerpc/platforms/pseries/eeh_cache.c b/trunk/arch/powerpc/platforms/pseries/eeh_cache.c index e5ae1c687c66..fc5ae767989e 100644 --- a/trunk/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/trunk/arch/powerpc/platforms/pseries/eeh_cache.c @@ -1,4 +1,5 @@ /* + * eeh_cache.c * PCI address cache; allows the lookup of PCI devices based on I/O address * * Copyright IBM Corporation 2004 @@ -46,7 +47,8 @@ * than any hash algo I could think of for this problem, even * with the penalty of slow pointer chases for d-cache misses). */ -struct pci_io_addr_range { +struct pci_io_addr_range +{ struct rb_node rb_node; unsigned long addr_lo; unsigned long addr_hi; @@ -54,12 +56,13 @@ struct pci_io_addr_range { unsigned int flags; }; -static struct pci_io_addr_cache { +static struct pci_io_addr_cache +{ struct rb_root rb_root; spinlock_t piar_lock; } pci_io_addr_cache_root; -static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) +static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) { struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; @@ -83,7 +86,7 @@ static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) } /** - * pci_addr_cache_get_device - Get device, given only address + * pci_get_device_by_addr - Get device, given only address * @addr: mmio (PIO) phys address or i/o port number * * Given an mmio phys address, or a port number, find a pci device @@ -92,13 +95,13 @@ static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) * from zero (that is, they do *not* have pci_io_addr added in). * It is safe to call this function within an interrupt. */ -struct pci_dev *pci_addr_cache_get_device(unsigned long addr) +struct pci_dev *pci_get_device_by_addr(unsigned long addr) { struct pci_dev *dev; unsigned long flags; spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); - dev = __pci_addr_cache_get_device(addr); + dev = __pci_get_device_by_addr(addr); spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); return dev; } @@ -163,7 +166,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, #ifdef DEBUG printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", - alo, ahi, pci_name(dev)); + alo, ahi, pci_name (dev)); #endif rb_link_node(&piar->rb_node, parent, p); @@ -175,7 +178,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, static void __pci_addr_cache_insert_device(struct pci_dev *dev) { struct device_node *dn; - struct eeh_dev *edev; + struct pci_dn *pdn; int i; dn = pci_device_to_OF_node(dev); @@ -184,19 +187,13 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) return; } - edev = of_node_to_eeh_dev(dn); - if (!edev) { - pr_warning("PCI: no EEH dev found for dn=%s\n", - dn->full_name); - return; - } - /* Skip any devices for which EEH is not enabled. */ - if (!(edev->mode & EEH_MODE_SUPPORTED) || - edev->mode & EEH_MODE_NOCHECK) { + pdn = PCI_DN(dn); + if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || + pdn->eeh_mode & EEH_MODE_NOCHECK) { #ifdef DEBUG - pr_info("PCI: skip building address cache for=%s - %s\n", - pci_name(dev), dn->full_name); + printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n", + pci_name(dev), pdn->node->full_name); #endif return; } @@ -287,7 +284,6 @@ void pci_addr_cache_remove_device(struct pci_dev *dev) void __init pci_addr_cache_build(void) { struct device_node *dn; - struct eeh_dev *edev; struct pci_dev *dev = NULL; spin_lock_init(&pci_io_addr_cache_root.piar_lock); @@ -298,14 +294,8 @@ void __init pci_addr_cache_build(void) dn = pci_device_to_OF_node(dev); if (!dn) continue; - - edev = of_node_to_eeh_dev(dn); - if (!edev) - continue; - pci_dev_get(dev); /* matching put is in eeh_remove_device() */ - dev->dev.archdata.edev = edev; - edev->pdev = dev; + PCI_DN(dn)->pcidev = dev; eeh_sysfs_add_device(dev); } diff --git a/trunk/arch/powerpc/platforms/pseries/eeh_dev.c b/trunk/arch/powerpc/platforms/pseries/eeh_dev.c deleted file mode 100644 index f3aed7dcae95..000000000000 --- a/trunk/arch/powerpc/platforms/pseries/eeh_dev.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * The file intends to implement dynamic creation of EEH device, which will - * be bound with OF node and PCI device simutaneously. The EEH devices would - * be foundamental information for EEH core components to work proerly. Besides, - * We have to support multiple situations where dynamic creation of EEH device - * is required: - * - * 1) Before PCI emunation starts, we need create EEH devices according to the - * PCI sensitive OF nodes. - * 2) When PCI emunation is done, we need do the binding between PCI device and - * the associated EEH device. - * 3) DR (Dynamic Reconfiguration) would create PCI sensitive OF node. EEH device - * will be created while PCI sensitive OF node is detected from DR. - * 4) PCI hotplug needs redoing the binding between PCI device and EEH device. If - * PHB is newly inserted, we also need create EEH devices accordingly. - * - * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -/** - * eeh_dev_init - Create EEH device according to OF node - * @dn: device node - * @data: PHB - * - * It will create EEH device according to the given OF node. The function - * might be called by PCI emunation, DR, PHB hotplug. - */ -void * __devinit eeh_dev_init(struct device_node *dn, void *data) -{ - struct pci_controller *phb = data; - struct eeh_dev *edev; - - /* Allocate EEH device */ - edev = zalloc_maybe_bootmem(sizeof(*edev), GFP_KERNEL); - if (!edev) { - pr_warning("%s: out of memory\n", __func__); - return NULL; - } - - /* Associate EEH device with OF node */ - dn->edev = edev; - edev->dn = dn; - edev->phb = phb; - - return NULL; -} - -/** - * eeh_dev_phb_init_dynamic - Create EEH devices for devices included in PHB - * @phb: PHB - * - * Scan the PHB OF node and its child association, then create the - * EEH devices accordingly - */ -void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb) -{ - struct device_node *dn = phb->dn; - - /* EEH device for PHB */ - eeh_dev_init(dn, phb); - - /* EEH devices for children OF nodes */ - traverse_pci_devices(dn, eeh_dev_init, phb); -} - -/** - * eeh_dev_phb_init - Create EEH devices for devices included in existing PHBs - * - * Scan all the existing PHBs and create EEH devices for their OF - * nodes and their children OF nodes - */ -void __init eeh_dev_phb_init(void) -{ - struct pci_controller *phb, *tmp; - - list_for_each_entry_safe(phb, tmp, &hose_list, list_node) - eeh_dev_phb_init_dynamic(phb); -} diff --git a/trunk/arch/powerpc/platforms/pseries/eeh_driver.c b/trunk/arch/powerpc/platforms/pseries/eeh_driver.c index baf92cd9dfab..1b6cb10589e0 100644 --- a/trunk/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/trunk/arch/powerpc/platforms/pseries/eeh_driver.c @@ -33,14 +33,8 @@ #include #include -/** - * eeh_pcid_name - Retrieve name of PCI device driver - * @pdev: PCI device - * - * This routine is used to retrieve the name of PCI device driver - * if that's valid. - */ -static inline const char *eeh_pcid_name(struct pci_dev *pdev) + +static inline const char * pcid_name (struct pci_dev *pdev) { if (pdev && pdev->dev.driver) return pdev->dev.driver->name; @@ -70,59 +64,48 @@ static void print_device_node_tree(struct pci_dn *pdn, int dent) #endif /** - * eeh_disable_irq - Disable interrupt for the recovering device - * @dev: PCI device - * - * This routine must be called when reporting temporary or permanent - * error to the particular PCI device to disable interrupt of that - * device. If the device has enabled MSI or MSI-X interrupt, we needn't - * do real work because EEH should freeze DMA transfers for those PCI - * devices encountering EEH errors, which includes MSI or MSI-X. + * eeh_disable_irq - disable interrupt for the recovering device */ static void eeh_disable_irq(struct pci_dev *dev) { - struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); + struct device_node *dn = pci_device_to_OF_node(dev); /* Don't disable MSI and MSI-X interrupts. They are * effectively disabled by the DMA Stopped state * when an EEH error occurs. - */ + */ if (dev->msi_enabled || dev->msix_enabled) return; if (!irq_has_action(dev->irq)) return; - edev->mode |= EEH_MODE_IRQ_DISABLED; + PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; disable_irq_nosync(dev->irq); } /** - * eeh_enable_irq - Enable interrupt for the recovering device - * @dev: PCI device - * - * This routine must be called to enable interrupt while failed - * device could be resumed. + * eeh_enable_irq - enable interrupt for the recovering device */ static void eeh_enable_irq(struct pci_dev *dev) { - struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); + struct device_node *dn = pci_device_to_OF_node(dev); - if ((edev->mode) & EEH_MODE_IRQ_DISABLED) { - edev->mode &= ~EEH_MODE_IRQ_DISABLED; + if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { + PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; enable_irq(dev->irq); } } +/* ------------------------------------------------------- */ /** - * eeh_report_error - Report pci error to each device driver - * @dev: PCI device - * @userdata: return value + * eeh_report_error - report pci error to each device driver * * Report an EEH error to each device driver, collect up and * merge the device driver responses. Cumulative response * passed back in "userdata". */ + static int eeh_report_error(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; @@ -139,7 +122,7 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) !driver->err_handler->error_detected) return 0; - rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); + rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen); /* A driver that needs a reset trumps all others */ if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; @@ -149,14 +132,13 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) } /** - * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled - * @dev: PCI device - * @userdata: return value + * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled * * Tells each device driver that IO ports, MMIO and config space I/O * are now enabled. Collects up and merges the device driver responses. * Cumulative response passed back in "userdata". */ + static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; @@ -167,7 +149,7 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) !driver->err_handler->mmio_enabled) return 0; - rc = driver->err_handler->mmio_enabled(dev); + rc = driver->err_handler->mmio_enabled (dev); /* A driver that needs a reset trumps all others */ if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; @@ -177,15 +159,9 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) } /** - * eeh_report_reset - Tell device that slot has been reset - * @dev: PCI device - * @userdata: return value - * - * This routine must be called while EEH tries to reset particular - * PCI device so that the associated PCI device driver could take - * some actions, usually to save data the driver needs so that the - * driver can work again while the device is recovered. + * eeh_report_reset - tell device that slot has been reset */ + static int eeh_report_reset(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; @@ -212,14 +188,9 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata) } /** - * eeh_report_resume - Tell device to resume normal operations - * @dev: PCI device - * @userdata: return value - * - * This routine must be called to notify the device driver that it - * could resume so that the device driver can do some initialization - * to make the recovered device work again. + * eeh_report_resume - tell device to resume normal operations */ + static int eeh_report_resume(struct pci_dev *dev, void *userdata) { struct pci_driver *driver = dev->driver; @@ -241,13 +212,12 @@ static int eeh_report_resume(struct pci_dev *dev, void *userdata) } /** - * eeh_report_failure - Tell device driver that device is dead. - * @dev: PCI device - * @userdata: return value + * eeh_report_failure - tell device driver that device is dead. * * This informs the device driver that the device is permanently * dead, and that no further recovery attempts will be made on it. */ + static int eeh_report_failure(struct pci_dev *dev, void *userdata) { struct pci_driver *driver = dev->driver; @@ -268,46 +238,65 @@ static int eeh_report_failure(struct pci_dev *dev, void *userdata) return 0; } +/* ------------------------------------------------------- */ /** - * eeh_reset_device - Perform actual reset of a pci slot - * @edev: PE associated EEH device - * @bus: PCI bus corresponding to the isolcated slot + * handle_eeh_events -- reset a PCI device after hard lockup. + * + * pSeries systems will isolate a PCI slot if the PCI-Host + * bridge detects address or data parity errors, DMA's + * occurring to wild addresses (which usually happen due to + * bugs in device drivers or in PCI adapter firmware). + * Slot isolations also occur if #SERR, #PERR or other misc + * PCI-related errors are detected. * - * This routine must be called to do reset on the indicated PE. - * During the reset, udev might be invoked because those affected - * PCI devices will be removed and then added. + * Recovery process consists of unplugging the device driver + * (which generated hotplug events to userspace), then issuing + * a PCI #RST to the device, then reconfiguring the PCI config + * space for all bridges & devices under this slot, and then + * finally restarting the device drivers (which cause a second + * set of hotplug events to go out to userspace). */ -static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) + +/** + * eeh_reset_device() -- perform actual reset of a pci slot + * @bus: pointer to the pci bus structure corresponding + * to the isolated slot. A non-null value will + * cause all devices under the bus to be removed + * and then re-added. + * @pe_dn: pointer to a "Partionable Endpoint" device node. + * This is the top-level structure on which pci + * bus resets can be performed. + */ + +static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) { struct device_node *dn; int cnt, rc; /* pcibios will clear the counter; save the value */ - cnt = edev->freeze_count; + cnt = pe_dn->eeh_freeze_count; if (bus) pcibios_remove_pci_devices(bus); /* Reset the pci controller. (Asserts RST#; resets config space). * Reconfigure bridges and devices. Don't try to bring the system - * up if the reset failed for some reason. - */ - rc = eeh_reset_pe(edev); + * up if the reset failed for some reason. */ + rc = rtas_set_slot_reset(pe_dn); if (rc) return rc; - /* Walk over all functions on this device. */ - dn = eeh_dev_to_of_node(edev); - if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) + /* Walk over all functions on this device. */ + dn = pe_dn->node; + if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) dn = dn->parent->child; while (dn) { - struct eeh_dev *pedev = of_node_to_eeh_dev(dn); - + struct pci_dn *ppe = PCI_DN(dn); /* On Power4, always true because eeh_pe_config_addr=0 */ - if (edev->pe_config_addr == pedev->pe_config_addr) { - eeh_ops->configure_bridge(dn); - eeh_restore_bars(pedev); + if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { + rtas_configure_bridge(ppe); + eeh_restore_bars(ppe); } dn = dn->sibling; } @@ -319,10 +308,10 @@ static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) * potentially weird things happen. */ if (bus) { - ssleep(5); + ssleep (5); pcibios_add_pci_devices(bus); } - edev->freeze_count = cnt; + pe_dn->eeh_freeze_count = cnt; return 0; } @@ -332,39 +321,23 @@ static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) */ #define MAX_WAIT_FOR_RECOVERY 150 -/** - * eeh_handle_event - Reset a PCI device after hard lockup. - * @event: EEH event - * - * While PHB detects address or data parity errors on particular PCI - * slot, the associated PE will be frozen. Besides, DMA's occurring - * to wild addresses (which usually happen due to bugs in device - * drivers or in PCI adapter firmware) can cause EEH error. #SERR, - * #PERR or other misc PCI-related errors also can trigger EEH errors. - * - * Recovery process consists of unplugging the device driver (which - * generated hotplug events to userspace), then issuing a PCI #RST to - * the device, then reconfiguring the PCI config space for all bridges - * & devices under this slot, and then finally restarting the device - * drivers (which cause a second set of hotplug events to go out to - * userspace). - */ -struct eeh_dev *handle_eeh_events(struct eeh_event *event) +struct pci_dn * handle_eeh_events (struct eeh_event *event) { struct device_node *frozen_dn; - struct eeh_dev *frozen_edev; + struct pci_dn *frozen_pdn; struct pci_bus *frozen_bus; int rc = 0; enum pci_ers_result result = PCI_ERS_RESULT_NONE; const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; - frozen_dn = eeh_find_device_pe(eeh_dev_to_of_node(event->edev)); + frozen_dn = find_device_pe(event->dn); if (!frozen_dn) { - location = of_get_property(eeh_dev_to_of_node(event->edev), "ibm,loc-code", NULL); + + location = of_get_property(event->dn, "ibm,loc-code", NULL); location = location ? location : "unknown"; printk(KERN_ERR "EEH: Error: Cannot find partition endpoint " "for location=%s pci addr=%s\n", - location, eeh_pci_name(eeh_dev_to_pci_dev(event->edev))); + location, eeh_pci_name(event->dev)); return NULL; } @@ -377,10 +350,9 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) * which was always an EADS pci bridge. In the new style, * there might not be any EADS bridges, and even when there are, * the firmware marks them as "EEH incapable". So another - * two-step is needed to find the pci bus.. - */ + * two-step is needed to find the pci bus.. */ if (!frozen_bus) - frozen_bus = pcibios_find_pci_bus(frozen_dn->parent); + frozen_bus = pcibios_find_pci_bus (frozen_dn->parent); if (!frozen_bus) { printk(KERN_ERR "EEH: Cannot find PCI bus " @@ -389,21 +361,22 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) return NULL; } - frozen_edev = of_node_to_eeh_dev(frozen_dn); - frozen_edev->freeze_count++; - pci_str = eeh_pci_name(eeh_dev_to_pci_dev(event->edev)); - drv_str = eeh_pcid_name(eeh_dev_to_pci_dev(event->edev)); + frozen_pdn = PCI_DN(frozen_dn); + frozen_pdn->eeh_freeze_count++; - if (frozen_edev->freeze_count > EEH_MAX_ALLOWED_FREEZES) + pci_str = eeh_pci_name(event->dev); + drv_str = pcid_name(event->dev); + + if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) goto excess_failures; printk(KERN_WARNING "EEH: This PCI device has failed %d times in the last hour:\n", - frozen_edev->freeze_count); + frozen_pdn->eeh_freeze_count); - if (frozen_edev->pdev) { - bus_pci_str = pci_name(frozen_edev->pdev); - bus_drv_str = eeh_pcid_name(frozen_edev->pdev); + if (frozen_pdn->pcidev) { + bus_pci_str = pci_name(frozen_pdn->pcidev); + bus_drv_str = pcid_name(frozen_pdn->pcidev); printk(KERN_WARNING "EEH: Bus location=%s driver=%s pci addr=%s\n", location, bus_drv_str, bus_pci_str); @@ -422,10 +395,9 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) pci_walk_bus(frozen_bus, eeh_report_error, &result); /* Get the current PCI slot state. This can take a long time, - * sometimes over 3 seconds for certain systems. - */ - rc = eeh_ops->wait_state(eeh_dev_to_of_node(frozen_edev), MAX_WAIT_FOR_RECOVERY*1000); - if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { + * sometimes over 3 seconds for certain systems. */ + rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000); + if (rc < 0) { printk(KERN_WARNING "EEH: Permanent failure\n"); goto hard_fail; } @@ -434,14 +406,14 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) * don't post the error log until after all dev drivers * have been informed. */ - eeh_slot_error_detail(frozen_edev, EEH_LOG_TEMP); + eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE); /* If all device drivers were EEH-unaware, then shut * down all of the device drivers, and hope they * go down willingly, without panicing the system. */ if (result == PCI_ERS_RESULT_NONE) { - rc = eeh_reset_device(frozen_edev, frozen_bus); + rc = eeh_reset_device(frozen_pdn, frozen_bus); if (rc) { printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); goto hard_fail; @@ -450,7 +422,7 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) /* If all devices reported they can proceed, then re-enable MMIO */ if (result == PCI_ERS_RESULT_CAN_RECOVER) { - rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_MMIO); + rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO); if (rc < 0) goto hard_fail; @@ -464,7 +436,7 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) /* If all devices reported they can proceed, then re-enable DMA */ if (result == PCI_ERS_RESULT_CAN_RECOVER) { - rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_DMA); + rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA); if (rc < 0) goto hard_fail; @@ -482,7 +454,7 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) /* If any device called out for a reset, then reset the slot */ if (result == PCI_ERS_RESULT_NEED_RESET) { - rc = eeh_reset_device(frozen_edev, NULL); + rc = eeh_reset_device(frozen_pdn, NULL); if (rc) { printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); goto hard_fail; @@ -501,7 +473,7 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) /* Tell all device drivers that they can resume operations */ pci_walk_bus(frozen_bus, eeh_report_resume, NULL); - return frozen_edev; + return frozen_pdn; excess_failures: /* @@ -514,7 +486,7 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) "has failed %d times in the last hour " "and has been permanently disabled.\n" "Please try reseating this device or replacing it.\n", - location, drv_str, pci_str, frozen_edev->freeze_count); + location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); goto perm_error; hard_fail: @@ -525,7 +497,7 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) location, drv_str, pci_str); perm_error: - eeh_slot_error_detail(frozen_edev, EEH_LOG_PERM); + eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE); /* Notify all devices that they're about to go down. */ pci_walk_bus(frozen_bus, eeh_report_failure, NULL); @@ -536,3 +508,4 @@ struct eeh_dev *handle_eeh_events(struct eeh_event *event) return NULL; } +/* ---------- end of file ---------- */ diff --git a/trunk/arch/powerpc/platforms/pseries/eeh_event.c b/trunk/arch/powerpc/platforms/pseries/eeh_event.c index 4a4752565856..d2383cfb6dfd 100644 --- a/trunk/arch/powerpc/platforms/pseries/eeh_event.c +++ b/trunk/arch/powerpc/platforms/pseries/eeh_event.c @@ -1,4 +1,6 @@ /* + * eeh_event.c + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -44,7 +46,7 @@ DECLARE_WORK(eeh_event_wq, eeh_thread_launcher); DEFINE_MUTEX(eeh_event_mutex); /** - * eeh_event_handler - Dispatch EEH events. + * eeh_event_handler - dispatch EEH events. * @dummy - unused * * The detection of a frozen slot can occur inside an interrupt, @@ -56,10 +58,10 @@ DEFINE_MUTEX(eeh_event_mutex); static int eeh_event_handler(void * dummy) { unsigned long flags; - struct eeh_event *event; - struct eeh_dev *edev; + struct eeh_event *event; + struct pci_dn *pdn; - daemonize("eehd"); + daemonize ("eehd"); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&eeh_eventlist_lock, flags); @@ -77,37 +79,31 @@ static int eeh_event_handler(void * dummy) /* Serialize processing of EEH events */ mutex_lock(&eeh_event_mutex); - edev = event->edev; - eeh_mark_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); + eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", - eeh_pci_name(edev->pdev)); - - edev = handle_eeh_events(event); + eeh_pci_name(event->dev)); - eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); - pci_dev_put(edev->pdev); + pdn = handle_eeh_events(event); + eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); + pci_dev_put(event->dev); kfree(event); mutex_unlock(&eeh_event_mutex); /* If there are no new errors after an hour, clear the counter. */ - if (edev && edev->freeze_count>0) { - msleep_interruptible(3600*1000); - if (edev->freeze_count>0) - edev->freeze_count--; - + if (pdn && pdn->eeh_freeze_count>0) { + msleep_interruptible (3600*1000); + if (pdn->eeh_freeze_count>0) + pdn->eeh_freeze_count--; } return 0; } /** - * eeh_thread_launcher - Start kernel thread to handle EEH events + * eeh_thread_launcher * @dummy - unused - * - * This routine is called to start the kernel thread for processing - * EEH event. */ static void eeh_thread_launcher(struct work_struct *dummy) { @@ -116,18 +112,18 @@ static void eeh_thread_launcher(struct work_struct *dummy) } /** - * eeh_send_failure_event - Generate a PCI error event - * @edev: EEH device + * eeh_send_failure_event - generate a PCI error event + * @dev pci device * * This routine can be called within an interrupt context; * the actual event will be delivered in a normal context * (from a workqueue). */ -int eeh_send_failure_event(struct eeh_dev *edev) +int eeh_send_failure_event (struct device_node *dn, + struct pci_dev *dev) { unsigned long flags; struct eeh_event *event; - struct device_node *dn = eeh_dev_to_of_node(edev); const char *location; if (!mem_init_done) { @@ -139,14 +135,15 @@ int eeh_send_failure_event(struct eeh_dev *edev) } event = kmalloc(sizeof(*event), GFP_ATOMIC); if (event == NULL) { - printk(KERN_ERR "EEH: out of memory, event not handled\n"); + printk (KERN_ERR "EEH: out of memory, event not handled\n"); return 1; } - if (edev->pdev) - pci_dev_get(edev->pdev); + if (dev) + pci_dev_get(dev); - event->edev = edev; + event->dn = dn; + event->dev = dev; /* We may or may not be called in an interrupt context */ spin_lock_irqsave(&eeh_eventlist_lock, flags); @@ -157,3 +154,5 @@ int eeh_send_failure_event(struct eeh_dev *edev) return 0; } + +/********************** END OF FILE ******************************/ diff --git a/trunk/arch/powerpc/platforms/pseries/eeh_pseries.c b/trunk/arch/powerpc/platforms/pseries/eeh_pseries.c deleted file mode 100644 index 8752f79a6af8..000000000000 --- a/trunk/arch/powerpc/platforms/pseries/eeh_pseries.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - * The file intends to implement the platform dependent EEH operations on pseries. - * Actually, the pseries platform is built based on RTAS heavily. That means the - * pseries platform dependent EEH operations will be built on RTAS calls. The functions - * are devired from arch/powerpc/platforms/pseries/eeh.c and necessary cleanup has - * been done. - * - * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2011. - * Copyright IBM Corporation 2001, 2005, 2006 - * Copyright Dave Engebretsen & Todd Inglett 2001 - * Copyright Linas Vepstas 2005, 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* RTAS tokens */ -static int ibm_set_eeh_option; -static int ibm_set_slot_reset; -static int ibm_read_slot_reset_state; -static int ibm_read_slot_reset_state2; -static int ibm_slot_error_detail; -static int ibm_get_config_addr_info; -static int ibm_get_config_addr_info2; -static int ibm_configure_bridge; -static int ibm_configure_pe; - -/* - * Buffer for reporting slot-error-detail rtas calls. Its here - * in BSS, and not dynamically alloced, so that it ends up in - * RMO where RTAS can access it. - */ -static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; -static DEFINE_SPINLOCK(slot_errbuf_lock); -static int eeh_error_buf_size; - -/** - * pseries_eeh_init - EEH platform dependent initialization - * - * EEH platform dependent initialization on pseries. - */ -static int pseries_eeh_init(void) -{ - /* figure out EEH RTAS function call tokens */ - ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); - ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); - ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); - ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); - ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); - ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); - ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); - ibm_configure_pe = rtas_token("ibm,configure-pe"); - ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); - - /* necessary sanity check */ - if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) { - pr_warning("%s: RTAS service invalid\n", - __func__); - return -EINVAL; - } else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) { - pr_warning("%s: RTAS service invalid\n", - __func__); - return -EINVAL; - } else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE && - ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) { - pr_warning("%s: RTAS service and " - " invalid\n", - __func__); - return -EINVAL; - } else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) { - pr_warning("%s: RTAS service invalid\n", - __func__); - return -EINVAL; - } else if (ibm_get_config_addr_info2 == RTAS_UNKNOWN_SERVICE && - ibm_get_config_addr_info == RTAS_UNKNOWN_SERVICE) { - pr_warning("%s: RTAS service and " - " invalid\n", - __func__); - return -EINVAL; - } else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE && - ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) { - pr_warning("%s: RTAS service and " - " invalid\n", - __func__); - return -EINVAL; - } - - /* Initialize error log lock and size */ - spin_lock_init(&slot_errbuf_lock); - eeh_error_buf_size = rtas_token("rtas-error-log-max"); - if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { - pr_warning("%s: unknown EEH error log size\n", - __func__); - eeh_error_buf_size = 1024; - } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { - pr_warning("%s: EEH error log size %d exceeds the maximal %d\n", - __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX); - eeh_error_buf_size = RTAS_ERROR_LOG_MAX; - } - - return 0; -} - -/** - * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable - * @dn: device node - * @option: operation to be issued - * - * The function is used to control the EEH functionality globally. - * Currently, following options are support according to PAPR: - * Enable EEH, Disable EEH, Enable MMIO and Enable DMA - */ -static int pseries_eeh_set_option(struct device_node *dn, int option) -{ - int ret = 0; - struct eeh_dev *edev; - const u32 *reg; - int config_addr; - - edev = of_node_to_eeh_dev(dn); - - /* - * When we're enabling or disabling EEH functioality on - * the particular PE, the PE config address is possibly - * unavailable. Therefore, we have to figure it out from - * the FDT node. - */ - switch (option) { - case EEH_OPT_DISABLE: - case EEH_OPT_ENABLE: - reg = of_get_property(dn, "reg", NULL); - config_addr = reg[0]; - break; - - case EEH_OPT_THAW_MMIO: - case EEH_OPT_THAW_DMA: - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; - break; - - default: - pr_err("%s: Invalid option %d\n", - __func__, option); - return -EINVAL; - } - - ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), option); - - return ret; -} - -/** - * pseries_eeh_get_pe_addr - Retrieve PE address - * @dn: device node - * - * Retrieve the assocated PE address. Actually, there're 2 RTAS - * function calls dedicated for the purpose. We need implement - * it through the new function and then the old one. Besides, - * you should make sure the config address is figured out from - * FDT node before calling the function. - * - * It's notable that zero'ed return value means invalid PE config - * address. - */ -static int pseries_eeh_get_pe_addr(struct device_node *dn) -{ - struct eeh_dev *edev; - int ret = 0; - int rets[3]; - - edev = of_node_to_eeh_dev(dn); - - if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { - /* - * First of all, we need to make sure there has one PE - * associated with the device. Otherwise, PE address is - * meaningless. - */ - ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, - edev->config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), 1); - if (ret || (rets[0] == 0)) - return 0; - - /* Retrieve the associated PE config address */ - ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, - edev->config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), 0); - if (ret) { - pr_warning("%s: Failed to get PE address for %s\n", - __func__, dn->full_name); - return 0; - } - - return rets[0]; - } - - if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets, - edev->config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), 0); - if (ret) { - pr_warning("%s: Failed to get PE address for %s\n", - __func__, dn->full_name); - return 0; - } - - return rets[0]; - } - - return ret; -} - -/** - * pseries_eeh_get_state - Retrieve PE state - * @dn: PE associated device node - * @state: return value - * - * Retrieve the state of the specified PE. On RTAS compliant - * pseries platform, there already has one dedicated RTAS function - * for the purpose. It's notable that the associated PE config address - * might be ready when calling the function. Therefore, endeavour to - * use the PE config address if possible. Further more, there're 2 - * RTAS calls for the purpose, we need to try the new one and back - * to the old one if the new one couldn't work properly. - */ -static int pseries_eeh_get_state(struct device_node *dn, int *state) -{ - struct eeh_dev *edev; - int config_addr; - int ret; - int rets[4]; - int result; - - /* Figure out PE config address if possible */ - edev = of_node_to_eeh_dev(dn); - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; - - if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid)); - } else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) { - /* Fake PE unavailable info */ - rets[2] = 0; - ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid)); - } else { - return EEH_STATE_NOT_SUPPORT; - } - - if (ret) - return ret; - - /* Parse the result out */ - result = 0; - if (rets[1]) { - switch(rets[0]) { - case 0: - result &= ~EEH_STATE_RESET_ACTIVE; - result |= EEH_STATE_MMIO_ACTIVE; - result |= EEH_STATE_DMA_ACTIVE; - break; - case 1: - result |= EEH_STATE_RESET_ACTIVE; - result |= EEH_STATE_MMIO_ACTIVE; - result |= EEH_STATE_DMA_ACTIVE; - break; - case 2: - result &= ~EEH_STATE_RESET_ACTIVE; - result &= ~EEH_STATE_MMIO_ACTIVE; - result &= ~EEH_STATE_DMA_ACTIVE; - break; - case 4: - result &= ~EEH_STATE_RESET_ACTIVE; - result &= ~EEH_STATE_MMIO_ACTIVE; - result &= ~EEH_STATE_DMA_ACTIVE; - result |= EEH_STATE_MMIO_ENABLED; - break; - case 5: - if (rets[2]) { - if (state) *state = rets[2]; - result = EEH_STATE_UNAVAILABLE; - } else { - result = EEH_STATE_NOT_SUPPORT; - } - default: - result = EEH_STATE_NOT_SUPPORT; - } - } else { - result = EEH_STATE_NOT_SUPPORT; - } - - return result; -} - -/** - * pseries_eeh_reset - Reset the specified PE - * @dn: PE associated device node - * @option: reset option - * - * Reset the specified PE - */ -static int pseries_eeh_reset(struct device_node *dn, int option) -{ - struct eeh_dev *edev; - int config_addr; - int ret; - - /* Figure out PE address */ - edev = of_node_to_eeh_dev(dn); - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; - - /* Reset PE through RTAS call */ - ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), option); - - /* If fundamental-reset not supported, try hot-reset */ - if (option == EEH_RESET_FUNDAMENTAL && - ret == -8) { - ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid), EEH_RESET_HOT); - } - - return ret; -} - -/** - * pseries_eeh_wait_state - Wait for PE state - * @dn: PE associated device node - * @max_wait: maximal period in microsecond - * - * Wait for the state of associated PE. It might take some time - * to retrieve the PE's state. - */ -static int pseries_eeh_wait_state(struct device_node *dn, int max_wait) -{ - int ret; - int mwait; - - /* - * According to PAPR, the state of PE might be temporarily - * unavailable. Under the circumstance, we have to wait - * for indicated time determined by firmware. The maximal - * wait time is 5 minutes, which is acquired from the original - * EEH implementation. Also, the original implementation - * also defined the minimal wait time as 1 second. - */ -#define EEH_STATE_MIN_WAIT_TIME (1000) -#define EEH_STATE_MAX_WAIT_TIME (300 * 1000) - - while (1) { - ret = pseries_eeh_get_state(dn, &mwait); - - /* - * If the PE's state is temporarily unavailable, - * we have to wait for the specified time. Otherwise, - * the PE's state will be returned immediately. - */ - if (ret != EEH_STATE_UNAVAILABLE) - return ret; - - if (max_wait <= 0) { - pr_warning("%s: Timeout when getting PE's state (%d)\n", - __func__, max_wait); - return EEH_STATE_NOT_SUPPORT; - } - - if (mwait <= 0) { - pr_warning("%s: Firmware returned bad wait value %d\n", - __func__, mwait); - mwait = EEH_STATE_MIN_WAIT_TIME; - } else if (mwait > EEH_STATE_MAX_WAIT_TIME) { - pr_warning("%s: Firmware returned too long wait value %d\n", - __func__, mwait); - mwait = EEH_STATE_MAX_WAIT_TIME; - } - - max_wait -= mwait; - msleep(mwait); - } - - return EEH_STATE_NOT_SUPPORT; -} - -/** - * pseries_eeh_get_log - Retrieve error log - * @dn: device node - * @severity: temporary or permanent error log - * @drv_log: driver log to be combined with retrieved error log - * @len: length of driver log - * - * Retrieve the temporary or permanent error from the PE. - * Actually, the error will be retrieved through the dedicated - * RTAS call. - */ -static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len) -{ - struct eeh_dev *edev; - int config_addr; - unsigned long flags; - int ret; - - edev = of_node_to_eeh_dev(dn); - spin_lock_irqsave(&slot_errbuf_lock, flags); - memset(slot_errbuf, 0, eeh_error_buf_size); - - /* Figure out the PE address */ - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; - - ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr, - BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), - virt_to_phys(drv_log), len, - virt_to_phys(slot_errbuf), eeh_error_buf_size, - severity); - if (!ret) - log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); - spin_unlock_irqrestore(&slot_errbuf_lock, flags); - - return ret; -} - -/** - * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE - * @dn: PE associated device node - * - * The function will be called to reconfigure the bridges included - * in the specified PE so that the mulfunctional PE would be recovered - * again. - */ -static int pseries_eeh_configure_bridge(struct device_node *dn) -{ - struct eeh_dev *edev; - int config_addr; - int ret; - - /* Figure out the PE address */ - edev = of_node_to_eeh_dev(dn); - config_addr = edev->config_addr; - if (edev->pe_config_addr) - config_addr = edev->pe_config_addr; - - /* Use new configure-pe function, if supported */ - if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call(ibm_configure_pe, 3, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid)); - } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { - ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, - config_addr, BUID_HI(edev->phb->buid), - BUID_LO(edev->phb->buid)); - } else { - return -EFAULT; - } - - if (ret) - pr_warning("%s: Unable to configure bridge %d for %s\n", - __func__, ret, dn->full_name); - - return ret; -} - -/** - * pseries_eeh_read_config - Read PCI config space - * @dn: device node - * @where: PCI address - * @size: size to read - * @val: return value - * - * Read config space from the speicifed device - */ -static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val) -{ - struct pci_dn *pdn; - - pdn = PCI_DN(dn); - - return rtas_read_config(pdn, where, size, val); -} - -/** - * pseries_eeh_write_config - Write PCI config space - * @dn: device node - * @where: PCI address - * @size: size to write - * @val: value to be written - * - * Write config space to the specified device - */ -static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val) -{ - struct pci_dn *pdn; - - pdn = PCI_DN(dn); - - return rtas_write_config(pdn, where, size, val); -} - -static struct eeh_ops pseries_eeh_ops = { - .name = "pseries", - .init = pseries_eeh_init, - .set_option = pseries_eeh_set_option, - .get_pe_addr = pseries_eeh_get_pe_addr, - .get_state = pseries_eeh_get_state, - .reset = pseries_eeh_reset, - .wait_state = pseries_eeh_wait_state, - .get_log = pseries_eeh_get_log, - .configure_bridge = pseries_eeh_configure_bridge, - .read_config = pseries_eeh_read_config, - .write_config = pseries_eeh_write_config -}; - -/** - * eeh_pseries_init - Register platform dependent EEH operations - * - * EEH initialization on pseries platform. This function should be - * called before any EEH related functions. - */ -int __init eeh_pseries_init(void) -{ - return eeh_ops_register(&pseries_eeh_ops); -} diff --git a/trunk/arch/powerpc/platforms/pseries/eeh_sysfs.c b/trunk/arch/powerpc/platforms/pseries/eeh_sysfs.c index 243b3510d70f..eb744ee234da 100644 --- a/trunk/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/trunk/arch/powerpc/platforms/pseries/eeh_sysfs.c @@ -28,7 +28,7 @@ #include /** - * EEH_SHOW_ATTR -- Create sysfs entry for eeh statistic + * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic * @_name: name of file in sysfs directory * @_memb: name of member in struct pci_dn to access * @_format: printf format for display @@ -41,21 +41,24 @@ static ssize_t eeh_show_##_name(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct pci_dev *pdev = to_pci_dev(dev); \ - struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev); \ + struct device_node *dn = pci_device_to_OF_node(pdev); \ + struct pci_dn *pdn; \ \ - if (!edev) \ - return 0; \ + if (!dn || PCI_DN(dn) == NULL) \ + return 0; \ \ - return sprintf(buf, _format "\n", edev->_memb); \ + pdn = PCI_DN(dn); \ + return sprintf(buf, _format "\n", pdn->_memb); \ } \ static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); -EEH_SHOW_ATTR(eeh_mode, mode, "0x%x"); -EEH_SHOW_ATTR(eeh_config_addr, config_addr, "0x%x"); -EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x"); -EEH_SHOW_ATTR(eeh_check_count, check_count, "%d" ); -EEH_SHOW_ATTR(eeh_freeze_count, freeze_count, "%d" ); -EEH_SHOW_ATTR(eeh_false_positives, false_positives, "%d" ); + +EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x"); +EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x"); +EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x"); +EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d"); +EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d"); +EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d"); void eeh_sysfs_add_device(struct pci_dev *pdev) { diff --git a/trunk/arch/powerpc/platforms/pseries/lpar.c b/trunk/arch/powerpc/platforms/pseries/lpar.c index 5f3ef876ded2..7bc73af6c7b9 100644 --- a/trunk/arch/powerpc/platforms/pseries/lpar.c +++ b/trunk/arch/powerpc/platforms/pseries/lpar.c @@ -41,7 +41,6 @@ #include #include #include -#include #include "plpar_wrappers.h" #include "pseries.h" diff --git a/trunk/arch/powerpc/platforms/pseries/msi.c b/trunk/arch/powerpc/platforms/pseries/msi.c index 109fdb75578d..38d24e7e7bb1 100644 --- a/trunk/arch/powerpc/platforms/pseries/msi.c +++ b/trunk/arch/powerpc/platforms/pseries/msi.c @@ -217,7 +217,7 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) if (!dn) return NULL; - dn = eeh_find_device_pe(dn); + dn = find_device_pe(dn); if (!dn) return NULL; diff --git a/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c b/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c index fbb21fc3080b..55d4ec1bd1ac 100644 --- a/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/trunk/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -147,9 +147,6 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) pci_devs_phb_init_dynamic(phb); - /* Create EEH devices for the PHB */ - eeh_dev_phb_init_dynamic(phb); - if (dn->child) eeh_add_device_tree_early(dn); diff --git a/trunk/arch/powerpc/platforms/pseries/phyp_dump.c b/trunk/arch/powerpc/platforms/pseries/phyp_dump.c new file mode 100644 index 000000000000..6e7742da0072 --- /dev/null +++ b/trunk/arch/powerpc/platforms/pseries/phyp_dump.c @@ -0,0 +1,513 @@ +/* + * Hypervisor-assisted dump + * + * Linas Vepstas, Manish Ahuja 2008 + * Copyright 2008 IBM Corp. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/* Variables, used to communicate data between early boot and late boot */ +static struct phyp_dump phyp_dump_vars; +struct phyp_dump *phyp_dump_info = &phyp_dump_vars; + +static int ibm_configure_kernel_dump; +/* ------------------------------------------------- */ +/* RTAS interfaces to declare the dump regions */ + +struct dump_section { + u32 dump_flags; + u16 source_type; + u16 error_flags; + u64 source_address; + u64 source_length; + u64 length_copied; + u64 destination_address; +}; + +struct phyp_dump_header { + u32 version; + u16 num_of_sections; + u16 status; + + u32 first_offset_section; + u32 dump_disk_section; + u64 block_num_dd; + u64 num_of_blocks_dd; + u32 offset_dd; + u32 maxtime_to_auto; + /* No dump disk path string used */ + + struct dump_section cpu_data; + struct dump_section hpte_data; + struct dump_section kernel_data; +}; + +/* The dump header *must be* in low memory, so .bss it */ +static struct phyp_dump_header phdr; + +#define NUM_DUMP_SECTIONS 3 +#define DUMP_HEADER_VERSION 0x1 +#define DUMP_REQUEST_FLAG 0x1 +#define DUMP_SOURCE_CPU 0x0001 +#define DUMP_SOURCE_HPTE 0x0002 +#define DUMP_SOURCE_RMO 0x0011 +#define DUMP_ERROR_FLAG 0x2000 +#define DUMP_TRIGGERED 0x4000 +#define DUMP_PERFORMED 0x8000 + + +/** + * init_dump_header() - initialize the header declaring a dump + * Returns: length of dump save area. + * + * When the hypervisor saves crashed state, it needs to put + * it somewhere. The dump header tells the hypervisor where + * the data can be saved. + */ +static unsigned long init_dump_header(struct phyp_dump_header *ph) +{ + unsigned long addr_offset = 0; + + /* Set up the dump header */ + ph->version = DUMP_HEADER_VERSION; + ph->num_of_sections = NUM_DUMP_SECTIONS; + ph->status = 0; + + ph->first_offset_section = + (u32)offsetof(struct phyp_dump_header, cpu_data); + ph->dump_disk_section = 0; + ph->block_num_dd = 0; + ph->num_of_blocks_dd = 0; + ph->offset_dd = 0; + + ph->maxtime_to_auto = 0; /* disabled */ + + /* The first two sections are mandatory */ + ph->cpu_data.dump_flags = DUMP_REQUEST_FLAG; + ph->cpu_data.source_type = DUMP_SOURCE_CPU; + ph->cpu_data.source_address = 0; + ph->cpu_data.source_length = phyp_dump_info->cpu_state_size; + ph->cpu_data.destination_address = addr_offset; + addr_offset += phyp_dump_info->cpu_state_size; + + ph->hpte_data.dump_flags = DUMP_REQUEST_FLAG; + ph->hpte_data.source_type = DUMP_SOURCE_HPTE; + ph->hpte_data.source_address = 0; + ph->hpte_data.source_length = phyp_dump_info->hpte_region_size; + ph->hpte_data.destination_address = addr_offset; + addr_offset += phyp_dump_info->hpte_region_size; + + /* This section describes the low kernel region */ + ph->kernel_data.dump_flags = DUMP_REQUEST_FLAG; + ph->kernel_data.source_type = DUMP_SOURCE_RMO; + ph->kernel_data.source_address = PHYP_DUMP_RMR_START; + ph->kernel_data.source_length = PHYP_DUMP_RMR_END; + ph->kernel_data.destination_address = addr_offset; + addr_offset += ph->kernel_data.source_length; + + return addr_offset; +} + +static void print_dump_header(const struct phyp_dump_header *ph) +{ +#ifdef DEBUG + if (ph == NULL) + return; + + printk(KERN_INFO "dump header:\n"); + /* setup some ph->sections required */ + printk(KERN_INFO "version = %d\n", ph->version); + printk(KERN_INFO "Sections = %d\n", ph->num_of_sections); + printk(KERN_INFO "Status = 0x%x\n", ph->status); + + /* No ph->disk, so all should be set to 0 */ + printk(KERN_INFO "Offset to first section 0x%x\n", + ph->first_offset_section); + printk(KERN_INFO "dump disk sections should be zero\n"); + printk(KERN_INFO "dump disk section = %d\n", ph->dump_disk_section); + printk(KERN_INFO "block num = %lld\n", ph->block_num_dd); + printk(KERN_INFO "number of blocks = %lld\n", ph->num_of_blocks_dd); + printk(KERN_INFO "dump disk offset = %d\n", ph->offset_dd); + printk(KERN_INFO "Max auto time= %d\n", ph->maxtime_to_auto); + + /*set cpu state and hpte states as well scratch pad area */ + printk(KERN_INFO " CPU AREA\n"); + printk(KERN_INFO "cpu dump_flags =%d\n", ph->cpu_data.dump_flags); + printk(KERN_INFO "cpu source_type =%d\n", ph->cpu_data.source_type); + printk(KERN_INFO "cpu error_flags =%d\n", ph->cpu_data.error_flags); + printk(KERN_INFO "cpu source_address =%llx\n", + ph->cpu_data.source_address); + printk(KERN_INFO "cpu source_length =%llx\n", + ph->cpu_data.source_length); + printk(KERN_INFO "cpu length_copied =%llx\n", + ph->cpu_data.length_copied); + + printk(KERN_INFO " HPTE AREA\n"); + printk(KERN_INFO "HPTE dump_flags =%d\n", ph->hpte_data.dump_flags); + printk(KERN_INFO "HPTE source_type =%d\n", ph->hpte_data.source_type); + printk(KERN_INFO "HPTE error_flags =%d\n", ph->hpte_data.error_flags); + printk(KERN_INFO "HPTE source_address =%llx\n", + ph->hpte_data.source_address); + printk(KERN_INFO "HPTE source_length =%llx\n", + ph->hpte_data.source_length); + printk(KERN_INFO "HPTE length_copied =%llx\n", + ph->hpte_data.length_copied); + + printk(KERN_INFO " SRSD AREA\n"); + printk(KERN_INFO "SRSD dump_flags =%d\n", ph->kernel_data.dump_flags); + printk(KERN_INFO "SRSD source_type =%d\n", ph->kernel_data.source_type); + printk(KERN_INFO "SRSD error_flags =%d\n", ph->kernel_data.error_flags); + printk(KERN_INFO "SRSD source_address =%llx\n", + ph->kernel_data.source_address); + printk(KERN_INFO "SRSD source_length =%llx\n", + ph->kernel_data.source_length); + printk(KERN_INFO "SRSD length_copied =%llx\n", + ph->kernel_data.length_copied); +#endif +} + +static ssize_t show_phyp_dump_active(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + + /* create filesystem entry so kdump is phyp-dump aware */ + return sprintf(buf, "%lx\n", phyp_dump_info->phyp_dump_at_boot); +} + +static struct kobj_attribute pdl = __ATTR(phyp_dump_active, 0600, + show_phyp_dump_active, + NULL); + +static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) +{ + int rc; + + /* Add addr value if not initialized before */ + if (ph->cpu_data.destination_address == 0) { + ph->cpu_data.destination_address += addr; + ph->hpte_data.destination_address += addr; + ph->kernel_data.destination_address += addr; + } + + /* ToDo Invalidate kdump and free memory range. */ + + do { + rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, + 1, ph, sizeof(struct phyp_dump_header)); + } while (rtas_busy_delay(rc)); + + if (rc) { + printk(KERN_ERR "phyp-dump: unexpected error (%d) on " + "register\n", rc); + print_dump_header(ph); + return; + } + + rc = sysfs_create_file(kernel_kobj, &pdl.attr); + if (rc) + printk(KERN_ERR "phyp-dump: unable to create sysfs" + " file (%d)\n", rc); +} + +static +void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr) +{ + int rc; + + /* Add addr value if not initialized before */ + if (ph->cpu_data.destination_address == 0) { + ph->cpu_data.destination_address += addr; + ph->hpte_data.destination_address += addr; + ph->kernel_data.destination_address += addr; + } + + do { + rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, + 2, ph, sizeof(struct phyp_dump_header)); + } while (rtas_busy_delay(rc)); + + if (rc) { + printk(KERN_ERR "phyp-dump: unexpected error (%d) " + "on invalidate\n", rc); + print_dump_header(ph); + } +} + +/* ------------------------------------------------- */ +/** + * release_memory_range -- release memory previously memblock_reserved + * @start_pfn: starting physical frame number + * @nr_pages: number of pages to free. + * + * This routine will release memory that had been previously + * memblock_reserved in early boot. The released memory becomes + * available for genreal use. + */ +static void release_memory_range(unsigned long start_pfn, + unsigned long nr_pages) +{ + struct page *rpage; + unsigned long end_pfn; + long i; + + end_pfn = start_pfn + nr_pages; + + for (i = start_pfn; i <= end_pfn; i++) { + rpage = pfn_to_page(i); + if (PageReserved(rpage)) { + ClearPageReserved(rpage); + init_page_count(rpage); + __free_page(rpage); + totalram_pages++; + } + } +} + +/** + * track_freed_range -- Counts the range being freed. + * Once the counter goes to zero, it re-registers dump for + * future use. + */ +static void +track_freed_range(unsigned long addr, unsigned long length) +{ + static unsigned long scratch_area_size, reserved_area_size; + + if (addr < phyp_dump_info->init_reserve_start) + return; + + if ((addr >= phyp_dump_info->init_reserve_start) && + (addr <= phyp_dump_info->init_reserve_start + + phyp_dump_info->init_reserve_size)) + reserved_area_size += length; + + if ((addr >= phyp_dump_info->reserved_scratch_addr) && + (addr <= phyp_dump_info->reserved_scratch_addr + + phyp_dump_info->reserved_scratch_size)) + scratch_area_size += length; + + if ((reserved_area_size == phyp_dump_info->init_reserve_size) && + (scratch_area_size == phyp_dump_info->reserved_scratch_size)) { + + invalidate_last_dump(&phdr, + phyp_dump_info->reserved_scratch_addr); + register_dump_area(&phdr, + phyp_dump_info->reserved_scratch_addr); + } +} + +/* ------------------------------------------------- */ +/** + * sysfs_release_region -- sysfs interface to release memory range. + * + * Usage: + * "echo > /sys/kernel/release_region" + * + * Example: + * "echo 0x40000000 0x10000000 > /sys/kernel/release_region" + * + * will release 256MB starting at 1GB. + */ +static ssize_t store_release_region(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned long start_addr, length, end_addr; + unsigned long start_pfn, nr_pages; + ssize_t ret; + + ret = sscanf(buf, "%lx %lx", &start_addr, &length); + if (ret != 2) + return -EINVAL; + + track_freed_range(start_addr, length); + + /* Range-check - don't free any reserved memory that + * wasn't reserved for phyp-dump */ + if (start_addr < phyp_dump_info->init_reserve_start) + start_addr = phyp_dump_info->init_reserve_start; + + end_addr = phyp_dump_info->init_reserve_start + + phyp_dump_info->init_reserve_size; + if (start_addr+length > end_addr) + length = end_addr - start_addr; + + /* Release the region of memory assed in by user */ + start_pfn = PFN_DOWN(start_addr); + nr_pages = PFN_DOWN(length); + release_memory_range(start_pfn, nr_pages); + + return count; +} + +static ssize_t show_release_region(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + u64 second_addr_range; + + /* total reserved size - start of scratch area */ + second_addr_range = phyp_dump_info->init_reserve_size - + phyp_dump_info->reserved_scratch_size; + return sprintf(buf, "CPU:0x%llx-0x%llx: HPTE:0x%llx-0x%llx:" + " DUMP:0x%llx-0x%llx, 0x%lx-0x%llx:\n", + phdr.cpu_data.destination_address, + phdr.cpu_data.length_copied, + phdr.hpte_data.destination_address, + phdr.hpte_data.length_copied, + phdr.kernel_data.destination_address, + phdr.kernel_data.length_copied, + phyp_dump_info->init_reserve_start, + second_addr_range); +} + +static struct kobj_attribute rr = __ATTR(release_region, 0600, + show_release_region, + store_release_region); + +static int __init phyp_dump_setup(void) +{ + struct device_node *rtas; + const struct phyp_dump_header *dump_header = NULL; + unsigned long dump_area_start; + unsigned long dump_area_length; + int header_len = 0; + int rc; + + /* If no memory was reserved in early boot, there is nothing to do */ + if (phyp_dump_info->init_reserve_size == 0) + return 0; + + /* Return if phyp dump not supported */ + if (!phyp_dump_info->phyp_dump_configured) + return -ENOSYS; + + /* Is there dump data waiting for us? If there isn't, + * then register a new dump area, and release all of + * the rest of the reserved ram. + * + * The /rtas/ibm,kernel-dump rtas node is present only + * if there is dump data waiting for us. + */ + rtas = of_find_node_by_path("/rtas"); + if (rtas) { + dump_header = of_get_property(rtas, "ibm,kernel-dump", + &header_len); + of_node_put(rtas); + } + + ibm_configure_kernel_dump = rtas_token("ibm,configure-kernel-dump"); + + print_dump_header(dump_header); + dump_area_length = init_dump_header(&phdr); + /* align down */ + dump_area_start = phyp_dump_info->init_reserve_start & PAGE_MASK; + + if (dump_header == NULL) { + register_dump_area(&phdr, dump_area_start); + return 0; + } + + /* re-register the dump area, if old dump was invalid */ + if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) { + invalidate_last_dump(&phdr, dump_area_start); + register_dump_area(&phdr, dump_area_start); + return 0; + } + + if (dump_header) { + phyp_dump_info->reserved_scratch_addr = + dump_header->cpu_data.destination_address; + phyp_dump_info->reserved_scratch_size = + dump_header->cpu_data.source_length + + dump_header->hpte_data.source_length + + dump_header->kernel_data.source_length; + } + + /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ + rc = sysfs_create_file(kernel_kobj, &rr.attr); + if (rc) + printk(KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n", + rc); + + /* ToDo: re-register the dump area, for next time. */ + return 0; +} +machine_subsys_initcall(pseries, phyp_dump_setup); + +int __init early_init_dt_scan_phyp_dump(unsigned long node, + const char *uname, int depth, void *data) +{ + const unsigned int *sizes; + + phyp_dump_info->phyp_dump_configured = 0; + phyp_dump_info->phyp_dump_is_active = 0; + + if (depth != 1 || strcmp(uname, "rtas") != 0) + return 0; + + if (of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL)) + phyp_dump_info->phyp_dump_configured++; + + if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL)) + phyp_dump_info->phyp_dump_is_active++; + + sizes = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes", + NULL); + if (!sizes) + return 0; + + if (sizes[0] == 1) + phyp_dump_info->cpu_state_size = *((unsigned long *)&sizes[1]); + + if (sizes[3] == 2) + phyp_dump_info->hpte_region_size = + *((unsigned long *)&sizes[4]); + return 1; +} + +/* Look for phyp_dump= cmdline option */ +static int __init early_phyp_dump_enabled(char *p) +{ + phyp_dump_info->phyp_dump_at_boot = 1; + + if (!p) + return 0; + + if (strncmp(p, "1", 1) == 0) + phyp_dump_info->phyp_dump_at_boot = 1; + else if (strncmp(p, "0", 1) == 0) + phyp_dump_info->phyp_dump_at_boot = 0; + + return 0; +} +early_param("phyp_dump", early_phyp_dump_enabled); + +/* Look for phyp_dump_reserve_size= cmdline option */ +static int __init early_phyp_dump_reserve_size(char *p) +{ + if (p) + phyp_dump_info->reserve_bootvar = memparse(p, &p); + + return 0; +} +early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size); diff --git a/trunk/arch/powerpc/platforms/pseries/processor_idle.c b/trunk/arch/powerpc/platforms/pseries/processor_idle.c index a12e95af6933..085fd3f45ad2 100644 --- a/trunk/arch/powerpc/platforms/pseries/processor_idle.c +++ b/trunk/arch/powerpc/platforms/pseries/processor_idle.c @@ -96,20 +96,6 @@ static int snooze_loop(struct cpuidle_device *dev, return index; } -static void check_and_cede_processor(void) -{ - /* - * Interrupts are soft-disabled at this point, - * but not hard disabled. So an interrupt might have - * occurred before entering NAP, and would be potentially - * lost (edge events, decrementer events, etc...) unless - * we first hard disable then check. - */ - hard_irq_disable(); - if (get_paca()->irq_happened == 0) - cede_processor(); -} - static int dedicated_cede_loop(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -122,7 +108,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, ppc64_runlatch_off(); HMT_medium(); - check_and_cede_processor(); + cede_processor(); get_lppaca()->donate_dedicated_cpu = 0; dev->last_residency = @@ -146,7 +132,7 @@ static int shared_cede_loop(struct cpuidle_device *dev, * processor. When returning here, external interrupts * are enabled. */ - check_and_cede_processor(); + cede_processor(); dev->last_residency = (int)idle_loop_epilog(in_purr, kt_before); diff --git a/trunk/arch/powerpc/platforms/pseries/setup.c b/trunk/arch/powerpc/platforms/pseries/setup.c index 8f137af616af..f79f1278dfca 100644 --- a/trunk/arch/powerpc/platforms/pseries/setup.c +++ b/trunk/arch/powerpc/platforms/pseries/setup.c @@ -190,8 +190,9 @@ static void __init pseries_mpic_init_IRQ(void) BUG_ON(openpic_addr == 0); /* Setup the openpic driver */ - mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, - MPIC_NO_RESET, 16, 0, " MPIC "); + mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, 0, + 16, 250, /* isu size, irq count */ + " MPIC "); BUG_ON(mpic == NULL); /* Add ISUs */ @@ -260,12 +261,8 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act switch (action) { case PSERIES_RECONFIG_ADD: pci = np->parent->data; - if (pci) { + if (pci) update_dn_pci_info(np, pci->phb); - - /* Create EEH device for the OF node */ - eeh_dev_init(np, pci->phb); - } break; default: err = NOTIFY_DONE; @@ -385,7 +382,6 @@ static void __init pSeries_setup_arch(void) /* Find and initialize PCI host bridges */ init_pci_config_tokens(); - eeh_pseries_init(); find_and_init_phbs(); pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); eeh_init(); diff --git a/trunk/arch/powerpc/sysdev/Kconfig b/trunk/arch/powerpc/sysdev/Kconfig index a84fecf63c4d..7b4df37ac381 100644 --- a/trunk/arch/powerpc/sysdev/Kconfig +++ b/trunk/arch/powerpc/sysdev/Kconfig @@ -29,7 +29,3 @@ config SCOM_DEBUGFS bool "Expose SCOM controllers via debugfs" depends on PPC_SCOM default n - -config GE_FPGA - bool - default n diff --git a/trunk/arch/powerpc/sysdev/Makefile b/trunk/arch/powerpc/sysdev/Makefile index 1bd7ecb24620..5e37b4717864 100644 --- a/trunk/arch/powerpc/sysdev/Makefile +++ b/trunk/arch/powerpc/sysdev/Makefile @@ -4,8 +4,6 @@ ccflags-$(CONFIG_PPC64) := -mno-minimal-toc mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) -mpic-msgr-obj-$(CONFIG_MPIC_MSGR) += mpic_msgr.o -obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y) obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o @@ -67,5 +65,3 @@ obj-$(CONFIG_PPC_SCOM) += scom.o subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror obj-$(CONFIG_PPC_XICS) += xics/ - -obj-$(CONFIG_GE_FPGA) += ge/ diff --git a/trunk/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/trunk/arch/powerpc/sysdev/fsl_85xx_cache_sram.c index 37a69097e022..116415899176 100644 --- a/trunk/arch/powerpc/sysdev/fsl_85xx_cache_sram.c +++ b/trunk/arch/powerpc/sysdev/fsl_85xx_cache_sram.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include diff --git a/trunk/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/trunk/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c index cedabd0f4bfe..5f88797dce73 100644 --- a/trunk/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c +++ b/trunk/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c @@ -21,7 +21,6 @@ */ #include -#include #include #include @@ -201,9 +200,6 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = { { .compatible = "fsl,p1022-l2-cache-controller", }, - { - .compatible = "fsl,mpc8548-l2-cache-controller", - }, {}, }; diff --git a/trunk/arch/powerpc/sysdev/fsl_msi.c b/trunk/arch/powerpc/sysdev/fsl_msi.c index 6e097de00e09..0c01debe963b 100644 --- a/trunk/arch/powerpc/sysdev/fsl_msi.c +++ b/trunk/arch/powerpc/sysdev/fsl_msi.c @@ -410,7 +410,6 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) msi->msi_regs = ioremap(res.start, resource_size(&res)); if (!msi->msi_regs) { - err = -ENOMEM; dev_err(&dev->dev, "could not map node %s\n", dev->dev.of_node->full_name); goto error_out; diff --git a/trunk/arch/powerpc/sysdev/fsl_rio.c b/trunk/arch/powerpc/sysdev/fsl_rio.c index 5b6f556094dd..a4c4f4a932d8 100644 --- a/trunk/arch/powerpc/sysdev/fsl_rio.c +++ b/trunk/arch/powerpc/sysdev/fsl_rio.c @@ -66,8 +66,8 @@ " li %0,%3\n" \ " b 2b\n" \ ".section __ex_table,\"a\"\n" \ - PPC_LONG_ALIGN "\n" \ - PPC_LONG "1b,3b\n" \ + " .align 2\n" \ + " .long 1b,3b\n" \ ".text" \ : "=r" (err), "=r" (x) \ : "b" (addr), "i" (-EFAULT), "0" (err)) diff --git a/trunk/arch/powerpc/sysdev/fsl_rmu.c b/trunk/arch/powerpc/sysdev/fsl_rmu.c index 14bd5221f28a..15485789e9db 100644 --- a/trunk/arch/powerpc/sysdev/fsl_rmu.c +++ b/trunk/arch/powerpc/sysdev/fsl_rmu.c @@ -100,8 +100,14 @@ #define DOORBELL_DSR_TE 0x00000080 #define DOORBELL_DSR_QFI 0x00000010 #define DOORBELL_DSR_DIQI 0x00000001 +#define DOORBELL_TID_OFFSET 0x02 +#define DOORBELL_SID_OFFSET 0x04 +#define DOORBELL_INFO_OFFSET 0x06 #define DOORBELL_MESSAGE_SIZE 0x08 +#define DBELL_SID(x) (*(u16 *)(x + DOORBELL_SID_OFFSET)) +#define DBELL_TID(x) (*(u16 *)(x + DOORBELL_TID_OFFSET)) +#define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) struct rio_msg_regs { u32 omr; @@ -187,13 +193,6 @@ struct fsl_rmu { int rxirq; }; -struct rio_dbell_msg { - u16 pad1; - u16 tid; - u16 sid; - u16 info; -}; - /** * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler * @irq: Linux interrupt number @@ -312,8 +311,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) /* XXX Need to check/dispatch until queue empty */ if (dsr & DOORBELL_DSR_DIQI) { - struct rio_dbell_msg *dmsg = - fsl_dbell->dbell_ring.virt + + u32 dmsg = + (u32) fsl_dbell->dbell_ring.virt + (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff); struct rio_dbell *dbell; int found = 0; @@ -321,25 +320,25 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) pr_debug ("RIO: processing doorbell," " sid %2.2x tid %2.2x info %4.4x\n", - dmsg->sid, dmsg->tid, dmsg->info); + DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); for (i = 0; i < MAX_PORT_NUM; i++) { if (fsl_dbell->mport[i]) { list_for_each_entry(dbell, &fsl_dbell->mport[i]->dbells, node) { if ((dbell->res->start - <= dmsg->info) + <= DBELL_INF(dmsg)) && (dbell->res->end - >= dmsg->info)) { + >= DBELL_INF(dmsg))) { found = 1; break; } } if (found && dbell->dinb) { dbell->dinb(fsl_dbell->mport[i], - dbell->dev_id, dmsg->sid, - dmsg->tid, - dmsg->info); + dbell->dev_id, DBELL_SID(dmsg), + DBELL_TID(dmsg), + DBELL_INF(dmsg)); break; } } @@ -349,8 +348,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) pr_debug ("RIO: spurious doorbell," " sid %2.2x tid %2.2x info %4.4x\n", - dmsg->sid, dmsg->tid, - dmsg->info); + DBELL_SID(dmsg), DBELL_TID(dmsg), + DBELL_INF(dmsg)); } setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI); out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI); @@ -658,7 +657,7 @@ fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, int ret = 0; pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \ - "%p len %8.8zx\n", rdev->destid, mbox, buffer, len); + "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len); if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { ret = -EINVAL; goto out; @@ -973,8 +972,7 @@ int fsl_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) void *fsl_get_inb_message(struct rio_mport *mport, int mbox) { struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); - u32 phys_buf; - void *virt_buf; + u32 phys_buf, virt_buf; void *buf = NULL; int buf_idx; @@ -984,7 +982,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox) if (phys_buf == in_be32(&rmu->msg_regs->ifqepar)) goto out2; - virt_buf = rmu->msg_rx_ring.virt + (phys_buf + virt_buf = (u32) rmu->msg_rx_ring.virt + (phys_buf - rmu->msg_rx_ring.phys); buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; buf = rmu->msg_rx_ring.virt_buffer[buf_idx]; @@ -996,7 +994,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox) } /* Copy max message size, caller is expected to allocate that big */ - memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE); + memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE); /* Clear the available buffer */ rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL; diff --git a/trunk/arch/powerpc/sysdev/ge/Makefile b/trunk/arch/powerpc/sysdev/ge/Makefile deleted file mode 100644 index 8731ffcb79b9..000000000000 --- a/trunk/arch/powerpc/sysdev/ge/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_GE_FPGA) += ge_pic.o diff --git a/trunk/arch/powerpc/sysdev/mpic.c b/trunk/arch/powerpc/sysdev/mpic.c index 9ac71ebd2c40..c83a512fa175 100644 --- a/trunk/arch/powerpc/sysdev/mpic.c +++ b/trunk/arch/powerpc/sysdev/mpic.c @@ -873,7 +873,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", mpic, d->irq, src, flow_type); - if (src >= mpic->num_sources) + if (src >= mpic->irq_count) return -EINVAL; if (flow_type == IRQ_TYPE_NONE) @@ -909,7 +909,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", mpic, virq, src, vector); - if (src >= mpic->num_sources) + if (src >= mpic->irq_count) return; vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); @@ -926,7 +926,7 @@ void mpic_set_destination(unsigned int virq, unsigned int cpuid) DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", mpic, virq, src, cpuid); - if (src >= mpic->num_sources) + if (src >= mpic->irq_count) return; mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); @@ -1006,7 +1006,7 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq, return 0; } - if (hw >= mpic->num_sources) + if (hw >= mpic->irq_count) return -EINVAL; mpic_msi_reserve_hwirq(mpic, hw); @@ -1149,7 +1149,6 @@ struct mpic * __init mpic_alloc(struct device_node *node, u32 greg_feature; const char *vers; const u32 *psrc; - u32 last_irq; /* Default MPIC search parameters */ static const struct of_device_id __initconst mpic_device_id[] = { @@ -1183,16 +1182,6 @@ struct mpic * __init mpic_alloc(struct device_node *node, } } - /* Read extra device-tree properties into the flags variable */ - if (of_get_property(node, "big-endian", NULL)) - flags |= MPIC_BIG_ENDIAN; - if (of_get_property(node, "pic-no-reset", NULL)) - flags |= MPIC_NO_RESET; - if (of_get_property(node, "single-cpu-affinity", NULL)) - flags |= MPIC_SINGLE_DEST_CPU; - if (of_device_is_compatible(node, "fsl,mpic")) - flags |= MPIC_FSL; - mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); if (mpic == NULL) goto err_of_node_put; @@ -1200,16 +1189,15 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->name = name; mpic->node = node; mpic->paddr = phys_addr; - mpic->flags = flags; mpic->hc_irq = mpic_irq_chip; mpic->hc_irq.name = name; - if (!(mpic->flags & MPIC_SECONDARY)) + if (!(flags & MPIC_SECONDARY)) mpic->hc_irq.irq_set_affinity = mpic_set_affinity; #ifdef CONFIG_MPIC_U3_HT_IRQS mpic->hc_ht_irq = mpic_irq_ht_chip; mpic->hc_ht_irq.name = name; - if (!(mpic->flags & MPIC_SECONDARY)) + if (!(flags & MPIC_SECONDARY)) mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; #endif /* CONFIG_MPIC_U3_HT_IRQS */ @@ -1221,9 +1209,12 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->hc_tm = mpic_tm_chip; mpic->hc_tm.name = name; + mpic->flags = flags; + mpic->isu_size = isu_size; + mpic->irq_count = irq_count; mpic->num_sources = 0; /* so far */ - if (mpic->flags & MPIC_LARGE_VECTORS) + if (flags & MPIC_LARGE_VECTORS) intvec_top = 2047; else intvec_top = 255; @@ -1242,6 +1233,12 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->ipi_vecs[3] = intvec_top - 1; mpic->spurious_vec = intvec_top; + /* Check for "big-endian" in device-tree */ + if (of_get_property(mpic->node, "big-endian", NULL) != NULL) + mpic->flags |= MPIC_BIG_ENDIAN; + if (of_device_is_compatible(mpic->node, "fsl,mpic")) + mpic->flags |= MPIC_FSL; + /* Look for protected sources */ psrc = of_get_property(mpic->node, "protected-sources", &psize); if (psrc) { @@ -1257,11 +1254,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, } #ifdef CONFIG_MPIC_WEIRD - mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)]; + mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; #endif /* default register type */ - if (mpic->flags & MPIC_BIG_ENDIAN) + if (flags & MPIC_BIG_ENDIAN) mpic->reg_type = mpic_access_mmio_be; else mpic->reg_type = mpic_access_mmio_le; @@ -1271,10 +1268,10 @@ struct mpic * __init mpic_alloc(struct device_node *node, * only if the kernel includes DCR support. */ #ifdef CONFIG_PPC_DCR - if (mpic->flags & MPIC_USES_DCR) + if (flags & MPIC_USES_DCR) mpic->reg_type = mpic_access_dcr; #else - BUG_ON(mpic->flags & MPIC_USES_DCR); + BUG_ON(flags & MPIC_USES_DCR); #endif /* Map the global registers */ @@ -1286,7 +1283,10 @@ struct mpic * __init mpic_alloc(struct device_node *node, /* When using a device-node, reset requests are only honored if the MPIC * is allowed to reset. */ - if (!(mpic->flags & MPIC_NO_RESET)) { + if (of_get_property(mpic->node, "pic-no-reset", NULL)) + mpic->flags |= MPIC_NO_RESET; + + if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { printk(KERN_DEBUG "mpic: Resetting\n"); mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) @@ -1297,16 +1297,30 @@ struct mpic * __init mpic_alloc(struct device_node *node, } /* CoreInt */ - if (mpic->flags & MPIC_ENABLE_COREINT) + if (flags & MPIC_ENABLE_COREINT) mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | MPIC_GREG_GCONF_COREINT); - if (mpic->flags & MPIC_ENABLE_MCK) + if (flags & MPIC_ENABLE_MCK) mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | MPIC_GREG_GCONF_MCK); + /* + * Read feature register. For non-ISU MPICs, num sources as well. On + * ISU MPICs, sources are counted as ISUs are added + */ + greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); + if (isu_size == 0) { + if (flags & MPIC_BROKEN_FRR_NIRQS) + mpic->num_sources = mpic->irq_count; + else + mpic->num_sources = + ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) + >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; + } + /* * The MPIC driver will crash if there are more cores than we * can initialize, so we may as well catch that problem here. @@ -1322,41 +1336,17 @@ struct mpic * __init mpic_alloc(struct device_node *node, 0x1000); } - /* - * Read feature register. For non-ISU MPICs, num sources as well. On - * ISU MPICs, sources are counted as ISUs are added - */ - greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); - - /* - * By default, the last source number comes from the MPIC, but the - * device-tree and board support code can override it on buggy hw. - * If we get passed an isu_size (multi-isu MPIC) then we use that - * as a default instead of the value read from the HW. - */ - last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) - >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT; - if (isu_size) - last_irq = isu_size * MPIC_MAX_ISU - 1; - of_property_read_u32(mpic->node, "last-interrupt-source", &last_irq); - if (irq_count) - last_irq = irq_count - 1; - /* Initialize main ISU if none provided */ - if (!isu_size) { - isu_size = last_irq + 1; - mpic->num_sources = isu_size; + if (mpic->isu_size == 0) { + mpic->isu_size = mpic->num_sources; mpic_map(mpic, mpic->paddr, &mpic->isus[0], - MPIC_INFO(IRQ_BASE), - MPIC_INFO(IRQ_STRIDE) * isu_size); + MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); } - - mpic->isu_size = isu_size; mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); mpic->isu_mask = (1 << mpic->isu_shift) - 1; mpic->irqhost = irq_domain_add_linear(mpic->node, - last_irq + 1, + isu_size ? isu_size : mpic->num_sources, &mpic_host_ops, mpic); /* @@ -1390,7 +1380,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->next = mpics; mpics = mpic; - if (!(mpic->flags & MPIC_SECONDARY)) { + if (!(flags & MPIC_SECONDARY)) { mpic_primary = mpic; irq_set_default_host(mpic->irqhost); } @@ -1457,6 +1447,10 @@ void __init mpic_init(struct mpic *mpic) (mpic->ipi_vecs[0] + i)); } + /* Initialize interrupt sources */ + if (mpic->irq_count == 0) + mpic->irq_count = mpic->num_sources; + /* Do the HT PIC fixups on U3 broken mpic */ DBG("MPIC flags: %x\n", mpic->flags); if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) { diff --git a/trunk/arch/powerpc/sysdev/mpic_msgr.c b/trunk/arch/powerpc/sysdev/mpic_msgr.c deleted file mode 100644 index 6e7fa386e76a..000000000000 --- a/trunk/arch/powerpc/sysdev/mpic_msgr.c +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation. - * - * Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and - * Mingkai Hu from Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 of the - * License. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#define MPIC_MSGR_REGISTERS_PER_BLOCK 4 -#define MPIC_MSGR_STRIDE 0x10 -#define MPIC_MSGR_MER_OFFSET 0x100 -#define MSGR_INUSE 0 -#define MSGR_FREE 1 - -static struct mpic_msgr **mpic_msgrs; -static unsigned int mpic_msgr_count; - -static inline void _mpic_msgr_mer_write(struct mpic_msgr *msgr, u32 value) -{ - out_be32(msgr->mer, value); -} - -static inline u32 _mpic_msgr_mer_read(struct mpic_msgr *msgr) -{ - return in_be32(msgr->mer); -} - -static inline void _mpic_msgr_disable(struct mpic_msgr *msgr) -{ - u32 mer = _mpic_msgr_mer_read(msgr); - - _mpic_msgr_mer_write(msgr, mer & ~(1 << msgr->num)); -} - -struct mpic_msgr *mpic_msgr_get(unsigned int reg_num) -{ - unsigned long flags; - struct mpic_msgr *msgr; - - /* Assume busy until proven otherwise. */ - msgr = ERR_PTR(-EBUSY); - - if (reg_num >= mpic_msgr_count) - return ERR_PTR(-ENODEV); - - raw_spin_lock_irqsave(&msgr->lock, flags); - if (mpic_msgrs[reg_num]->in_use == MSGR_FREE) { - msgr = mpic_msgrs[reg_num]; - msgr->in_use = MSGR_INUSE; - } - raw_spin_unlock_irqrestore(&msgr->lock, flags); - - return msgr; -} -EXPORT_SYMBOL_GPL(mpic_msgr_get); - -void mpic_msgr_put(struct mpic_msgr *msgr) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&msgr->lock, flags); - msgr->in_use = MSGR_FREE; - _mpic_msgr_disable(msgr); - raw_spin_unlock_irqrestore(&msgr->lock, flags); -} -EXPORT_SYMBOL_GPL(mpic_msgr_put); - -void mpic_msgr_enable(struct mpic_msgr *msgr) -{ - unsigned long flags; - u32 mer; - - raw_spin_lock_irqsave(&msgr->lock, flags); - mer = _mpic_msgr_mer_read(msgr); - _mpic_msgr_mer_write(msgr, mer | (1 << msgr->num)); - raw_spin_unlock_irqrestore(&msgr->lock, flags); -} -EXPORT_SYMBOL_GPL(mpic_msgr_enable); - -void mpic_msgr_disable(struct mpic_msgr *msgr) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&msgr->lock, flags); - _mpic_msgr_disable(msgr); - raw_spin_unlock_irqrestore(&msgr->lock, flags); -} -EXPORT_SYMBOL_GPL(mpic_msgr_disable); - -/* The following three functions are used to compute the order and number of - * the message register blocks. They are clearly very inefficent. However, - * they are called *only* a few times during device initialization. - */ -static unsigned int mpic_msgr_number_of_blocks(void) -{ - unsigned int count; - struct device_node *aliases; - - count = 0; - aliases = of_find_node_by_name(NULL, "aliases"); - - if (aliases) { - char buf[32]; - - for (;;) { - snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count); - if (!of_find_property(aliases, buf, NULL)) - break; - - count += 1; - } - } - - return count; -} - -static unsigned int mpic_msgr_number_of_registers(void) -{ - return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK; -} - -static int mpic_msgr_block_number(struct device_node *node) -{ - struct device_node *aliases; - unsigned int index, number_of_blocks; - char buf[64]; - - number_of_blocks = mpic_msgr_number_of_blocks(); - aliases = of_find_node_by_name(NULL, "aliases"); - if (!aliases) - return -1; - - for (index = 0; index < number_of_blocks; ++index) { - struct property *prop; - - snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index); - prop = of_find_property(aliases, buf, NULL); - if (node == of_find_node_by_path(prop->value)) - break; - } - - return index == number_of_blocks ? -1 : index; -} - -/* The probe function for a single message register block. - */ -static __devinit int mpic_msgr_probe(struct platform_device *dev) -{ - void __iomem *msgr_block_addr; - int block_number; - struct resource rsrc; - unsigned int i; - unsigned int irq_index; - struct device_node *np = dev->dev.of_node; - unsigned int receive_mask; - const unsigned int *prop; - - if (!np) { - dev_err(&dev->dev, "Device OF-Node is NULL"); - return -EFAULT; - } - - /* Allocate the message register array upon the first device - * registered. - */ - if (!mpic_msgrs) { - mpic_msgr_count = mpic_msgr_number_of_registers(); - dev_info(&dev->dev, "Found %d message registers\n", - mpic_msgr_count); - - mpic_msgrs = kzalloc(sizeof(struct mpic_msgr) * mpic_msgr_count, - GFP_KERNEL); - if (!mpic_msgrs) { - dev_err(&dev->dev, - "No memory for message register blocks\n"); - return -ENOMEM; - } - } - dev_info(&dev->dev, "Of-device full name %s\n", np->full_name); - - /* IO map the message register block. */ - of_address_to_resource(np, 0, &rsrc); - msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start); - if (!msgr_block_addr) { - dev_err(&dev->dev, "Failed to iomap MPIC message registers"); - return -EFAULT; - } - - /* Ensure the block has a defined order. */ - block_number = mpic_msgr_block_number(np); - if (block_number < 0) { - dev_err(&dev->dev, - "Failed to find message register block alias\n"); - return -ENODEV; - } - dev_info(&dev->dev, "Setting up message register block %d\n", - block_number); - - /* Grab the receive mask which specifies what registers can receive - * interrupts. - */ - prop = of_get_property(np, "mpic-msgr-receive-mask", NULL); - receive_mask = (prop) ? *prop : 0xF; - - /* Build up the appropriate message register data structures. */ - for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) { - struct mpic_msgr *msgr; - unsigned int reg_number; - - msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL); - if (!msgr) { - dev_err(&dev->dev, "No memory for message register\n"); - return -ENOMEM; - } - - reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i; - msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE; - msgr->mer = msgr->base + MPIC_MSGR_MER_OFFSET; - msgr->in_use = MSGR_FREE; - msgr->num = i; - raw_spin_lock_init(&msgr->lock); - - if (receive_mask & (1 << i)) { - struct resource irq; - - if (of_irq_to_resource(np, irq_index, &irq) == NO_IRQ) { - dev_err(&dev->dev, - "Missing interrupt specifier"); - kfree(msgr); - return -EFAULT; - } - msgr->irq = irq.start; - irq_index += 1; - } else { - msgr->irq = NO_IRQ; - } - - mpic_msgrs[reg_number] = msgr; - mpic_msgr_disable(msgr); - dev_info(&dev->dev, "Register %d initialized: irq %d\n", - reg_number, msgr->irq); - - } - - return 0; -} - -static const struct of_device_id mpic_msgr_ids[] = { - { - .compatible = "fsl,mpic-v3.1-msgr", - .data = NULL, - }, - {} -}; - -static struct platform_driver mpic_msgr_driver = { - .driver = { - .name = "mpic-msgr", - .owner = THIS_MODULE, - .of_match_table = mpic_msgr_ids, - }, - .probe = mpic_msgr_probe, -}; - -static __init int mpic_msgr_init(void) -{ - return platform_driver_register(&mpic_msgr_driver); -} -subsys_initcall(mpic_msgr_init); diff --git a/trunk/arch/powerpc/sysdev/mpic_msi.c b/trunk/arch/powerpc/sysdev/mpic_msi.c index bbf342c88314..0622aa91b18a 100644 --- a/trunk/arch/powerpc/sysdev/mpic_msi.c +++ b/trunk/arch/powerpc/sysdev/mpic_msi.c @@ -54,7 +54,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) for (i = 100; i < 105; i++) msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); - for (i = 124; i < mpic->num_sources; i++) + for (i = 124; i < mpic->irq_count; i++) msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); @@ -83,7 +83,7 @@ int mpic_msi_init_allocator(struct mpic *mpic) { int rc; - rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->num_sources, + rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count, mpic->irqhost->of_node); if (rc) return rc; diff --git a/trunk/arch/powerpc/sysdev/ppc4xx_pci.c b/trunk/arch/powerpc/sysdev/ppc4xx_pci.c index 56e8b3c3c890..4f05f7542346 100644 --- a/trunk/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/trunk/arch/powerpc/sysdev/ppc4xx_pci.c @@ -1050,74 +1050,6 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata = .check_link = ppc4xx_pciex_check_link_sdr, }; -static int __init apm821xx_pciex_core_init(struct device_node *np) -{ - /* Return the number of pcie port */ - return 1; -} - -static int apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) -{ - u32 val; - - /* - * Do a software reset on PCIe ports. - * This code is to fix the issue that pci drivers doesn't re-assign - * bus number for PCIE devices after Uboot - * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000 - * PT quad port, SAS LSI 1064E) - */ - - mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0); - mdelay(10); - - if (port->endpoint) - val = PTYPE_LEGACY_ENDPOINT << 20; - else - val = PTYPE_ROOT_PORT << 20; - - val |= LNKW_X1 << 12; - - mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val); - mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000); - mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000); - - mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230); - mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130); - mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006); - - mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000); - mdelay(50); - mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000); - - mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, - mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | - (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN)); - - /* Poll for PHY reset */ - val = PESDR0_460EX_RSTSTA - port->sdr_base; - if (ppc4xx_pciex_wait_on_sdr(port, val, 0x1, 1, 100)) { - printk(KERN_WARNING "%s: PCIE: Can't reset PHY\n", __func__); - return -EBUSY; - } else { - mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, - (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) & - ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) | - PESDRx_RCSSET_RSTPYN); - - port->has_ibpre = 1; - return 0; - } -} - -static struct ppc4xx_pciex_hwops apm821xx_pcie_hwops __initdata = { - .want_sdr = true, - .core_init = apm821xx_pciex_core_init, - .port_init_hw = apm821xx_pciex_init_port_hw, - .setup_utl = ppc460ex_pciex_init_utl, - .check_link = ppc4xx_pciex_check_link_sdr, -}; - static int __init ppc460sx_pciex_core_init(struct device_node *np) { /* HSS drive amplitude */ @@ -1430,8 +1362,6 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops; if (of_device_is_compatible(np, "ibm,plb-pciex-460sx")) ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops; - if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx")) - ppc4xx_pciex_hwops = &apm821xx_pcie_hwops; #endif /* CONFIG_44x */ #ifdef CONFIG_40x if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) diff --git a/trunk/arch/powerpc/xmon/xmon.c b/trunk/arch/powerpc/xmon/xmon.c index 68a9cbbab450..cb95eea74d3d 100644 --- a/trunk/arch/powerpc/xmon/xmon.c +++ b/trunk/arch/powerpc/xmon/xmon.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -1436,8 +1437,7 @@ static void excprint(struct pt_regs *fp) printf(" current = 0x%lx\n", current); #ifdef CONFIG_PPC64 - printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n", - local_paca, local_paca->soft_enabled, local_paca->irq_happened); + printf(" paca = 0x%lx\n", get_paca()); #endif if (current) { printf(" pid = %ld, comm = %s\n", @@ -1634,6 +1634,25 @@ static void super_regs(void) mfspr(SPRN_DEC), mfspr(SPRN_SPRG2)); printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3)); printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR)); +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES)) { + struct paca_struct *ptrPaca; + struct lppaca *ptrLpPaca; + + /* Dump out relevant Paca data areas. */ + printf("Paca: \n"); + ptrPaca = get_paca(); + + printf(" Local Processor Control Area (LpPaca): \n"); + ptrLpPaca = ptrPaca->lppaca_ptr; + printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n", + ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1); + printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", + ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4); + printf(" Saved Gpr5=%.16lx \n", + ptrLpPaca->gpr5_dword.saved_gpr5); + } +#endif return; } @@ -2625,7 +2644,7 @@ static void dump_slb(void) static void dump_stab(void) { int i; - unsigned long *tmp = (unsigned long *)local_paca->stab_addr; + unsigned long *tmp = (unsigned long *)get_paca()->stab_addr; printf("Segment table contents of cpu %x\n", smp_processor_id()); @@ -2836,6 +2855,10 @@ static void dump_tlb_book3e(void) static void xmon_init(int enable) { +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return; +#endif if (enable) { __debugger = xmon; __debugger_ipi = xmon_ipi; @@ -2872,6 +2895,10 @@ static struct sysrq_key_op sysrq_xmon_op = { static int __init setup_xmon_sysrq(void) { +#ifdef CONFIG_PPC_ISERIES + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return 0; +#endif register_sysrq_key('x', &sysrq_xmon_op); return 0; } diff --git a/trunk/arch/s390/hypfs/inode.c b/trunk/arch/s390/hypfs/inode.c index 6a2cb560e968..8a2a887478cc 100644 --- a/trunk/arch/s390/hypfs/inode.c +++ b/trunk/arch/s390/hypfs/inode.c @@ -293,9 +293,11 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; root_inode->i_op = &simple_dir_inode_operations; root_inode->i_fop = &simple_dir_operations; - sb->s_root = root_dentry = d_make_root(root_inode); - if (!root_dentry) + sb->s_root = root_dentry = d_alloc_root(root_inode); + if (!root_dentry) { + iput(root_inode); return -ENOMEM; + } if (MACHINE_IS_VM) rc = hypfs_vm_create_files(sb, root_dentry); else diff --git a/trunk/arch/um/include/asm/mmu.h b/trunk/arch/um/include/asm/mmu.h index 53e8b498ebba..30509b9f37fd 100644 --- a/trunk/arch/um/include/asm/mmu.h +++ b/trunk/arch/um/include/asm/mmu.h @@ -12,7 +12,7 @@ typedef struct mm_context { struct mm_id id; struct uml_arch_mm_context arch; - struct page *stub_pages[2]; + struct page **stub_pages; } mm_context_t; extern void __switch_mm(struct mm_id * mm_idp); diff --git a/trunk/arch/um/include/asm/mmu_context.h b/trunk/arch/um/include/asm/mmu_context.h index aa4a743dc4ab..591b3d8d7614 100644 --- a/trunk/arch/um/include/asm/mmu_context.h +++ b/trunk/arch/um/include/asm/mmu_context.h @@ -9,7 +9,7 @@ #include #include -extern void uml_setup_stubs(struct mm_struct *mm); +extern void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm); extern void arch_exit_mmap(struct mm_struct *mm); #define deactivate_mm(tsk,mm) do { } while (0) @@ -23,9 +23,7 @@ static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) * when the new ->mm is used for the first time. */ __switch_mm(&new->context.id); - down_write(&new->mmap_sem); - uml_setup_stubs(new); - up_write(&new->mmap_sem); + arch_dup_mmap(old, new); } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, @@ -41,11 +39,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, } } -static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) -{ - uml_setup_stubs(mm); -} - static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk) { diff --git a/trunk/arch/um/kernel/skas/mmu.c b/trunk/arch/um/kernel/skas/mmu.c index 4947b319f53a..1aee587e9c5d 100644 --- a/trunk/arch/um/kernel/skas/mmu.c +++ b/trunk/arch/um/kernel/skas/mmu.c @@ -92,6 +92,8 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) goto out_free; } + to_mm->stub_pages = NULL; + return 0; out_free: @@ -101,7 +103,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) return ret; } -void uml_setup_stubs(struct mm_struct *mm) +void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) { struct page **pages; int err, ret; @@ -118,20 +120,29 @@ void uml_setup_stubs(struct mm_struct *mm) if (ret) goto out; - mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start); - mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack); + pages = kmalloc(2 * sizeof(struct page *), GFP_KERNEL); + if (pages == NULL) { + printk(KERN_ERR "arch_dup_mmap failed to allocate 2 page " + "pointers\n"); + goto out; + } + + pages[0] = virt_to_page(&__syscall_stub_start); + pages[1] = virt_to_page(mm->context.id.stack); + mm->context.stub_pages = pages; /* dup_mmap already holds mmap_sem */ err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START, VM_READ | VM_MAYREAD | VM_EXEC | - VM_MAYEXEC | VM_DONTCOPY, - mm->context.stub_pages); + VM_MAYEXEC | VM_DONTCOPY, pages); if (err) { printk(KERN_ERR "install_special_mapping returned %d\n", err); - goto out; + goto out_free; } return; +out_free: + kfree(pages); out: force_sigsegv(SIGSEGV, current); } @@ -140,6 +151,8 @@ void arch_exit_mmap(struct mm_struct *mm) { pte_t *pte; + if (mm->context.stub_pages != NULL) + kfree(mm->context.stub_pages); pte = virt_to_pte(mm, STUB_CODE); if (pte != NULL) pte_clear(mm, STUB_CODE, pte); diff --git a/trunk/arch/x86/crypto/Makefile b/trunk/arch/x86/crypto/Makefile index e191ac048b59..2b0b9631474b 100644 --- a/trunk/arch/x86/crypto/Makefile +++ b/trunk/arch/x86/crypto/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_CRYPTO_SALSA20_586) += salsa20-i586.o obj-$(CONFIG_CRYPTO_SERPENT_SSE2_586) += serpent-sse2-i586.o obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o -obj-$(CONFIG_CRYPTO_CAMELLIA_X86_64) += camellia-x86_64.o obj-$(CONFIG_CRYPTO_BLOWFISH_X86_64) += blowfish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64) += twofish-x86_64.o obj-$(CONFIG_CRYPTO_TWOFISH_X86_64_3WAY) += twofish-x86_64-3way.o @@ -26,7 +25,6 @@ salsa20-i586-y := salsa20-i586-asm_32.o salsa20_glue.o serpent-sse2-i586-y := serpent-sse2-i586-asm_32.o serpent_sse2_glue.o aes-x86_64-y := aes-x86_64-asm_64.o aes_glue.o -camellia-x86_64-y := camellia-x86_64-asm_64.o camellia_glue.o blowfish-x86_64-y := blowfish-x86_64-asm_64.o blowfish_glue.o twofish-x86_64-y := twofish-x86_64-asm_64.o twofish_glue.o twofish-x86_64-3way-y := twofish-x86_64-asm_64-3way.o twofish_glue_3way.o diff --git a/trunk/arch/x86/crypto/blowfish_glue.c b/trunk/arch/x86/crypto/blowfish_glue.c index 7967474de8f7..b05aa163d55a 100644 --- a/trunk/arch/x86/crypto/blowfish_glue.c +++ b/trunk/arch/x86/crypto/blowfish_glue.c @@ -25,7 +25,6 @@ * */ -#include #include #include #include @@ -77,6 +76,27 @@ static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src); } +static struct crypto_alg bf_alg = { + .cra_name = "blowfish", + .cra_driver_name = "blowfish-asm", + .cra_priority = 200, + .cra_flags = CRYPTO_ALG_TYPE_CIPHER, + .cra_blocksize = BF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct bf_ctx), + .cra_alignmask = 3, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(bf_alg.cra_list), + .cra_u = { + .cipher = { + .cia_min_keysize = BF_MIN_KEY_SIZE, + .cia_max_keysize = BF_MAX_KEY_SIZE, + .cia_setkey = blowfish_setkey, + .cia_encrypt = blowfish_encrypt, + .cia_decrypt = blowfish_decrypt, + } + } +}; + static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, void (*fn)(struct bf_ctx *, u8 *, const u8 *), void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *)) @@ -140,6 +160,28 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ecb_crypt(desc, &walk, blowfish_dec_blk, blowfish_dec_blk_4way); } +static struct crypto_alg blk_ecb_alg = { + .cra_name = "ecb(blowfish)", + .cra_driver_name = "ecb-blowfish-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = BF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct bf_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = BF_MIN_KEY_SIZE, + .max_keysize = BF_MAX_KEY_SIZE, + .setkey = blowfish_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}; + static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { @@ -265,6 +307,29 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } +static struct crypto_alg blk_cbc_alg = { + .cra_name = "cbc(blowfish)", + .cra_driver_name = "cbc-blowfish-asm", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = BF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct bf_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = BF_MIN_KEY_SIZE, + .max_keysize = BF_MAX_KEY_SIZE, + .ivsize = BF_BLOCK_SIZE, + .setkey = blowfish_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}; + static void ctr_crypt_final(struct bf_ctx *ctx, struct blkcipher_walk *walk) { u8 *ctrblk = walk->iv; @@ -358,67 +423,7 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg bf_algs[4] = { { - .cra_name = "blowfish", - .cra_driver_name = "blowfish-asm", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = BF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct bf_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_algs[0].cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = BF_MIN_KEY_SIZE, - .cia_max_keysize = BF_MAX_KEY_SIZE, - .cia_setkey = blowfish_setkey, - .cia_encrypt = blowfish_encrypt, - .cia_decrypt = blowfish_decrypt, - } - } -}, { - .cra_name = "ecb(blowfish)", - .cra_driver_name = "ecb-blowfish-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = BF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct bf_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_algs[1].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = BF_MIN_KEY_SIZE, - .max_keysize = BF_MAX_KEY_SIZE, - .setkey = blowfish_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}, { - .cra_name = "cbc(blowfish)", - .cra_driver_name = "cbc-blowfish-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = BF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct bf_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_algs[2].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = BF_MIN_KEY_SIZE, - .max_keysize = BF_MAX_KEY_SIZE, - .ivsize = BF_BLOCK_SIZE, - .setkey = blowfish_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}, { +static struct crypto_alg blk_ctr_alg = { .cra_name = "ctr(blowfish)", .cra_driver_name = "ctr-blowfish-asm", .cra_priority = 300, @@ -428,7 +433,7 @@ static struct crypto_alg bf_algs[4] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(bf_algs[3].cra_list), + .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = BF_MIN_KEY_SIZE, @@ -439,45 +444,43 @@ static struct crypto_alg bf_algs[4] = { { .decrypt = ctr_crypt, }, }, -} }; - -static bool is_blacklisted_cpu(void) -{ - if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) - return false; - - if (boot_cpu_data.x86 == 0x0f) { - /* - * On Pentium 4, blowfish-x86_64 is slower than generic C - * implementation because use of 64bit rotates (which are really - * slow on P4). Therefore blacklist P4s. - */ - return true; - } - - return false; -} - -static int force; -module_param(force, int, 0); -MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); +}; static int __init init(void) { - if (!force && is_blacklisted_cpu()) { - printk(KERN_INFO - "blowfish-x86_64: performance on this CPU " - "would be suboptimal: disabling " - "blowfish-x86_64.\n"); - return -ENODEV; - } + int err; - return crypto_register_algs(bf_algs, ARRAY_SIZE(bf_algs)); + err = crypto_register_alg(&bf_alg); + if (err) + goto bf_err; + err = crypto_register_alg(&blk_ecb_alg); + if (err) + goto ecb_err; + err = crypto_register_alg(&blk_cbc_alg); + if (err) + goto cbc_err; + err = crypto_register_alg(&blk_ctr_alg); + if (err) + goto ctr_err; + + return 0; + +ctr_err: + crypto_unregister_alg(&blk_cbc_alg); +cbc_err: + crypto_unregister_alg(&blk_ecb_alg); +ecb_err: + crypto_unregister_alg(&bf_alg); +bf_err: + return err; } static void __exit fini(void) { - crypto_unregister_algs(bf_algs, ARRAY_SIZE(bf_algs)); + crypto_unregister_alg(&blk_ctr_alg); + crypto_unregister_alg(&blk_cbc_alg); + crypto_unregister_alg(&blk_ecb_alg); + crypto_unregister_alg(&bf_alg); } module_init(init); diff --git a/trunk/arch/x86/crypto/camellia-x86_64-asm_64.S b/trunk/arch/x86/crypto/camellia-x86_64-asm_64.S deleted file mode 100644 index 0b3374335fdc..000000000000 --- a/trunk/arch/x86/crypto/camellia-x86_64-asm_64.S +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Camellia Cipher Algorithm (x86_64) - * - * Copyright (C) 2012 Jussi Kivilinna - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - */ - -.file "camellia-x86_64-asm_64.S" -.text - -.extern camellia_sp10011110; -.extern camellia_sp22000222; -.extern camellia_sp03303033; -.extern camellia_sp00444404; -.extern camellia_sp02220222; -.extern camellia_sp30333033; -.extern camellia_sp44044404; -.extern camellia_sp11101110; - -#define sp10011110 camellia_sp10011110 -#define sp22000222 camellia_sp22000222 -#define sp03303033 camellia_sp03303033 -#define sp00444404 camellia_sp00444404 -#define sp02220222 camellia_sp02220222 -#define sp30333033 camellia_sp30333033 -#define sp44044404 camellia_sp44044404 -#define sp11101110 camellia_sp11101110 - -#define CAMELLIA_TABLE_BYTE_LEN 272 - -/* struct camellia_ctx: */ -#define key_table 0 -#define key_length CAMELLIA_TABLE_BYTE_LEN - -/* register macros */ -#define CTX %rdi -#define RIO %rsi -#define RIOd %esi - -#define RAB0 %rax -#define RCD0 %rcx -#define RAB1 %rbx -#define RCD1 %rdx - -#define RAB0d %eax -#define RCD0d %ecx -#define RAB1d %ebx -#define RCD1d %edx - -#define RAB0bl %al -#define RCD0bl %cl -#define RAB1bl %bl -#define RCD1bl %dl - -#define RAB0bh %ah -#define RCD0bh %ch -#define RAB1bh %bh -#define RCD1bh %dh - -#define RT0 %rsi -#define RT1 %rbp -#define RT2 %r8 - -#define RT0d %esi -#define RT1d %ebp -#define RT2d %r8d - -#define RT2bl %r8b - -#define RXOR %r9 -#define RRBP %r10 -#define RDST %r11 - -#define RXORd %r9d -#define RXORbl %r9b - -#define xor2ror16(T0, T1, tmp1, tmp2, ab, dst) \ - movzbl ab ## bl, tmp2 ## d; \ - movzbl ab ## bh, tmp1 ## d; \ - rorq $16, ab; \ - xorq T0(, tmp2, 8), dst; \ - xorq T1(, tmp1, 8), dst; - -/********************************************************************** - 1-way camellia - **********************************************************************/ -#define roundsm(ab, subkey, cd) \ - movq (key_table + ((subkey) * 2) * 4)(CTX), RT2; \ - \ - xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \ - xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \ - xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \ - xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \ - \ - xorq RT2, cd ## 0; - -#define fls(l, r, kl, kr) \ - movl (key_table + ((kl) * 2) * 4)(CTX), RT0d; \ - andl l ## 0d, RT0d; \ - roll $1, RT0d; \ - shlq $32, RT0; \ - xorq RT0, l ## 0; \ - movq (key_table + ((kr) * 2) * 4)(CTX), RT1; \ - orq r ## 0, RT1; \ - shrq $32, RT1; \ - xorq RT1, r ## 0; \ - \ - movq (key_table + ((kl) * 2) * 4)(CTX), RT2; \ - orq l ## 0, RT2; \ - shrq $32, RT2; \ - xorq RT2, l ## 0; \ - movl (key_table + ((kr) * 2) * 4)(CTX), RT0d; \ - andl r ## 0d, RT0d; \ - roll $1, RT0d; \ - shlq $32, RT0; \ - xorq RT0, r ## 0; - -#define enc_rounds(i) \ - roundsm(RAB, i + 2, RCD); \ - roundsm(RCD, i + 3, RAB); \ - roundsm(RAB, i + 4, RCD); \ - roundsm(RCD, i + 5, RAB); \ - roundsm(RAB, i + 6, RCD); \ - roundsm(RCD, i + 7, RAB); - -#define enc_fls(i) \ - fls(RAB, RCD, i + 0, i + 1); - -#define enc_inpack() \ - movq (RIO), RAB0; \ - bswapq RAB0; \ - rolq $32, RAB0; \ - movq 4*2(RIO), RCD0; \ - bswapq RCD0; \ - rorq $32, RCD0; \ - xorq key_table(CTX), RAB0; - -#define enc_outunpack(op, max) \ - xorq key_table(CTX, max, 8), RCD0; \ - rorq $32, RCD0; \ - bswapq RCD0; \ - op ## q RCD0, (RIO); \ - rolq $32, RAB0; \ - bswapq RAB0; \ - op ## q RAB0, 4*2(RIO); - -#define dec_rounds(i) \ - roundsm(RAB, i + 7, RCD); \ - roundsm(RCD, i + 6, RAB); \ - roundsm(RAB, i + 5, RCD); \ - roundsm(RCD, i + 4, RAB); \ - roundsm(RAB, i + 3, RCD); \ - roundsm(RCD, i + 2, RAB); - -#define dec_fls(i) \ - fls(RAB, RCD, i + 1, i + 0); - -#define dec_inpack(max) \ - movq (RIO), RAB0; \ - bswapq RAB0; \ - rolq $32, RAB0; \ - movq 4*2(RIO), RCD0; \ - bswapq RCD0; \ - rorq $32, RCD0; \ - xorq key_table(CTX, max, 8), RAB0; - -#define dec_outunpack() \ - xorq key_table(CTX), RCD0; \ - rorq $32, RCD0; \ - bswapq RCD0; \ - movq RCD0, (RIO); \ - rolq $32, RAB0; \ - bswapq RAB0; \ - movq RAB0, 4*2(RIO); - -.global __camellia_enc_blk; -.type __camellia_enc_blk,@function; - -__camellia_enc_blk: - /* input: - * %rdi: ctx, CTX - * %rsi: dst - * %rdx: src - * %rcx: bool xor - */ - movq %rbp, RRBP; - - movq %rcx, RXOR; - movq %rsi, RDST; - movq %rdx, RIO; - - enc_inpack(); - - enc_rounds(0); - enc_fls(8); - enc_rounds(8); - enc_fls(16); - enc_rounds(16); - movl $24, RT1d; /* max */ - - cmpb $16, key_length(CTX); - je __enc_done; - - enc_fls(24); - enc_rounds(24); - movl $32, RT1d; /* max */ - -__enc_done: - testb RXORbl, RXORbl; - movq RDST, RIO; - - jnz __enc_xor; - - enc_outunpack(mov, RT1); - - movq RRBP, %rbp; - ret; - -__enc_xor: - enc_outunpack(xor, RT1); - - movq RRBP, %rbp; - ret; - -.global camellia_dec_blk; -.type camellia_dec_blk,@function; - -camellia_dec_blk: - /* input: - * %rdi: ctx, CTX - * %rsi: dst - * %rdx: src - */ - cmpl $16, key_length(CTX); - movl $32, RT2d; - movl $24, RXORd; - cmovel RXORd, RT2d; /* max */ - - movq %rbp, RRBP; - movq %rsi, RDST; - movq %rdx, RIO; - - dec_inpack(RT2); - - cmpb $24, RT2bl; - je __dec_rounds16; - - dec_rounds(24); - dec_fls(24); - -__dec_rounds16: - dec_rounds(16); - dec_fls(16); - dec_rounds(8); - dec_fls(8); - dec_rounds(0); - - movq RDST, RIO; - - dec_outunpack(); - - movq RRBP, %rbp; - ret; - -/********************************************************************** - 2-way camellia - **********************************************************************/ -#define roundsm2(ab, subkey, cd) \ - movq (key_table + ((subkey) * 2) * 4)(CTX), RT2; \ - xorq RT2, cd ## 1; \ - \ - xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 0, cd ## 0); \ - xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 0, RT2); \ - xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 0, cd ## 0); \ - xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 0, RT2); \ - \ - xor2ror16(sp00444404, sp03303033, RT0, RT1, ab ## 1, cd ## 1); \ - xorq RT2, cd ## 0; \ - xor2ror16(sp22000222, sp10011110, RT0, RT1, ab ## 1, cd ## 1); \ - xor2ror16(sp11101110, sp44044404, RT0, RT1, ab ## 1, cd ## 1); \ - xor2ror16(sp30333033, sp02220222, RT0, RT1, ab ## 1, cd ## 1); - -#define fls2(l, r, kl, kr) \ - movl (key_table + ((kl) * 2) * 4)(CTX), RT0d; \ - andl l ## 0d, RT0d; \ - roll $1, RT0d; \ - shlq $32, RT0; \ - xorq RT0, l ## 0; \ - movq (key_table + ((kr) * 2) * 4)(CTX), RT1; \ - orq r ## 0, RT1; \ - shrq $32, RT1; \ - xorq RT1, r ## 0; \ - \ - movl (key_table + ((kl) * 2) * 4)(CTX), RT2d; \ - andl l ## 1d, RT2d; \ - roll $1, RT2d; \ - shlq $32, RT2; \ - xorq RT2, l ## 1; \ - movq (key_table + ((kr) * 2) * 4)(CTX), RT0; \ - orq r ## 1, RT0; \ - shrq $32, RT0; \ - xorq RT0, r ## 1; \ - \ - movq (key_table + ((kl) * 2) * 4)(CTX), RT1; \ - orq l ## 0, RT1; \ - shrq $32, RT1; \ - xorq RT1, l ## 0; \ - movl (key_table + ((kr) * 2) * 4)(CTX), RT2d; \ - andl r ## 0d, RT2d; \ - roll $1, RT2d; \ - shlq $32, RT2; \ - xorq RT2, r ## 0; \ - \ - movq (key_table + ((kl) * 2) * 4)(CTX), RT0; \ - orq l ## 1, RT0; \ - shrq $32, RT0; \ - xorq RT0, l ## 1; \ - movl (key_table + ((kr) * 2) * 4)(CTX), RT1d; \ - andl r ## 1d, RT1d; \ - roll $1, RT1d; \ - shlq $32, RT1; \ - xorq RT1, r ## 1; - -#define enc_rounds2(i) \ - roundsm2(RAB, i + 2, RCD); \ - roundsm2(RCD, i + 3, RAB); \ - roundsm2(RAB, i + 4, RCD); \ - roundsm2(RCD, i + 5, RAB); \ - roundsm2(RAB, i + 6, RCD); \ - roundsm2(RCD, i + 7, RAB); - -#define enc_fls2(i) \ - fls2(RAB, RCD, i + 0, i + 1); - -#define enc_inpack2() \ - movq (RIO), RAB0; \ - bswapq RAB0; \ - rorq $32, RAB0; \ - movq 4*2(RIO), RCD0; \ - bswapq RCD0; \ - rolq $32, RCD0; \ - xorq key_table(CTX), RAB0; \ - \ - movq 8*2(RIO), RAB1; \ - bswapq RAB1; \ - rorq $32, RAB1; \ - movq 12*2(RIO), RCD1; \ - bswapq RCD1; \ - rolq $32, RCD1; \ - xorq key_table(CTX), RAB1; - -#define enc_outunpack2(op, max) \ - xorq key_table(CTX, max, 8), RCD0; \ - rolq $32, RCD0; \ - bswapq RCD0; \ - op ## q RCD0, (RIO); \ - rorq $32, RAB0; \ - bswapq RAB0; \ - op ## q RAB0, 4*2(RIO); \ - \ - xorq key_table(CTX, max, 8), RCD1; \ - rolq $32, RCD1; \ - bswapq RCD1; \ - op ## q RCD1, 8*2(RIO); \ - rorq $32, RAB1; \ - bswapq RAB1; \ - op ## q RAB1, 12*2(RIO); - -#define dec_rounds2(i) \ - roundsm2(RAB, i + 7, RCD); \ - roundsm2(RCD, i + 6, RAB); \ - roundsm2(RAB, i + 5, RCD); \ - roundsm2(RCD, i + 4, RAB); \ - roundsm2(RAB, i + 3, RCD); \ - roundsm2(RCD, i + 2, RAB); - -#define dec_fls2(i) \ - fls2(RAB, RCD, i + 1, i + 0); - -#define dec_inpack2(max) \ - movq (RIO), RAB0; \ - bswapq RAB0; \ - rorq $32, RAB0; \ - movq 4*2(RIO), RCD0; \ - bswapq RCD0; \ - rolq $32, RCD0; \ - xorq key_table(CTX, max, 8), RAB0; \ - \ - movq 8*2(RIO), RAB1; \ - bswapq RAB1; \ - rorq $32, RAB1; \ - movq 12*2(RIO), RCD1; \ - bswapq RCD1; \ - rolq $32, RCD1; \ - xorq key_table(CTX, max, 8), RAB1; - -#define dec_outunpack2() \ - xorq key_table(CTX), RCD0; \ - rolq $32, RCD0; \ - bswapq RCD0; \ - movq RCD0, (RIO); \ - rorq $32, RAB0; \ - bswapq RAB0; \ - movq RAB0, 4*2(RIO); \ - \ - xorq key_table(CTX), RCD1; \ - rolq $32, RCD1; \ - bswapq RCD1; \ - movq RCD1, 8*2(RIO); \ - rorq $32, RAB1; \ - bswapq RAB1; \ - movq RAB1, 12*2(RIO); - -.global __camellia_enc_blk_2way; -.type __camellia_enc_blk_2way,@function; - -__camellia_enc_blk_2way: - /* input: - * %rdi: ctx, CTX - * %rsi: dst - * %rdx: src - * %rcx: bool xor - */ - pushq %rbx; - - movq %rbp, RRBP; - movq %rcx, RXOR; - movq %rsi, RDST; - movq %rdx, RIO; - - enc_inpack2(); - - enc_rounds2(0); - enc_fls2(8); - enc_rounds2(8); - enc_fls2(16); - enc_rounds2(16); - movl $24, RT2d; /* max */ - - cmpb $16, key_length(CTX); - je __enc2_done; - - enc_fls2(24); - enc_rounds2(24); - movl $32, RT2d; /* max */ - -__enc2_done: - test RXORbl, RXORbl; - movq RDST, RIO; - jnz __enc2_xor; - - enc_outunpack2(mov, RT2); - - movq RRBP, %rbp; - popq %rbx; - ret; - -__enc2_xor: - enc_outunpack2(xor, RT2); - - movq RRBP, %rbp; - popq %rbx; - ret; - -.global camellia_dec_blk_2way; -.type camellia_dec_blk_2way,@function; - -camellia_dec_blk_2way: - /* input: - * %rdi: ctx, CTX - * %rsi: dst - * %rdx: src - */ - cmpl $16, key_length(CTX); - movl $32, RT2d; - movl $24, RXORd; - cmovel RXORd, RT2d; /* max */ - - movq %rbx, RXOR; - movq %rbp, RRBP; - movq %rsi, RDST; - movq %rdx, RIO; - - dec_inpack2(RT2); - - cmpb $24, RT2bl; - je __dec2_rounds16; - - dec_rounds2(24); - dec_fls2(24); - -__dec2_rounds16: - dec_rounds2(16); - dec_fls2(16); - dec_rounds2(8); - dec_fls2(8); - dec_rounds2(0); - - movq RDST, RIO; - - dec_outunpack2(); - - movq RRBP, %rbp; - movq RXOR, %rbx; - ret; diff --git a/trunk/arch/x86/crypto/camellia_glue.c b/trunk/arch/x86/crypto/camellia_glue.c deleted file mode 100644 index 1ca36a93fd2f..000000000000 --- a/trunk/arch/x86/crypto/camellia_glue.c +++ /dev/null @@ -1,1952 +0,0 @@ -/* - * Glue Code for assembler optimized version of Camellia - * - * Copyright (c) 2012 Jussi Kivilinna - * - * Camellia parts based on code by: - * Copyright (C) 2006 NTT (Nippon Telegraph and Telephone Corporation) - * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: - * Copyright (c) 2006 Herbert Xu - * CTR part based on code (crypto/ctr.c) by: - * (C) Copyright IBM Corp. 2007 - Joy Latten - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CAMELLIA_MIN_KEY_SIZE 16 -#define CAMELLIA_MAX_KEY_SIZE 32 -#define CAMELLIA_BLOCK_SIZE 16 -#define CAMELLIA_TABLE_BYTE_LEN 272 - -struct camellia_ctx { - u64 key_table[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)]; - u32 key_length; -}; - -/* regular block cipher functions */ -asmlinkage void __camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst, - const u8 *src, bool xor); -asmlinkage void camellia_dec_blk(struct camellia_ctx *ctx, u8 *dst, - const u8 *src); - -/* 2-way parallel cipher functions */ -asmlinkage void __camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst, - const u8 *src, bool xor); -asmlinkage void camellia_dec_blk_2way(struct camellia_ctx *ctx, u8 *dst, - const u8 *src); - -static inline void camellia_enc_blk(struct camellia_ctx *ctx, u8 *dst, - const u8 *src) -{ - __camellia_enc_blk(ctx, dst, src, false); -} - -static inline void camellia_enc_blk_xor(struct camellia_ctx *ctx, u8 *dst, - const u8 *src) -{ - __camellia_enc_blk(ctx, dst, src, true); -} - -static inline void camellia_enc_blk_2way(struct camellia_ctx *ctx, u8 *dst, - const u8 *src) -{ - __camellia_enc_blk_2way(ctx, dst, src, false); -} - -static inline void camellia_enc_blk_xor_2way(struct camellia_ctx *ctx, u8 *dst, - const u8 *src) -{ - __camellia_enc_blk_2way(ctx, dst, src, true); -} - -static void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - camellia_enc_blk(crypto_tfm_ctx(tfm), dst, src); -} - -static void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - camellia_dec_blk(crypto_tfm_ctx(tfm), dst, src); -} - -/* camellia sboxes */ -const u64 camellia_sp10011110[256] = { - 0x7000007070707000, 0x8200008282828200, 0x2c00002c2c2c2c00, - 0xec0000ecececec00, 0xb30000b3b3b3b300, 0x2700002727272700, - 0xc00000c0c0c0c000, 0xe50000e5e5e5e500, 0xe40000e4e4e4e400, - 0x8500008585858500, 0x5700005757575700, 0x3500003535353500, - 0xea0000eaeaeaea00, 0x0c00000c0c0c0c00, 0xae0000aeaeaeae00, - 0x4100004141414100, 0x2300002323232300, 0xef0000efefefef00, - 0x6b00006b6b6b6b00, 0x9300009393939300, 0x4500004545454500, - 0x1900001919191900, 0xa50000a5a5a5a500, 0x2100002121212100, - 0xed0000edededed00, 0x0e00000e0e0e0e00, 0x4f00004f4f4f4f00, - 0x4e00004e4e4e4e00, 0x1d00001d1d1d1d00, 0x6500006565656500, - 0x9200009292929200, 0xbd0000bdbdbdbd00, 0x8600008686868600, - 0xb80000b8b8b8b800, 0xaf0000afafafaf00, 0x8f00008f8f8f8f00, - 0x7c00007c7c7c7c00, 0xeb0000ebebebeb00, 0x1f00001f1f1f1f00, - 0xce0000cececece00, 0x3e00003e3e3e3e00, 0x3000003030303000, - 0xdc0000dcdcdcdc00, 0x5f00005f5f5f5f00, 0x5e00005e5e5e5e00, - 0xc50000c5c5c5c500, 0x0b00000b0b0b0b00, 0x1a00001a1a1a1a00, - 0xa60000a6a6a6a600, 0xe10000e1e1e1e100, 0x3900003939393900, - 0xca0000cacacaca00, 0xd50000d5d5d5d500, 0x4700004747474700, - 0x5d00005d5d5d5d00, 0x3d00003d3d3d3d00, 0xd90000d9d9d9d900, - 0x0100000101010100, 0x5a00005a5a5a5a00, 0xd60000d6d6d6d600, - 0x5100005151515100, 0x5600005656565600, 0x6c00006c6c6c6c00, - 0x4d00004d4d4d4d00, 0x8b00008b8b8b8b00, 0x0d00000d0d0d0d00, - 0x9a00009a9a9a9a00, 0x6600006666666600, 0xfb0000fbfbfbfb00, - 0xcc0000cccccccc00, 0xb00000b0b0b0b000, 0x2d00002d2d2d2d00, - 0x7400007474747400, 0x1200001212121200, 0x2b00002b2b2b2b00, - 0x2000002020202000, 0xf00000f0f0f0f000, 0xb10000b1b1b1b100, - 0x8400008484848400, 0x9900009999999900, 0xdf0000dfdfdfdf00, - 0x4c00004c4c4c4c00, 0xcb0000cbcbcbcb00, 0xc20000c2c2c2c200, - 0x3400003434343400, 0x7e00007e7e7e7e00, 0x7600007676767600, - 0x0500000505050500, 0x6d00006d6d6d6d00, 0xb70000b7b7b7b700, - 0xa90000a9a9a9a900, 0x3100003131313100, 0xd10000d1d1d1d100, - 0x1700001717171700, 0x0400000404040400, 0xd70000d7d7d7d700, - 0x1400001414141400, 0x5800005858585800, 0x3a00003a3a3a3a00, - 0x6100006161616100, 0xde0000dededede00, 0x1b00001b1b1b1b00, - 0x1100001111111100, 0x1c00001c1c1c1c00, 0x3200003232323200, - 0x0f00000f0f0f0f00, 0x9c00009c9c9c9c00, 0x1600001616161600, - 0x5300005353535300, 0x1800001818181800, 0xf20000f2f2f2f200, - 0x2200002222222200, 0xfe0000fefefefe00, 0x4400004444444400, - 0xcf0000cfcfcfcf00, 0xb20000b2b2b2b200, 0xc30000c3c3c3c300, - 0xb50000b5b5b5b500, 0x7a00007a7a7a7a00, 0x9100009191919100, - 0x2400002424242400, 0x0800000808080800, 0xe80000e8e8e8e800, - 0xa80000a8a8a8a800, 0x6000006060606000, 0xfc0000fcfcfcfc00, - 0x6900006969696900, 0x5000005050505000, 0xaa0000aaaaaaaa00, - 0xd00000d0d0d0d000, 0xa00000a0a0a0a000, 0x7d00007d7d7d7d00, - 0xa10000a1a1a1a100, 0x8900008989898900, 0x6200006262626200, - 0x9700009797979700, 0x5400005454545400, 0x5b00005b5b5b5b00, - 0x1e00001e1e1e1e00, 0x9500009595959500, 0xe00000e0e0e0e000, - 0xff0000ffffffff00, 0x6400006464646400, 0xd20000d2d2d2d200, - 0x1000001010101000, 0xc40000c4c4c4c400, 0x0000000000000000, - 0x4800004848484800, 0xa30000a3a3a3a300, 0xf70000f7f7f7f700, - 0x7500007575757500, 0xdb0000dbdbdbdb00, 0x8a00008a8a8a8a00, - 0x0300000303030300, 0xe60000e6e6e6e600, 0xda0000dadadada00, - 0x0900000909090900, 0x3f00003f3f3f3f00, 0xdd0000dddddddd00, - 0x9400009494949400, 0x8700008787878700, 0x5c00005c5c5c5c00, - 0x8300008383838300, 0x0200000202020200, 0xcd0000cdcdcdcd00, - 0x4a00004a4a4a4a00, 0x9000009090909000, 0x3300003333333300, - 0x7300007373737300, 0x6700006767676700, 0xf60000f6f6f6f600, - 0xf30000f3f3f3f300, 0x9d00009d9d9d9d00, 0x7f00007f7f7f7f00, - 0xbf0000bfbfbfbf00, 0xe20000e2e2e2e200, 0x5200005252525200, - 0x9b00009b9b9b9b00, 0xd80000d8d8d8d800, 0x2600002626262600, - 0xc80000c8c8c8c800, 0x3700003737373700, 0xc60000c6c6c6c600, - 0x3b00003b3b3b3b00, 0x8100008181818100, 0x9600009696969600, - 0x6f00006f6f6f6f00, 0x4b00004b4b4b4b00, 0x1300001313131300, - 0xbe0000bebebebe00, 0x6300006363636300, 0x2e00002e2e2e2e00, - 0xe90000e9e9e9e900, 0x7900007979797900, 0xa70000a7a7a7a700, - 0x8c00008c8c8c8c00, 0x9f00009f9f9f9f00, 0x6e00006e6e6e6e00, - 0xbc0000bcbcbcbc00, 0x8e00008e8e8e8e00, 0x2900002929292900, - 0xf50000f5f5f5f500, 0xf90000f9f9f9f900, 0xb60000b6b6b6b600, - 0x2f00002f2f2f2f00, 0xfd0000fdfdfdfd00, 0xb40000b4b4b4b400, - 0x5900005959595900, 0x7800007878787800, 0x9800009898989800, - 0x0600000606060600, 0x6a00006a6a6a6a00, 0xe70000e7e7e7e700, - 0x4600004646464600, 0x7100007171717100, 0xba0000babababa00, - 0xd40000d4d4d4d400, 0x2500002525252500, 0xab0000abababab00, - 0x4200004242424200, 0x8800008888888800, 0xa20000a2a2a2a200, - 0x8d00008d8d8d8d00, 0xfa0000fafafafa00, 0x7200007272727200, - 0x0700000707070700, 0xb90000b9b9b9b900, 0x5500005555555500, - 0xf80000f8f8f8f800, 0xee0000eeeeeeee00, 0xac0000acacacac00, - 0x0a00000a0a0a0a00, 0x3600003636363600, 0x4900004949494900, - 0x2a00002a2a2a2a00, 0x6800006868686800, 0x3c00003c3c3c3c00, - 0x3800003838383800, 0xf10000f1f1f1f100, 0xa40000a4a4a4a400, - 0x4000004040404000, 0x2800002828282800, 0xd30000d3d3d3d300, - 0x7b00007b7b7b7b00, 0xbb0000bbbbbbbb00, 0xc90000c9c9c9c900, - 0x4300004343434300, 0xc10000c1c1c1c100, 0x1500001515151500, - 0xe30000e3e3e3e300, 0xad0000adadadad00, 0xf40000f4f4f4f400, - 0x7700007777777700, 0xc70000c7c7c7c700, 0x8000008080808000, - 0x9e00009e9e9e9e00, -}; - -const u64 camellia_sp22000222[256] = { - 0xe0e0000000e0e0e0, 0x0505000000050505, 0x5858000000585858, - 0xd9d9000000d9d9d9, 0x6767000000676767, 0x4e4e0000004e4e4e, - 0x8181000000818181, 0xcbcb000000cbcbcb, 0xc9c9000000c9c9c9, - 0x0b0b0000000b0b0b, 0xaeae000000aeaeae, 0x6a6a0000006a6a6a, - 0xd5d5000000d5d5d5, 0x1818000000181818, 0x5d5d0000005d5d5d, - 0x8282000000828282, 0x4646000000464646, 0xdfdf000000dfdfdf, - 0xd6d6000000d6d6d6, 0x2727000000272727, 0x8a8a0000008a8a8a, - 0x3232000000323232, 0x4b4b0000004b4b4b, 0x4242000000424242, - 0xdbdb000000dbdbdb, 0x1c1c0000001c1c1c, 0x9e9e0000009e9e9e, - 0x9c9c0000009c9c9c, 0x3a3a0000003a3a3a, 0xcaca000000cacaca, - 0x2525000000252525, 0x7b7b0000007b7b7b, 0x0d0d0000000d0d0d, - 0x7171000000717171, 0x5f5f0000005f5f5f, 0x1f1f0000001f1f1f, - 0xf8f8000000f8f8f8, 0xd7d7000000d7d7d7, 0x3e3e0000003e3e3e, - 0x9d9d0000009d9d9d, 0x7c7c0000007c7c7c, 0x6060000000606060, - 0xb9b9000000b9b9b9, 0xbebe000000bebebe, 0xbcbc000000bcbcbc, - 0x8b8b0000008b8b8b, 0x1616000000161616, 0x3434000000343434, - 0x4d4d0000004d4d4d, 0xc3c3000000c3c3c3, 0x7272000000727272, - 0x9595000000959595, 0xabab000000ababab, 0x8e8e0000008e8e8e, - 0xbaba000000bababa, 0x7a7a0000007a7a7a, 0xb3b3000000b3b3b3, - 0x0202000000020202, 0xb4b4000000b4b4b4, 0xadad000000adadad, - 0xa2a2000000a2a2a2, 0xacac000000acacac, 0xd8d8000000d8d8d8, - 0x9a9a0000009a9a9a, 0x1717000000171717, 0x1a1a0000001a1a1a, - 0x3535000000353535, 0xcccc000000cccccc, 0xf7f7000000f7f7f7, - 0x9999000000999999, 0x6161000000616161, 0x5a5a0000005a5a5a, - 0xe8e8000000e8e8e8, 0x2424000000242424, 0x5656000000565656, - 0x4040000000404040, 0xe1e1000000e1e1e1, 0x6363000000636363, - 0x0909000000090909, 0x3333000000333333, 0xbfbf000000bfbfbf, - 0x9898000000989898, 0x9797000000979797, 0x8585000000858585, - 0x6868000000686868, 0xfcfc000000fcfcfc, 0xecec000000ececec, - 0x0a0a0000000a0a0a, 0xdada000000dadada, 0x6f6f0000006f6f6f, - 0x5353000000535353, 0x6262000000626262, 0xa3a3000000a3a3a3, - 0x2e2e0000002e2e2e, 0x0808000000080808, 0xafaf000000afafaf, - 0x2828000000282828, 0xb0b0000000b0b0b0, 0x7474000000747474, - 0xc2c2000000c2c2c2, 0xbdbd000000bdbdbd, 0x3636000000363636, - 0x2222000000222222, 0x3838000000383838, 0x6464000000646464, - 0x1e1e0000001e1e1e, 0x3939000000393939, 0x2c2c0000002c2c2c, - 0xa6a6000000a6a6a6, 0x3030000000303030, 0xe5e5000000e5e5e5, - 0x4444000000444444, 0xfdfd000000fdfdfd, 0x8888000000888888, - 0x9f9f0000009f9f9f, 0x6565000000656565, 0x8787000000878787, - 0x6b6b0000006b6b6b, 0xf4f4000000f4f4f4, 0x2323000000232323, - 0x4848000000484848, 0x1010000000101010, 0xd1d1000000d1d1d1, - 0x5151000000515151, 0xc0c0000000c0c0c0, 0xf9f9000000f9f9f9, - 0xd2d2000000d2d2d2, 0xa0a0000000a0a0a0, 0x5555000000555555, - 0xa1a1000000a1a1a1, 0x4141000000414141, 0xfafa000000fafafa, - 0x4343000000434343, 0x1313000000131313, 0xc4c4000000c4c4c4, - 0x2f2f0000002f2f2f, 0xa8a8000000a8a8a8, 0xb6b6000000b6b6b6, - 0x3c3c0000003c3c3c, 0x2b2b0000002b2b2b, 0xc1c1000000c1c1c1, - 0xffff000000ffffff, 0xc8c8000000c8c8c8, 0xa5a5000000a5a5a5, - 0x2020000000202020, 0x8989000000898989, 0x0000000000000000, - 0x9090000000909090, 0x4747000000474747, 0xefef000000efefef, - 0xeaea000000eaeaea, 0xb7b7000000b7b7b7, 0x1515000000151515, - 0x0606000000060606, 0xcdcd000000cdcdcd, 0xb5b5000000b5b5b5, - 0x1212000000121212, 0x7e7e0000007e7e7e, 0xbbbb000000bbbbbb, - 0x2929000000292929, 0x0f0f0000000f0f0f, 0xb8b8000000b8b8b8, - 0x0707000000070707, 0x0404000000040404, 0x9b9b0000009b9b9b, - 0x9494000000949494, 0x2121000000212121, 0x6666000000666666, - 0xe6e6000000e6e6e6, 0xcece000000cecece, 0xeded000000ededed, - 0xe7e7000000e7e7e7, 0x3b3b0000003b3b3b, 0xfefe000000fefefe, - 0x7f7f0000007f7f7f, 0xc5c5000000c5c5c5, 0xa4a4000000a4a4a4, - 0x3737000000373737, 0xb1b1000000b1b1b1, 0x4c4c0000004c4c4c, - 0x9191000000919191, 0x6e6e0000006e6e6e, 0x8d8d0000008d8d8d, - 0x7676000000767676, 0x0303000000030303, 0x2d2d0000002d2d2d, - 0xdede000000dedede, 0x9696000000969696, 0x2626000000262626, - 0x7d7d0000007d7d7d, 0xc6c6000000c6c6c6, 0x5c5c0000005c5c5c, - 0xd3d3000000d3d3d3, 0xf2f2000000f2f2f2, 0x4f4f0000004f4f4f, - 0x1919000000191919, 0x3f3f0000003f3f3f, 0xdcdc000000dcdcdc, - 0x7979000000797979, 0x1d1d0000001d1d1d, 0x5252000000525252, - 0xebeb000000ebebeb, 0xf3f3000000f3f3f3, 0x6d6d0000006d6d6d, - 0x5e5e0000005e5e5e, 0xfbfb000000fbfbfb, 0x6969000000696969, - 0xb2b2000000b2b2b2, 0xf0f0000000f0f0f0, 0x3131000000313131, - 0x0c0c0000000c0c0c, 0xd4d4000000d4d4d4, 0xcfcf000000cfcfcf, - 0x8c8c0000008c8c8c, 0xe2e2000000e2e2e2, 0x7575000000757575, - 0xa9a9000000a9a9a9, 0x4a4a0000004a4a4a, 0x5757000000575757, - 0x8484000000848484, 0x1111000000111111, 0x4545000000454545, - 0x1b1b0000001b1b1b, 0xf5f5000000f5f5f5, 0xe4e4000000e4e4e4, - 0x0e0e0000000e0e0e, 0x7373000000737373, 0xaaaa000000aaaaaa, - 0xf1f1000000f1f1f1, 0xdddd000000dddddd, 0x5959000000595959, - 0x1414000000141414, 0x6c6c0000006c6c6c, 0x9292000000929292, - 0x5454000000545454, 0xd0d0000000d0d0d0, 0x7878000000787878, - 0x7070000000707070, 0xe3e3000000e3e3e3, 0x4949000000494949, - 0x8080000000808080, 0x5050000000505050, 0xa7a7000000a7a7a7, - 0xf6f6000000f6f6f6, 0x7777000000777777, 0x9393000000939393, - 0x8686000000868686, 0x8383000000838383, 0x2a2a0000002a2a2a, - 0xc7c7000000c7c7c7, 0x5b5b0000005b5b5b, 0xe9e9000000e9e9e9, - 0xeeee000000eeeeee, 0x8f8f0000008f8f8f, 0x0101000000010101, - 0x3d3d0000003d3d3d, -}; - -const u64 camellia_sp03303033[256] = { - 0x0038380038003838, 0x0041410041004141, 0x0016160016001616, - 0x0076760076007676, 0x00d9d900d900d9d9, 0x0093930093009393, - 0x0060600060006060, 0x00f2f200f200f2f2, 0x0072720072007272, - 0x00c2c200c200c2c2, 0x00abab00ab00abab, 0x009a9a009a009a9a, - 0x0075750075007575, 0x0006060006000606, 0x0057570057005757, - 0x00a0a000a000a0a0, 0x0091910091009191, 0x00f7f700f700f7f7, - 0x00b5b500b500b5b5, 0x00c9c900c900c9c9, 0x00a2a200a200a2a2, - 0x008c8c008c008c8c, 0x00d2d200d200d2d2, 0x0090900090009090, - 0x00f6f600f600f6f6, 0x0007070007000707, 0x00a7a700a700a7a7, - 0x0027270027002727, 0x008e8e008e008e8e, 0x00b2b200b200b2b2, - 0x0049490049004949, 0x00dede00de00dede, 0x0043430043004343, - 0x005c5c005c005c5c, 0x00d7d700d700d7d7, 0x00c7c700c700c7c7, - 0x003e3e003e003e3e, 0x00f5f500f500f5f5, 0x008f8f008f008f8f, - 0x0067670067006767, 0x001f1f001f001f1f, 0x0018180018001818, - 0x006e6e006e006e6e, 0x00afaf00af00afaf, 0x002f2f002f002f2f, - 0x00e2e200e200e2e2, 0x0085850085008585, 0x000d0d000d000d0d, - 0x0053530053005353, 0x00f0f000f000f0f0, 0x009c9c009c009c9c, - 0x0065650065006565, 0x00eaea00ea00eaea, 0x00a3a300a300a3a3, - 0x00aeae00ae00aeae, 0x009e9e009e009e9e, 0x00ecec00ec00ecec, - 0x0080800080008080, 0x002d2d002d002d2d, 0x006b6b006b006b6b, - 0x00a8a800a800a8a8, 0x002b2b002b002b2b, 0x0036360036003636, - 0x00a6a600a600a6a6, 0x00c5c500c500c5c5, 0x0086860086008686, - 0x004d4d004d004d4d, 0x0033330033003333, 0x00fdfd00fd00fdfd, - 0x0066660066006666, 0x0058580058005858, 0x0096960096009696, - 0x003a3a003a003a3a, 0x0009090009000909, 0x0095950095009595, - 0x0010100010001010, 0x0078780078007878, 0x00d8d800d800d8d8, - 0x0042420042004242, 0x00cccc00cc00cccc, 0x00efef00ef00efef, - 0x0026260026002626, 0x00e5e500e500e5e5, 0x0061610061006161, - 0x001a1a001a001a1a, 0x003f3f003f003f3f, 0x003b3b003b003b3b, - 0x0082820082008282, 0x00b6b600b600b6b6, 0x00dbdb00db00dbdb, - 0x00d4d400d400d4d4, 0x0098980098009898, 0x00e8e800e800e8e8, - 0x008b8b008b008b8b, 0x0002020002000202, 0x00ebeb00eb00ebeb, - 0x000a0a000a000a0a, 0x002c2c002c002c2c, 0x001d1d001d001d1d, - 0x00b0b000b000b0b0, 0x006f6f006f006f6f, 0x008d8d008d008d8d, - 0x0088880088008888, 0x000e0e000e000e0e, 0x0019190019001919, - 0x0087870087008787, 0x004e4e004e004e4e, 0x000b0b000b000b0b, - 0x00a9a900a900a9a9, 0x000c0c000c000c0c, 0x0079790079007979, - 0x0011110011001111, 0x007f7f007f007f7f, 0x0022220022002222, - 0x00e7e700e700e7e7, 0x0059590059005959, 0x00e1e100e100e1e1, - 0x00dada00da00dada, 0x003d3d003d003d3d, 0x00c8c800c800c8c8, - 0x0012120012001212, 0x0004040004000404, 0x0074740074007474, - 0x0054540054005454, 0x0030300030003030, 0x007e7e007e007e7e, - 0x00b4b400b400b4b4, 0x0028280028002828, 0x0055550055005555, - 0x0068680068006868, 0x0050500050005050, 0x00bebe00be00bebe, - 0x00d0d000d000d0d0, 0x00c4c400c400c4c4, 0x0031310031003131, - 0x00cbcb00cb00cbcb, 0x002a2a002a002a2a, 0x00adad00ad00adad, - 0x000f0f000f000f0f, 0x00caca00ca00caca, 0x0070700070007070, - 0x00ffff00ff00ffff, 0x0032320032003232, 0x0069690069006969, - 0x0008080008000808, 0x0062620062006262, 0x0000000000000000, - 0x0024240024002424, 0x00d1d100d100d1d1, 0x00fbfb00fb00fbfb, - 0x00baba00ba00baba, 0x00eded00ed00eded, 0x0045450045004545, - 0x0081810081008181, 0x0073730073007373, 0x006d6d006d006d6d, - 0x0084840084008484, 0x009f9f009f009f9f, 0x00eeee00ee00eeee, - 0x004a4a004a004a4a, 0x00c3c300c300c3c3, 0x002e2e002e002e2e, - 0x00c1c100c100c1c1, 0x0001010001000101, 0x00e6e600e600e6e6, - 0x0025250025002525, 0x0048480048004848, 0x0099990099009999, - 0x00b9b900b900b9b9, 0x00b3b300b300b3b3, 0x007b7b007b007b7b, - 0x00f9f900f900f9f9, 0x00cece00ce00cece, 0x00bfbf00bf00bfbf, - 0x00dfdf00df00dfdf, 0x0071710071007171, 0x0029290029002929, - 0x00cdcd00cd00cdcd, 0x006c6c006c006c6c, 0x0013130013001313, - 0x0064640064006464, 0x009b9b009b009b9b, 0x0063630063006363, - 0x009d9d009d009d9d, 0x00c0c000c000c0c0, 0x004b4b004b004b4b, - 0x00b7b700b700b7b7, 0x00a5a500a500a5a5, 0x0089890089008989, - 0x005f5f005f005f5f, 0x00b1b100b100b1b1, 0x0017170017001717, - 0x00f4f400f400f4f4, 0x00bcbc00bc00bcbc, 0x00d3d300d300d3d3, - 0x0046460046004646, 0x00cfcf00cf00cfcf, 0x0037370037003737, - 0x005e5e005e005e5e, 0x0047470047004747, 0x0094940094009494, - 0x00fafa00fa00fafa, 0x00fcfc00fc00fcfc, 0x005b5b005b005b5b, - 0x0097970097009797, 0x00fefe00fe00fefe, 0x005a5a005a005a5a, - 0x00acac00ac00acac, 0x003c3c003c003c3c, 0x004c4c004c004c4c, - 0x0003030003000303, 0x0035350035003535, 0x00f3f300f300f3f3, - 0x0023230023002323, 0x00b8b800b800b8b8, 0x005d5d005d005d5d, - 0x006a6a006a006a6a, 0x0092920092009292, 0x00d5d500d500d5d5, - 0x0021210021002121, 0x0044440044004444, 0x0051510051005151, - 0x00c6c600c600c6c6, 0x007d7d007d007d7d, 0x0039390039003939, - 0x0083830083008383, 0x00dcdc00dc00dcdc, 0x00aaaa00aa00aaaa, - 0x007c7c007c007c7c, 0x0077770077007777, 0x0056560056005656, - 0x0005050005000505, 0x001b1b001b001b1b, 0x00a4a400a400a4a4, - 0x0015150015001515, 0x0034340034003434, 0x001e1e001e001e1e, - 0x001c1c001c001c1c, 0x00f8f800f800f8f8, 0x0052520052005252, - 0x0020200020002020, 0x0014140014001414, 0x00e9e900e900e9e9, - 0x00bdbd00bd00bdbd, 0x00dddd00dd00dddd, 0x00e4e400e400e4e4, - 0x00a1a100a100a1a1, 0x00e0e000e000e0e0, 0x008a8a008a008a8a, - 0x00f1f100f100f1f1, 0x00d6d600d600d6d6, 0x007a7a007a007a7a, - 0x00bbbb00bb00bbbb, 0x00e3e300e300e3e3, 0x0040400040004040, - 0x004f4f004f004f4f, -}; - -const u64 camellia_sp00444404[256] = { - 0x0000707070700070, 0x00002c2c2c2c002c, 0x0000b3b3b3b300b3, - 0x0000c0c0c0c000c0, 0x0000e4e4e4e400e4, 0x0000575757570057, - 0x0000eaeaeaea00ea, 0x0000aeaeaeae00ae, 0x0000232323230023, - 0x00006b6b6b6b006b, 0x0000454545450045, 0x0000a5a5a5a500a5, - 0x0000edededed00ed, 0x00004f4f4f4f004f, 0x00001d1d1d1d001d, - 0x0000929292920092, 0x0000868686860086, 0x0000afafafaf00af, - 0x00007c7c7c7c007c, 0x00001f1f1f1f001f, 0x00003e3e3e3e003e, - 0x0000dcdcdcdc00dc, 0x00005e5e5e5e005e, 0x00000b0b0b0b000b, - 0x0000a6a6a6a600a6, 0x0000393939390039, 0x0000d5d5d5d500d5, - 0x00005d5d5d5d005d, 0x0000d9d9d9d900d9, 0x00005a5a5a5a005a, - 0x0000515151510051, 0x00006c6c6c6c006c, 0x00008b8b8b8b008b, - 0x00009a9a9a9a009a, 0x0000fbfbfbfb00fb, 0x0000b0b0b0b000b0, - 0x0000747474740074, 0x00002b2b2b2b002b, 0x0000f0f0f0f000f0, - 0x0000848484840084, 0x0000dfdfdfdf00df, 0x0000cbcbcbcb00cb, - 0x0000343434340034, 0x0000767676760076, 0x00006d6d6d6d006d, - 0x0000a9a9a9a900a9, 0x0000d1d1d1d100d1, 0x0000040404040004, - 0x0000141414140014, 0x00003a3a3a3a003a, 0x0000dededede00de, - 0x0000111111110011, 0x0000323232320032, 0x00009c9c9c9c009c, - 0x0000535353530053, 0x0000f2f2f2f200f2, 0x0000fefefefe00fe, - 0x0000cfcfcfcf00cf, 0x0000c3c3c3c300c3, 0x00007a7a7a7a007a, - 0x0000242424240024, 0x0000e8e8e8e800e8, 0x0000606060600060, - 0x0000696969690069, 0x0000aaaaaaaa00aa, 0x0000a0a0a0a000a0, - 0x0000a1a1a1a100a1, 0x0000626262620062, 0x0000545454540054, - 0x00001e1e1e1e001e, 0x0000e0e0e0e000e0, 0x0000646464640064, - 0x0000101010100010, 0x0000000000000000, 0x0000a3a3a3a300a3, - 0x0000757575750075, 0x00008a8a8a8a008a, 0x0000e6e6e6e600e6, - 0x0000090909090009, 0x0000dddddddd00dd, 0x0000878787870087, - 0x0000838383830083, 0x0000cdcdcdcd00cd, 0x0000909090900090, - 0x0000737373730073, 0x0000f6f6f6f600f6, 0x00009d9d9d9d009d, - 0x0000bfbfbfbf00bf, 0x0000525252520052, 0x0000d8d8d8d800d8, - 0x0000c8c8c8c800c8, 0x0000c6c6c6c600c6, 0x0000818181810081, - 0x00006f6f6f6f006f, 0x0000131313130013, 0x0000636363630063, - 0x0000e9e9e9e900e9, 0x0000a7a7a7a700a7, 0x00009f9f9f9f009f, - 0x0000bcbcbcbc00bc, 0x0000292929290029, 0x0000f9f9f9f900f9, - 0x00002f2f2f2f002f, 0x0000b4b4b4b400b4, 0x0000787878780078, - 0x0000060606060006, 0x0000e7e7e7e700e7, 0x0000717171710071, - 0x0000d4d4d4d400d4, 0x0000abababab00ab, 0x0000888888880088, - 0x00008d8d8d8d008d, 0x0000727272720072, 0x0000b9b9b9b900b9, - 0x0000f8f8f8f800f8, 0x0000acacacac00ac, 0x0000363636360036, - 0x00002a2a2a2a002a, 0x00003c3c3c3c003c, 0x0000f1f1f1f100f1, - 0x0000404040400040, 0x0000d3d3d3d300d3, 0x0000bbbbbbbb00bb, - 0x0000434343430043, 0x0000151515150015, 0x0000adadadad00ad, - 0x0000777777770077, 0x0000808080800080, 0x0000828282820082, - 0x0000ecececec00ec, 0x0000272727270027, 0x0000e5e5e5e500e5, - 0x0000858585850085, 0x0000353535350035, 0x00000c0c0c0c000c, - 0x0000414141410041, 0x0000efefefef00ef, 0x0000939393930093, - 0x0000191919190019, 0x0000212121210021, 0x00000e0e0e0e000e, - 0x00004e4e4e4e004e, 0x0000656565650065, 0x0000bdbdbdbd00bd, - 0x0000b8b8b8b800b8, 0x00008f8f8f8f008f, 0x0000ebebebeb00eb, - 0x0000cececece00ce, 0x0000303030300030, 0x00005f5f5f5f005f, - 0x0000c5c5c5c500c5, 0x00001a1a1a1a001a, 0x0000e1e1e1e100e1, - 0x0000cacacaca00ca, 0x0000474747470047, 0x00003d3d3d3d003d, - 0x0000010101010001, 0x0000d6d6d6d600d6, 0x0000565656560056, - 0x00004d4d4d4d004d, 0x00000d0d0d0d000d, 0x0000666666660066, - 0x0000cccccccc00cc, 0x00002d2d2d2d002d, 0x0000121212120012, - 0x0000202020200020, 0x0000b1b1b1b100b1, 0x0000999999990099, - 0x00004c4c4c4c004c, 0x0000c2c2c2c200c2, 0x00007e7e7e7e007e, - 0x0000050505050005, 0x0000b7b7b7b700b7, 0x0000313131310031, - 0x0000171717170017, 0x0000d7d7d7d700d7, 0x0000585858580058, - 0x0000616161610061, 0x00001b1b1b1b001b, 0x00001c1c1c1c001c, - 0x00000f0f0f0f000f, 0x0000161616160016, 0x0000181818180018, - 0x0000222222220022, 0x0000444444440044, 0x0000b2b2b2b200b2, - 0x0000b5b5b5b500b5, 0x0000919191910091, 0x0000080808080008, - 0x0000a8a8a8a800a8, 0x0000fcfcfcfc00fc, 0x0000505050500050, - 0x0000d0d0d0d000d0, 0x00007d7d7d7d007d, 0x0000898989890089, - 0x0000979797970097, 0x00005b5b5b5b005b, 0x0000959595950095, - 0x0000ffffffff00ff, 0x0000d2d2d2d200d2, 0x0000c4c4c4c400c4, - 0x0000484848480048, 0x0000f7f7f7f700f7, 0x0000dbdbdbdb00db, - 0x0000030303030003, 0x0000dadadada00da, 0x00003f3f3f3f003f, - 0x0000949494940094, 0x00005c5c5c5c005c, 0x0000020202020002, - 0x00004a4a4a4a004a, 0x0000333333330033, 0x0000676767670067, - 0x0000f3f3f3f300f3, 0x00007f7f7f7f007f, 0x0000e2e2e2e200e2, - 0x00009b9b9b9b009b, 0x0000262626260026, 0x0000373737370037, - 0x00003b3b3b3b003b, 0x0000969696960096, 0x00004b4b4b4b004b, - 0x0000bebebebe00be, 0x00002e2e2e2e002e, 0x0000797979790079, - 0x00008c8c8c8c008c, 0x00006e6e6e6e006e, 0x00008e8e8e8e008e, - 0x0000f5f5f5f500f5, 0x0000b6b6b6b600b6, 0x0000fdfdfdfd00fd, - 0x0000595959590059, 0x0000989898980098, 0x00006a6a6a6a006a, - 0x0000464646460046, 0x0000babababa00ba, 0x0000252525250025, - 0x0000424242420042, 0x0000a2a2a2a200a2, 0x0000fafafafa00fa, - 0x0000070707070007, 0x0000555555550055, 0x0000eeeeeeee00ee, - 0x00000a0a0a0a000a, 0x0000494949490049, 0x0000686868680068, - 0x0000383838380038, 0x0000a4a4a4a400a4, 0x0000282828280028, - 0x00007b7b7b7b007b, 0x0000c9c9c9c900c9, 0x0000c1c1c1c100c1, - 0x0000e3e3e3e300e3, 0x0000f4f4f4f400f4, 0x0000c7c7c7c700c7, - 0x00009e9e9e9e009e, -}; - -const u64 camellia_sp02220222[256] = { - 0x00e0e0e000e0e0e0, 0x0005050500050505, 0x0058585800585858, - 0x00d9d9d900d9d9d9, 0x0067676700676767, 0x004e4e4e004e4e4e, - 0x0081818100818181, 0x00cbcbcb00cbcbcb, 0x00c9c9c900c9c9c9, - 0x000b0b0b000b0b0b, 0x00aeaeae00aeaeae, 0x006a6a6a006a6a6a, - 0x00d5d5d500d5d5d5, 0x0018181800181818, 0x005d5d5d005d5d5d, - 0x0082828200828282, 0x0046464600464646, 0x00dfdfdf00dfdfdf, - 0x00d6d6d600d6d6d6, 0x0027272700272727, 0x008a8a8a008a8a8a, - 0x0032323200323232, 0x004b4b4b004b4b4b, 0x0042424200424242, - 0x00dbdbdb00dbdbdb, 0x001c1c1c001c1c1c, 0x009e9e9e009e9e9e, - 0x009c9c9c009c9c9c, 0x003a3a3a003a3a3a, 0x00cacaca00cacaca, - 0x0025252500252525, 0x007b7b7b007b7b7b, 0x000d0d0d000d0d0d, - 0x0071717100717171, 0x005f5f5f005f5f5f, 0x001f1f1f001f1f1f, - 0x00f8f8f800f8f8f8, 0x00d7d7d700d7d7d7, 0x003e3e3e003e3e3e, - 0x009d9d9d009d9d9d, 0x007c7c7c007c7c7c, 0x0060606000606060, - 0x00b9b9b900b9b9b9, 0x00bebebe00bebebe, 0x00bcbcbc00bcbcbc, - 0x008b8b8b008b8b8b, 0x0016161600161616, 0x0034343400343434, - 0x004d4d4d004d4d4d, 0x00c3c3c300c3c3c3, 0x0072727200727272, - 0x0095959500959595, 0x00ababab00ababab, 0x008e8e8e008e8e8e, - 0x00bababa00bababa, 0x007a7a7a007a7a7a, 0x00b3b3b300b3b3b3, - 0x0002020200020202, 0x00b4b4b400b4b4b4, 0x00adadad00adadad, - 0x00a2a2a200a2a2a2, 0x00acacac00acacac, 0x00d8d8d800d8d8d8, - 0x009a9a9a009a9a9a, 0x0017171700171717, 0x001a1a1a001a1a1a, - 0x0035353500353535, 0x00cccccc00cccccc, 0x00f7f7f700f7f7f7, - 0x0099999900999999, 0x0061616100616161, 0x005a5a5a005a5a5a, - 0x00e8e8e800e8e8e8, 0x0024242400242424, 0x0056565600565656, - 0x0040404000404040, 0x00e1e1e100e1e1e1, 0x0063636300636363, - 0x0009090900090909, 0x0033333300333333, 0x00bfbfbf00bfbfbf, - 0x0098989800989898, 0x0097979700979797, 0x0085858500858585, - 0x0068686800686868, 0x00fcfcfc00fcfcfc, 0x00ececec00ececec, - 0x000a0a0a000a0a0a, 0x00dadada00dadada, 0x006f6f6f006f6f6f, - 0x0053535300535353, 0x0062626200626262, 0x00a3a3a300a3a3a3, - 0x002e2e2e002e2e2e, 0x0008080800080808, 0x00afafaf00afafaf, - 0x0028282800282828, 0x00b0b0b000b0b0b0, 0x0074747400747474, - 0x00c2c2c200c2c2c2, 0x00bdbdbd00bdbdbd, 0x0036363600363636, - 0x0022222200222222, 0x0038383800383838, 0x0064646400646464, - 0x001e1e1e001e1e1e, 0x0039393900393939, 0x002c2c2c002c2c2c, - 0x00a6a6a600a6a6a6, 0x0030303000303030, 0x00e5e5e500e5e5e5, - 0x0044444400444444, 0x00fdfdfd00fdfdfd, 0x0088888800888888, - 0x009f9f9f009f9f9f, 0x0065656500656565, 0x0087878700878787, - 0x006b6b6b006b6b6b, 0x00f4f4f400f4f4f4, 0x0023232300232323, - 0x0048484800484848, 0x0010101000101010, 0x00d1d1d100d1d1d1, - 0x0051515100515151, 0x00c0c0c000c0c0c0, 0x00f9f9f900f9f9f9, - 0x00d2d2d200d2d2d2, 0x00a0a0a000a0a0a0, 0x0055555500555555, - 0x00a1a1a100a1a1a1, 0x0041414100414141, 0x00fafafa00fafafa, - 0x0043434300434343, 0x0013131300131313, 0x00c4c4c400c4c4c4, - 0x002f2f2f002f2f2f, 0x00a8a8a800a8a8a8, 0x00b6b6b600b6b6b6, - 0x003c3c3c003c3c3c, 0x002b2b2b002b2b2b, 0x00c1c1c100c1c1c1, - 0x00ffffff00ffffff, 0x00c8c8c800c8c8c8, 0x00a5a5a500a5a5a5, - 0x0020202000202020, 0x0089898900898989, 0x0000000000000000, - 0x0090909000909090, 0x0047474700474747, 0x00efefef00efefef, - 0x00eaeaea00eaeaea, 0x00b7b7b700b7b7b7, 0x0015151500151515, - 0x0006060600060606, 0x00cdcdcd00cdcdcd, 0x00b5b5b500b5b5b5, - 0x0012121200121212, 0x007e7e7e007e7e7e, 0x00bbbbbb00bbbbbb, - 0x0029292900292929, 0x000f0f0f000f0f0f, 0x00b8b8b800b8b8b8, - 0x0007070700070707, 0x0004040400040404, 0x009b9b9b009b9b9b, - 0x0094949400949494, 0x0021212100212121, 0x0066666600666666, - 0x00e6e6e600e6e6e6, 0x00cecece00cecece, 0x00ededed00ededed, - 0x00e7e7e700e7e7e7, 0x003b3b3b003b3b3b, 0x00fefefe00fefefe, - 0x007f7f7f007f7f7f, 0x00c5c5c500c5c5c5, 0x00a4a4a400a4a4a4, - 0x0037373700373737, 0x00b1b1b100b1b1b1, 0x004c4c4c004c4c4c, - 0x0091919100919191, 0x006e6e6e006e6e6e, 0x008d8d8d008d8d8d, - 0x0076767600767676, 0x0003030300030303, 0x002d2d2d002d2d2d, - 0x00dedede00dedede, 0x0096969600969696, 0x0026262600262626, - 0x007d7d7d007d7d7d, 0x00c6c6c600c6c6c6, 0x005c5c5c005c5c5c, - 0x00d3d3d300d3d3d3, 0x00f2f2f200f2f2f2, 0x004f4f4f004f4f4f, - 0x0019191900191919, 0x003f3f3f003f3f3f, 0x00dcdcdc00dcdcdc, - 0x0079797900797979, 0x001d1d1d001d1d1d, 0x0052525200525252, - 0x00ebebeb00ebebeb, 0x00f3f3f300f3f3f3, 0x006d6d6d006d6d6d, - 0x005e5e5e005e5e5e, 0x00fbfbfb00fbfbfb, 0x0069696900696969, - 0x00b2b2b200b2b2b2, 0x00f0f0f000f0f0f0, 0x0031313100313131, - 0x000c0c0c000c0c0c, 0x00d4d4d400d4d4d4, 0x00cfcfcf00cfcfcf, - 0x008c8c8c008c8c8c, 0x00e2e2e200e2e2e2, 0x0075757500757575, - 0x00a9a9a900a9a9a9, 0x004a4a4a004a4a4a, 0x0057575700575757, - 0x0084848400848484, 0x0011111100111111, 0x0045454500454545, - 0x001b1b1b001b1b1b, 0x00f5f5f500f5f5f5, 0x00e4e4e400e4e4e4, - 0x000e0e0e000e0e0e, 0x0073737300737373, 0x00aaaaaa00aaaaaa, - 0x00f1f1f100f1f1f1, 0x00dddddd00dddddd, 0x0059595900595959, - 0x0014141400141414, 0x006c6c6c006c6c6c, 0x0092929200929292, - 0x0054545400545454, 0x00d0d0d000d0d0d0, 0x0078787800787878, - 0x0070707000707070, 0x00e3e3e300e3e3e3, 0x0049494900494949, - 0x0080808000808080, 0x0050505000505050, 0x00a7a7a700a7a7a7, - 0x00f6f6f600f6f6f6, 0x0077777700777777, 0x0093939300939393, - 0x0086868600868686, 0x0083838300838383, 0x002a2a2a002a2a2a, - 0x00c7c7c700c7c7c7, 0x005b5b5b005b5b5b, 0x00e9e9e900e9e9e9, - 0x00eeeeee00eeeeee, 0x008f8f8f008f8f8f, 0x0001010100010101, - 0x003d3d3d003d3d3d, -}; - -const u64 camellia_sp30333033[256] = { - 0x3800383838003838, 0x4100414141004141, 0x1600161616001616, - 0x7600767676007676, 0xd900d9d9d900d9d9, 0x9300939393009393, - 0x6000606060006060, 0xf200f2f2f200f2f2, 0x7200727272007272, - 0xc200c2c2c200c2c2, 0xab00ababab00abab, 0x9a009a9a9a009a9a, - 0x7500757575007575, 0x0600060606000606, 0x5700575757005757, - 0xa000a0a0a000a0a0, 0x9100919191009191, 0xf700f7f7f700f7f7, - 0xb500b5b5b500b5b5, 0xc900c9c9c900c9c9, 0xa200a2a2a200a2a2, - 0x8c008c8c8c008c8c, 0xd200d2d2d200d2d2, 0x9000909090009090, - 0xf600f6f6f600f6f6, 0x0700070707000707, 0xa700a7a7a700a7a7, - 0x2700272727002727, 0x8e008e8e8e008e8e, 0xb200b2b2b200b2b2, - 0x4900494949004949, 0xde00dedede00dede, 0x4300434343004343, - 0x5c005c5c5c005c5c, 0xd700d7d7d700d7d7, 0xc700c7c7c700c7c7, - 0x3e003e3e3e003e3e, 0xf500f5f5f500f5f5, 0x8f008f8f8f008f8f, - 0x6700676767006767, 0x1f001f1f1f001f1f, 0x1800181818001818, - 0x6e006e6e6e006e6e, 0xaf00afafaf00afaf, 0x2f002f2f2f002f2f, - 0xe200e2e2e200e2e2, 0x8500858585008585, 0x0d000d0d0d000d0d, - 0x5300535353005353, 0xf000f0f0f000f0f0, 0x9c009c9c9c009c9c, - 0x6500656565006565, 0xea00eaeaea00eaea, 0xa300a3a3a300a3a3, - 0xae00aeaeae00aeae, 0x9e009e9e9e009e9e, 0xec00ececec00ecec, - 0x8000808080008080, 0x2d002d2d2d002d2d, 0x6b006b6b6b006b6b, - 0xa800a8a8a800a8a8, 0x2b002b2b2b002b2b, 0x3600363636003636, - 0xa600a6a6a600a6a6, 0xc500c5c5c500c5c5, 0x8600868686008686, - 0x4d004d4d4d004d4d, 0x3300333333003333, 0xfd00fdfdfd00fdfd, - 0x6600666666006666, 0x5800585858005858, 0x9600969696009696, - 0x3a003a3a3a003a3a, 0x0900090909000909, 0x9500959595009595, - 0x1000101010001010, 0x7800787878007878, 0xd800d8d8d800d8d8, - 0x4200424242004242, 0xcc00cccccc00cccc, 0xef00efefef00efef, - 0x2600262626002626, 0xe500e5e5e500e5e5, 0x6100616161006161, - 0x1a001a1a1a001a1a, 0x3f003f3f3f003f3f, 0x3b003b3b3b003b3b, - 0x8200828282008282, 0xb600b6b6b600b6b6, 0xdb00dbdbdb00dbdb, - 0xd400d4d4d400d4d4, 0x9800989898009898, 0xe800e8e8e800e8e8, - 0x8b008b8b8b008b8b, 0x0200020202000202, 0xeb00ebebeb00ebeb, - 0x0a000a0a0a000a0a, 0x2c002c2c2c002c2c, 0x1d001d1d1d001d1d, - 0xb000b0b0b000b0b0, 0x6f006f6f6f006f6f, 0x8d008d8d8d008d8d, - 0x8800888888008888, 0x0e000e0e0e000e0e, 0x1900191919001919, - 0x8700878787008787, 0x4e004e4e4e004e4e, 0x0b000b0b0b000b0b, - 0xa900a9a9a900a9a9, 0x0c000c0c0c000c0c, 0x7900797979007979, - 0x1100111111001111, 0x7f007f7f7f007f7f, 0x2200222222002222, - 0xe700e7e7e700e7e7, 0x5900595959005959, 0xe100e1e1e100e1e1, - 0xda00dadada00dada, 0x3d003d3d3d003d3d, 0xc800c8c8c800c8c8, - 0x1200121212001212, 0x0400040404000404, 0x7400747474007474, - 0x5400545454005454, 0x3000303030003030, 0x7e007e7e7e007e7e, - 0xb400b4b4b400b4b4, 0x2800282828002828, 0x5500555555005555, - 0x6800686868006868, 0x5000505050005050, 0xbe00bebebe00bebe, - 0xd000d0d0d000d0d0, 0xc400c4c4c400c4c4, 0x3100313131003131, - 0xcb00cbcbcb00cbcb, 0x2a002a2a2a002a2a, 0xad00adadad00adad, - 0x0f000f0f0f000f0f, 0xca00cacaca00caca, 0x7000707070007070, - 0xff00ffffff00ffff, 0x3200323232003232, 0x6900696969006969, - 0x0800080808000808, 0x6200626262006262, 0x0000000000000000, - 0x2400242424002424, 0xd100d1d1d100d1d1, 0xfb00fbfbfb00fbfb, - 0xba00bababa00baba, 0xed00ededed00eded, 0x4500454545004545, - 0x8100818181008181, 0x7300737373007373, 0x6d006d6d6d006d6d, - 0x8400848484008484, 0x9f009f9f9f009f9f, 0xee00eeeeee00eeee, - 0x4a004a4a4a004a4a, 0xc300c3c3c300c3c3, 0x2e002e2e2e002e2e, - 0xc100c1c1c100c1c1, 0x0100010101000101, 0xe600e6e6e600e6e6, - 0x2500252525002525, 0x4800484848004848, 0x9900999999009999, - 0xb900b9b9b900b9b9, 0xb300b3b3b300b3b3, 0x7b007b7b7b007b7b, - 0xf900f9f9f900f9f9, 0xce00cecece00cece, 0xbf00bfbfbf00bfbf, - 0xdf00dfdfdf00dfdf, 0x7100717171007171, 0x2900292929002929, - 0xcd00cdcdcd00cdcd, 0x6c006c6c6c006c6c, 0x1300131313001313, - 0x6400646464006464, 0x9b009b9b9b009b9b, 0x6300636363006363, - 0x9d009d9d9d009d9d, 0xc000c0c0c000c0c0, 0x4b004b4b4b004b4b, - 0xb700b7b7b700b7b7, 0xa500a5a5a500a5a5, 0x8900898989008989, - 0x5f005f5f5f005f5f, 0xb100b1b1b100b1b1, 0x1700171717001717, - 0xf400f4f4f400f4f4, 0xbc00bcbcbc00bcbc, 0xd300d3d3d300d3d3, - 0x4600464646004646, 0xcf00cfcfcf00cfcf, 0x3700373737003737, - 0x5e005e5e5e005e5e, 0x4700474747004747, 0x9400949494009494, - 0xfa00fafafa00fafa, 0xfc00fcfcfc00fcfc, 0x5b005b5b5b005b5b, - 0x9700979797009797, 0xfe00fefefe00fefe, 0x5a005a5a5a005a5a, - 0xac00acacac00acac, 0x3c003c3c3c003c3c, 0x4c004c4c4c004c4c, - 0x0300030303000303, 0x3500353535003535, 0xf300f3f3f300f3f3, - 0x2300232323002323, 0xb800b8b8b800b8b8, 0x5d005d5d5d005d5d, - 0x6a006a6a6a006a6a, 0x9200929292009292, 0xd500d5d5d500d5d5, - 0x2100212121002121, 0x4400444444004444, 0x5100515151005151, - 0xc600c6c6c600c6c6, 0x7d007d7d7d007d7d, 0x3900393939003939, - 0x8300838383008383, 0xdc00dcdcdc00dcdc, 0xaa00aaaaaa00aaaa, - 0x7c007c7c7c007c7c, 0x7700777777007777, 0x5600565656005656, - 0x0500050505000505, 0x1b001b1b1b001b1b, 0xa400a4a4a400a4a4, - 0x1500151515001515, 0x3400343434003434, 0x1e001e1e1e001e1e, - 0x1c001c1c1c001c1c, 0xf800f8f8f800f8f8, 0x5200525252005252, - 0x2000202020002020, 0x1400141414001414, 0xe900e9e9e900e9e9, - 0xbd00bdbdbd00bdbd, 0xdd00dddddd00dddd, 0xe400e4e4e400e4e4, - 0xa100a1a1a100a1a1, 0xe000e0e0e000e0e0, 0x8a008a8a8a008a8a, - 0xf100f1f1f100f1f1, 0xd600d6d6d600d6d6, 0x7a007a7a7a007a7a, - 0xbb00bbbbbb00bbbb, 0xe300e3e3e300e3e3, 0x4000404040004040, - 0x4f004f4f4f004f4f, -}; - -const u64 camellia_sp44044404[256] = { - 0x7070007070700070, 0x2c2c002c2c2c002c, 0xb3b300b3b3b300b3, - 0xc0c000c0c0c000c0, 0xe4e400e4e4e400e4, 0x5757005757570057, - 0xeaea00eaeaea00ea, 0xaeae00aeaeae00ae, 0x2323002323230023, - 0x6b6b006b6b6b006b, 0x4545004545450045, 0xa5a500a5a5a500a5, - 0xeded00ededed00ed, 0x4f4f004f4f4f004f, 0x1d1d001d1d1d001d, - 0x9292009292920092, 0x8686008686860086, 0xafaf00afafaf00af, - 0x7c7c007c7c7c007c, 0x1f1f001f1f1f001f, 0x3e3e003e3e3e003e, - 0xdcdc00dcdcdc00dc, 0x5e5e005e5e5e005e, 0x0b0b000b0b0b000b, - 0xa6a600a6a6a600a6, 0x3939003939390039, 0xd5d500d5d5d500d5, - 0x5d5d005d5d5d005d, 0xd9d900d9d9d900d9, 0x5a5a005a5a5a005a, - 0x5151005151510051, 0x6c6c006c6c6c006c, 0x8b8b008b8b8b008b, - 0x9a9a009a9a9a009a, 0xfbfb00fbfbfb00fb, 0xb0b000b0b0b000b0, - 0x7474007474740074, 0x2b2b002b2b2b002b, 0xf0f000f0f0f000f0, - 0x8484008484840084, 0xdfdf00dfdfdf00df, 0xcbcb00cbcbcb00cb, - 0x3434003434340034, 0x7676007676760076, 0x6d6d006d6d6d006d, - 0xa9a900a9a9a900a9, 0xd1d100d1d1d100d1, 0x0404000404040004, - 0x1414001414140014, 0x3a3a003a3a3a003a, 0xdede00dedede00de, - 0x1111001111110011, 0x3232003232320032, 0x9c9c009c9c9c009c, - 0x5353005353530053, 0xf2f200f2f2f200f2, 0xfefe00fefefe00fe, - 0xcfcf00cfcfcf00cf, 0xc3c300c3c3c300c3, 0x7a7a007a7a7a007a, - 0x2424002424240024, 0xe8e800e8e8e800e8, 0x6060006060600060, - 0x6969006969690069, 0xaaaa00aaaaaa00aa, 0xa0a000a0a0a000a0, - 0xa1a100a1a1a100a1, 0x6262006262620062, 0x5454005454540054, - 0x1e1e001e1e1e001e, 0xe0e000e0e0e000e0, 0x6464006464640064, - 0x1010001010100010, 0x0000000000000000, 0xa3a300a3a3a300a3, - 0x7575007575750075, 0x8a8a008a8a8a008a, 0xe6e600e6e6e600e6, - 0x0909000909090009, 0xdddd00dddddd00dd, 0x8787008787870087, - 0x8383008383830083, 0xcdcd00cdcdcd00cd, 0x9090009090900090, - 0x7373007373730073, 0xf6f600f6f6f600f6, 0x9d9d009d9d9d009d, - 0xbfbf00bfbfbf00bf, 0x5252005252520052, 0xd8d800d8d8d800d8, - 0xc8c800c8c8c800c8, 0xc6c600c6c6c600c6, 0x8181008181810081, - 0x6f6f006f6f6f006f, 0x1313001313130013, 0x6363006363630063, - 0xe9e900e9e9e900e9, 0xa7a700a7a7a700a7, 0x9f9f009f9f9f009f, - 0xbcbc00bcbcbc00bc, 0x2929002929290029, 0xf9f900f9f9f900f9, - 0x2f2f002f2f2f002f, 0xb4b400b4b4b400b4, 0x7878007878780078, - 0x0606000606060006, 0xe7e700e7e7e700e7, 0x7171007171710071, - 0xd4d400d4d4d400d4, 0xabab00ababab00ab, 0x8888008888880088, - 0x8d8d008d8d8d008d, 0x7272007272720072, 0xb9b900b9b9b900b9, - 0xf8f800f8f8f800f8, 0xacac00acacac00ac, 0x3636003636360036, - 0x2a2a002a2a2a002a, 0x3c3c003c3c3c003c, 0xf1f100f1f1f100f1, - 0x4040004040400040, 0xd3d300d3d3d300d3, 0xbbbb00bbbbbb00bb, - 0x4343004343430043, 0x1515001515150015, 0xadad00adadad00ad, - 0x7777007777770077, 0x8080008080800080, 0x8282008282820082, - 0xecec00ececec00ec, 0x2727002727270027, 0xe5e500e5e5e500e5, - 0x8585008585850085, 0x3535003535350035, 0x0c0c000c0c0c000c, - 0x4141004141410041, 0xefef00efefef00ef, 0x9393009393930093, - 0x1919001919190019, 0x2121002121210021, 0x0e0e000e0e0e000e, - 0x4e4e004e4e4e004e, 0x6565006565650065, 0xbdbd00bdbdbd00bd, - 0xb8b800b8b8b800b8, 0x8f8f008f8f8f008f, 0xebeb00ebebeb00eb, - 0xcece00cecece00ce, 0x3030003030300030, 0x5f5f005f5f5f005f, - 0xc5c500c5c5c500c5, 0x1a1a001a1a1a001a, 0xe1e100e1e1e100e1, - 0xcaca00cacaca00ca, 0x4747004747470047, 0x3d3d003d3d3d003d, - 0x0101000101010001, 0xd6d600d6d6d600d6, 0x5656005656560056, - 0x4d4d004d4d4d004d, 0x0d0d000d0d0d000d, 0x6666006666660066, - 0xcccc00cccccc00cc, 0x2d2d002d2d2d002d, 0x1212001212120012, - 0x2020002020200020, 0xb1b100b1b1b100b1, 0x9999009999990099, - 0x4c4c004c4c4c004c, 0xc2c200c2c2c200c2, 0x7e7e007e7e7e007e, - 0x0505000505050005, 0xb7b700b7b7b700b7, 0x3131003131310031, - 0x1717001717170017, 0xd7d700d7d7d700d7, 0x5858005858580058, - 0x6161006161610061, 0x1b1b001b1b1b001b, 0x1c1c001c1c1c001c, - 0x0f0f000f0f0f000f, 0x1616001616160016, 0x1818001818180018, - 0x2222002222220022, 0x4444004444440044, 0xb2b200b2b2b200b2, - 0xb5b500b5b5b500b5, 0x9191009191910091, 0x0808000808080008, - 0xa8a800a8a8a800a8, 0xfcfc00fcfcfc00fc, 0x5050005050500050, - 0xd0d000d0d0d000d0, 0x7d7d007d7d7d007d, 0x8989008989890089, - 0x9797009797970097, 0x5b5b005b5b5b005b, 0x9595009595950095, - 0xffff00ffffff00ff, 0xd2d200d2d2d200d2, 0xc4c400c4c4c400c4, - 0x4848004848480048, 0xf7f700f7f7f700f7, 0xdbdb00dbdbdb00db, - 0x0303000303030003, 0xdada00dadada00da, 0x3f3f003f3f3f003f, - 0x9494009494940094, 0x5c5c005c5c5c005c, 0x0202000202020002, - 0x4a4a004a4a4a004a, 0x3333003333330033, 0x6767006767670067, - 0xf3f300f3f3f300f3, 0x7f7f007f7f7f007f, 0xe2e200e2e2e200e2, - 0x9b9b009b9b9b009b, 0x2626002626260026, 0x3737003737370037, - 0x3b3b003b3b3b003b, 0x9696009696960096, 0x4b4b004b4b4b004b, - 0xbebe00bebebe00be, 0x2e2e002e2e2e002e, 0x7979007979790079, - 0x8c8c008c8c8c008c, 0x6e6e006e6e6e006e, 0x8e8e008e8e8e008e, - 0xf5f500f5f5f500f5, 0xb6b600b6b6b600b6, 0xfdfd00fdfdfd00fd, - 0x5959005959590059, 0x9898009898980098, 0x6a6a006a6a6a006a, - 0x4646004646460046, 0xbaba00bababa00ba, 0x2525002525250025, - 0x4242004242420042, 0xa2a200a2a2a200a2, 0xfafa00fafafa00fa, - 0x0707000707070007, 0x5555005555550055, 0xeeee00eeeeee00ee, - 0x0a0a000a0a0a000a, 0x4949004949490049, 0x6868006868680068, - 0x3838003838380038, 0xa4a400a4a4a400a4, 0x2828002828280028, - 0x7b7b007b7b7b007b, 0xc9c900c9c9c900c9, 0xc1c100c1c1c100c1, - 0xe3e300e3e3e300e3, 0xf4f400f4f4f400f4, 0xc7c700c7c7c700c7, - 0x9e9e009e9e9e009e, -}; - -const u64 camellia_sp11101110[256] = { - 0x7070700070707000, 0x8282820082828200, 0x2c2c2c002c2c2c00, - 0xececec00ececec00, 0xb3b3b300b3b3b300, 0x2727270027272700, - 0xc0c0c000c0c0c000, 0xe5e5e500e5e5e500, 0xe4e4e400e4e4e400, - 0x8585850085858500, 0x5757570057575700, 0x3535350035353500, - 0xeaeaea00eaeaea00, 0x0c0c0c000c0c0c00, 0xaeaeae00aeaeae00, - 0x4141410041414100, 0x2323230023232300, 0xefefef00efefef00, - 0x6b6b6b006b6b6b00, 0x9393930093939300, 0x4545450045454500, - 0x1919190019191900, 0xa5a5a500a5a5a500, 0x2121210021212100, - 0xededed00ededed00, 0x0e0e0e000e0e0e00, 0x4f4f4f004f4f4f00, - 0x4e4e4e004e4e4e00, 0x1d1d1d001d1d1d00, 0x6565650065656500, - 0x9292920092929200, 0xbdbdbd00bdbdbd00, 0x8686860086868600, - 0xb8b8b800b8b8b800, 0xafafaf00afafaf00, 0x8f8f8f008f8f8f00, - 0x7c7c7c007c7c7c00, 0xebebeb00ebebeb00, 0x1f1f1f001f1f1f00, - 0xcecece00cecece00, 0x3e3e3e003e3e3e00, 0x3030300030303000, - 0xdcdcdc00dcdcdc00, 0x5f5f5f005f5f5f00, 0x5e5e5e005e5e5e00, - 0xc5c5c500c5c5c500, 0x0b0b0b000b0b0b00, 0x1a1a1a001a1a1a00, - 0xa6a6a600a6a6a600, 0xe1e1e100e1e1e100, 0x3939390039393900, - 0xcacaca00cacaca00, 0xd5d5d500d5d5d500, 0x4747470047474700, - 0x5d5d5d005d5d5d00, 0x3d3d3d003d3d3d00, 0xd9d9d900d9d9d900, - 0x0101010001010100, 0x5a5a5a005a5a5a00, 0xd6d6d600d6d6d600, - 0x5151510051515100, 0x5656560056565600, 0x6c6c6c006c6c6c00, - 0x4d4d4d004d4d4d00, 0x8b8b8b008b8b8b00, 0x0d0d0d000d0d0d00, - 0x9a9a9a009a9a9a00, 0x6666660066666600, 0xfbfbfb00fbfbfb00, - 0xcccccc00cccccc00, 0xb0b0b000b0b0b000, 0x2d2d2d002d2d2d00, - 0x7474740074747400, 0x1212120012121200, 0x2b2b2b002b2b2b00, - 0x2020200020202000, 0xf0f0f000f0f0f000, 0xb1b1b100b1b1b100, - 0x8484840084848400, 0x9999990099999900, 0xdfdfdf00dfdfdf00, - 0x4c4c4c004c4c4c00, 0xcbcbcb00cbcbcb00, 0xc2c2c200c2c2c200, - 0x3434340034343400, 0x7e7e7e007e7e7e00, 0x7676760076767600, - 0x0505050005050500, 0x6d6d6d006d6d6d00, 0xb7b7b700b7b7b700, - 0xa9a9a900a9a9a900, 0x3131310031313100, 0xd1d1d100d1d1d100, - 0x1717170017171700, 0x0404040004040400, 0xd7d7d700d7d7d700, - 0x1414140014141400, 0x5858580058585800, 0x3a3a3a003a3a3a00, - 0x6161610061616100, 0xdedede00dedede00, 0x1b1b1b001b1b1b00, - 0x1111110011111100, 0x1c1c1c001c1c1c00, 0x3232320032323200, - 0x0f0f0f000f0f0f00, 0x9c9c9c009c9c9c00, 0x1616160016161600, - 0x5353530053535300, 0x1818180018181800, 0xf2f2f200f2f2f200, - 0x2222220022222200, 0xfefefe00fefefe00, 0x4444440044444400, - 0xcfcfcf00cfcfcf00, 0xb2b2b200b2b2b200, 0xc3c3c300c3c3c300, - 0xb5b5b500b5b5b500, 0x7a7a7a007a7a7a00, 0x9191910091919100, - 0x2424240024242400, 0x0808080008080800, 0xe8e8e800e8e8e800, - 0xa8a8a800a8a8a800, 0x6060600060606000, 0xfcfcfc00fcfcfc00, - 0x6969690069696900, 0x5050500050505000, 0xaaaaaa00aaaaaa00, - 0xd0d0d000d0d0d000, 0xa0a0a000a0a0a000, 0x7d7d7d007d7d7d00, - 0xa1a1a100a1a1a100, 0x8989890089898900, 0x6262620062626200, - 0x9797970097979700, 0x5454540054545400, 0x5b5b5b005b5b5b00, - 0x1e1e1e001e1e1e00, 0x9595950095959500, 0xe0e0e000e0e0e000, - 0xffffff00ffffff00, 0x6464640064646400, 0xd2d2d200d2d2d200, - 0x1010100010101000, 0xc4c4c400c4c4c400, 0x0000000000000000, - 0x4848480048484800, 0xa3a3a300a3a3a300, 0xf7f7f700f7f7f700, - 0x7575750075757500, 0xdbdbdb00dbdbdb00, 0x8a8a8a008a8a8a00, - 0x0303030003030300, 0xe6e6e600e6e6e600, 0xdadada00dadada00, - 0x0909090009090900, 0x3f3f3f003f3f3f00, 0xdddddd00dddddd00, - 0x9494940094949400, 0x8787870087878700, 0x5c5c5c005c5c5c00, - 0x8383830083838300, 0x0202020002020200, 0xcdcdcd00cdcdcd00, - 0x4a4a4a004a4a4a00, 0x9090900090909000, 0x3333330033333300, - 0x7373730073737300, 0x6767670067676700, 0xf6f6f600f6f6f600, - 0xf3f3f300f3f3f300, 0x9d9d9d009d9d9d00, 0x7f7f7f007f7f7f00, - 0xbfbfbf00bfbfbf00, 0xe2e2e200e2e2e200, 0x5252520052525200, - 0x9b9b9b009b9b9b00, 0xd8d8d800d8d8d800, 0x2626260026262600, - 0xc8c8c800c8c8c800, 0x3737370037373700, 0xc6c6c600c6c6c600, - 0x3b3b3b003b3b3b00, 0x8181810081818100, 0x9696960096969600, - 0x6f6f6f006f6f6f00, 0x4b4b4b004b4b4b00, 0x1313130013131300, - 0xbebebe00bebebe00, 0x6363630063636300, 0x2e2e2e002e2e2e00, - 0xe9e9e900e9e9e900, 0x7979790079797900, 0xa7a7a700a7a7a700, - 0x8c8c8c008c8c8c00, 0x9f9f9f009f9f9f00, 0x6e6e6e006e6e6e00, - 0xbcbcbc00bcbcbc00, 0x8e8e8e008e8e8e00, 0x2929290029292900, - 0xf5f5f500f5f5f500, 0xf9f9f900f9f9f900, 0xb6b6b600b6b6b600, - 0x2f2f2f002f2f2f00, 0xfdfdfd00fdfdfd00, 0xb4b4b400b4b4b400, - 0x5959590059595900, 0x7878780078787800, 0x9898980098989800, - 0x0606060006060600, 0x6a6a6a006a6a6a00, 0xe7e7e700e7e7e700, - 0x4646460046464600, 0x7171710071717100, 0xbababa00bababa00, - 0xd4d4d400d4d4d400, 0x2525250025252500, 0xababab00ababab00, - 0x4242420042424200, 0x8888880088888800, 0xa2a2a200a2a2a200, - 0x8d8d8d008d8d8d00, 0xfafafa00fafafa00, 0x7272720072727200, - 0x0707070007070700, 0xb9b9b900b9b9b900, 0x5555550055555500, - 0xf8f8f800f8f8f800, 0xeeeeee00eeeeee00, 0xacacac00acacac00, - 0x0a0a0a000a0a0a00, 0x3636360036363600, 0x4949490049494900, - 0x2a2a2a002a2a2a00, 0x6868680068686800, 0x3c3c3c003c3c3c00, - 0x3838380038383800, 0xf1f1f100f1f1f100, 0xa4a4a400a4a4a400, - 0x4040400040404000, 0x2828280028282800, 0xd3d3d300d3d3d300, - 0x7b7b7b007b7b7b00, 0xbbbbbb00bbbbbb00, 0xc9c9c900c9c9c900, - 0x4343430043434300, 0xc1c1c100c1c1c100, 0x1515150015151500, - 0xe3e3e300e3e3e300, 0xadadad00adadad00, 0xf4f4f400f4f4f400, - 0x7777770077777700, 0xc7c7c700c7c7c700, 0x8080800080808000, - 0x9e9e9e009e9e9e00, -}; - -/* key constants */ -#define CAMELLIA_SIGMA1L (0xA09E667FL) -#define CAMELLIA_SIGMA1R (0x3BCC908BL) -#define CAMELLIA_SIGMA2L (0xB67AE858L) -#define CAMELLIA_SIGMA2R (0x4CAA73B2L) -#define CAMELLIA_SIGMA3L (0xC6EF372FL) -#define CAMELLIA_SIGMA3R (0xE94F82BEL) -#define CAMELLIA_SIGMA4L (0x54FF53A5L) -#define CAMELLIA_SIGMA4R (0xF1D36F1CL) -#define CAMELLIA_SIGMA5L (0x10E527FAL) -#define CAMELLIA_SIGMA5R (0xDE682D1DL) -#define CAMELLIA_SIGMA6L (0xB05688C2L) -#define CAMELLIA_SIGMA6R (0xB3E6C1FDL) - -/* macros */ -#define ROLDQ(l, r, bits) ({ \ - u64 t = l; \ - l = (l << bits) | (r >> (64 - bits)); \ - r = (r << bits) | (t >> (64 - bits)); \ -}) - -#define CAMELLIA_F(x, kl, kr, y) ({ \ - u64 ii = x ^ (((u64)kl << 32) | kr); \ - y = camellia_sp11101110[(uint8_t)ii]; \ - y ^= camellia_sp44044404[(uint8_t)(ii >> 8)]; \ - ii >>= 16; \ - y ^= camellia_sp30333033[(uint8_t)ii]; \ - y ^= camellia_sp02220222[(uint8_t)(ii >> 8)]; \ - ii >>= 16; \ - y ^= camellia_sp00444404[(uint8_t)ii]; \ - y ^= camellia_sp03303033[(uint8_t)(ii >> 8)]; \ - ii >>= 16; \ - y ^= camellia_sp22000222[(uint8_t)ii]; \ - y ^= camellia_sp10011110[(uint8_t)(ii >> 8)]; \ - y = ror64(y, 32); \ -}) - -#define SET_SUBKEY_LR(INDEX, sRL) (subkey[(INDEX)] = ror64((sRL), 32)) - -static void camellia_setup_tail(u64 *subkey, u64 *subRL, int max) -{ - u64 kw4, tt; - u32 dw, tl, tr; - - /* absorb kw2 to other subkeys */ - /* round 2 */ - subRL[3] ^= subRL[1]; - /* round 4 */ - subRL[5] ^= subRL[1]; - /* round 6 */ - subRL[7] ^= subRL[1]; - - subRL[1] ^= (subRL[1] & ~subRL[9]) << 32; - /* modified for FLinv(kl2) */ - dw = (subRL[1] & subRL[9]) >> 32, - subRL[1] ^= rol32(dw, 1); - - /* round 8 */ - subRL[11] ^= subRL[1]; - /* round 10 */ - subRL[13] ^= subRL[1]; - /* round 12 */ - subRL[15] ^= subRL[1]; - - subRL[1] ^= (subRL[1] & ~subRL[17]) << 32; - /* modified for FLinv(kl4) */ - dw = (subRL[1] & subRL[17]) >> 32, - subRL[1] ^= rol32(dw, 1); - - /* round 14 */ - subRL[19] ^= subRL[1]; - /* round 16 */ - subRL[21] ^= subRL[1]; - /* round 18 */ - subRL[23] ^= subRL[1]; - - if (max == 24) { - /* kw3 */ - subRL[24] ^= subRL[1]; - - /* absorb kw4 to other subkeys */ - kw4 = subRL[25]; - } else { - subRL[1] ^= (subRL[1] & ~subRL[25]) << 32; - /* modified for FLinv(kl6) */ - dw = (subRL[1] & subRL[25]) >> 32, - subRL[1] ^= rol32(dw, 1); - - /* round 20 */ - subRL[27] ^= subRL[1]; - /* round 22 */ - subRL[29] ^= subRL[1]; - /* round 24 */ - subRL[31] ^= subRL[1]; - /* kw3 */ - subRL[32] ^= subRL[1]; - - /* absorb kw4 to other subkeys */ - kw4 = subRL[33]; - /* round 23 */ - subRL[30] ^= kw4; - /* round 21 */ - subRL[28] ^= kw4; - /* round 19 */ - subRL[26] ^= kw4; - - kw4 ^= (kw4 & ~subRL[24]) << 32; - /* modified for FL(kl5) */ - dw = (kw4 & subRL[24]) >> 32, - kw4 ^= rol32(dw, 1); - } - - /* round 17 */ - subRL[22] ^= kw4; - /* round 15 */ - subRL[20] ^= kw4; - /* round 13 */ - subRL[18] ^= kw4; - - kw4 ^= (kw4 & ~subRL[16]) << 32; - /* modified for FL(kl3) */ - dw = (kw4 & subRL[16]) >> 32, - kw4 ^= rol32(dw, 1); - - /* round 11 */ - subRL[14] ^= kw4; - /* round 9 */ - subRL[12] ^= kw4; - /* round 7 */ - subRL[10] ^= kw4; - - kw4 ^= (kw4 & ~subRL[8]) << 32; - /* modified for FL(kl1) */ - dw = (kw4 & subRL[8]) >> 32, - kw4 ^= rol32(dw, 1); - - /* round 5 */ - subRL[6] ^= kw4; - /* round 3 */ - subRL[4] ^= kw4; - /* round 1 */ - subRL[2] ^= kw4; - /* kw1 */ - subRL[0] ^= kw4; - - /* key XOR is end of F-function */ - SET_SUBKEY_LR(0, subRL[0] ^ subRL[2]); /* kw1 */ - SET_SUBKEY_LR(2, subRL[3]); /* round 1 */ - SET_SUBKEY_LR(3, subRL[2] ^ subRL[4]); /* round 2 */ - SET_SUBKEY_LR(4, subRL[3] ^ subRL[5]); /* round 3 */ - SET_SUBKEY_LR(5, subRL[4] ^ subRL[6]); /* round 4 */ - SET_SUBKEY_LR(6, subRL[5] ^ subRL[7]); /* round 5 */ - - tl = (subRL[10] >> 32) ^ (subRL[10] & ~subRL[8]); - dw = tl & (subRL[8] >> 32), /* FL(kl1) */ - tr = subRL[10] ^ rol32(dw, 1); - tt = (tr | ((u64)tl << 32)); - - SET_SUBKEY_LR(7, subRL[6] ^ tt); /* round 6 */ - SET_SUBKEY_LR(8, subRL[8]); /* FL(kl1) */ - SET_SUBKEY_LR(9, subRL[9]); /* FLinv(kl2) */ - - tl = (subRL[7] >> 32) ^ (subRL[7] & ~subRL[9]); - dw = tl & (subRL[9] >> 32), /* FLinv(kl2) */ - tr = subRL[7] ^ rol32(dw, 1); - tt = (tr | ((u64)tl << 32)); - - SET_SUBKEY_LR(10, subRL[11] ^ tt); /* round 7 */ - SET_SUBKEY_LR(11, subRL[10] ^ subRL[12]); /* round 8 */ - SET_SUBKEY_LR(12, subRL[11] ^ subRL[13]); /* round 9 */ - SET_SUBKEY_LR(13, subRL[12] ^ subRL[14]); /* round 10 */ - SET_SUBKEY_LR(14, subRL[13] ^ subRL[15]); /* round 11 */ - - tl = (subRL[18] >> 32) ^ (subRL[18] & ~subRL[16]); - dw = tl & (subRL[16] >> 32), /* FL(kl3) */ - tr = subRL[18] ^ rol32(dw, 1); - tt = (tr | ((u64)tl << 32)); - - SET_SUBKEY_LR(15, subRL[14] ^ tt); /* round 12 */ - SET_SUBKEY_LR(16, subRL[16]); /* FL(kl3) */ - SET_SUBKEY_LR(17, subRL[17]); /* FLinv(kl4) */ - - tl = (subRL[15] >> 32) ^ (subRL[15] & ~subRL[17]); - dw = tl & (subRL[17] >> 32), /* FLinv(kl4) */ - tr = subRL[15] ^ rol32(dw, 1); - tt = (tr | ((u64)tl << 32)); - - SET_SUBKEY_LR(18, subRL[19] ^ tt); /* round 13 */ - SET_SUBKEY_LR(19, subRL[18] ^ subRL[20]); /* round 14 */ - SET_SUBKEY_LR(20, subRL[19] ^ subRL[21]); /* round 15 */ - SET_SUBKEY_LR(21, subRL[20] ^ subRL[22]); /* round 16 */ - SET_SUBKEY_LR(22, subRL[21] ^ subRL[23]); /* round 17 */ - - if (max == 24) { - SET_SUBKEY_LR(23, subRL[22]); /* round 18 */ - SET_SUBKEY_LR(24, subRL[24] ^ subRL[23]); /* kw3 */ - } else { - tl = (subRL[26] >> 32) ^ (subRL[26] & ~subRL[24]); - dw = tl & (subRL[24] >> 32), /* FL(kl5) */ - tr = subRL[26] ^ rol32(dw, 1); - tt = (tr | ((u64)tl << 32)); - - SET_SUBKEY_LR(23, subRL[22] ^ tt); /* round 18 */ - SET_SUBKEY_LR(24, subRL[24]); /* FL(kl5) */ - SET_SUBKEY_LR(25, subRL[25]); /* FLinv(kl6) */ - - tl = (subRL[23] >> 32) ^ (subRL[23] & ~subRL[25]); - dw = tl & (subRL[25] >> 32), /* FLinv(kl6) */ - tr = subRL[23] ^ rol32(dw, 1); - tt = (tr | ((u64)tl << 32)); - - SET_SUBKEY_LR(26, subRL[27] ^ tt); /* round 19 */ - SET_SUBKEY_LR(27, subRL[26] ^ subRL[28]); /* round 20 */ - SET_SUBKEY_LR(28, subRL[27] ^ subRL[29]); /* round 21 */ - SET_SUBKEY_LR(29, subRL[28] ^ subRL[30]); /* round 22 */ - SET_SUBKEY_LR(30, subRL[29] ^ subRL[31]); /* round 23 */ - SET_SUBKEY_LR(31, subRL[30]); /* round 24 */ - SET_SUBKEY_LR(32, subRL[32] ^ subRL[31]); /* kw3 */ - } -} - -static void camellia_setup128(const unsigned char *key, u64 *subkey) -{ - u64 kl, kr, ww; - u64 subRL[26]; - - /** - * k == kl || kr (|| is concatenation) - */ - kl = get_unaligned_be64(key); - kr = get_unaligned_be64(key + 8); - - /* generate KL dependent subkeys */ - /* kw1 */ - subRL[0] = kl; - /* kw2 */ - subRL[1] = kr; - - /* rotation left shift 15bit */ - ROLDQ(kl, kr, 15); - - /* k3 */ - subRL[4] = kl; - /* k4 */ - subRL[5] = kr; - - /* rotation left shift 15+30bit */ - ROLDQ(kl, kr, 30); - - /* k7 */ - subRL[10] = kl; - /* k8 */ - subRL[11] = kr; - - /* rotation left shift 15+30+15bit */ - ROLDQ(kl, kr, 15); - - /* k10 */ - subRL[13] = kr; - /* rotation left shift 15+30+15+17 bit */ - ROLDQ(kl, kr, 17); - - /* kl3 */ - subRL[16] = kl; - /* kl4 */ - subRL[17] = kr; - - /* rotation left shift 15+30+15+17+17 bit */ - ROLDQ(kl, kr, 17); - - /* k13 */ - subRL[18] = kl; - /* k14 */ - subRL[19] = kr; - - /* rotation left shift 15+30+15+17+17+17 bit */ - ROLDQ(kl, kr, 17); - - /* k17 */ - subRL[22] = kl; - /* k18 */ - subRL[23] = kr; - - /* generate KA */ - kl = subRL[0]; - kr = subRL[1]; - CAMELLIA_F(kl, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, ww); - kr ^= ww; - CAMELLIA_F(kr, CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, kl); - - /* current status == (kll, klr, w0, w1) */ - CAMELLIA_F(kl, CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, kr); - kr ^= ww; - CAMELLIA_F(kr, CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, ww); - kl ^= ww; - - /* generate KA dependent subkeys */ - /* k1, k2 */ - subRL[2] = kl; - subRL[3] = kr; - ROLDQ(kl, kr, 15); - /* k5,k6 */ - subRL[6] = kl; - subRL[7] = kr; - ROLDQ(kl, kr, 15); - /* kl1, kl2 */ - subRL[8] = kl; - subRL[9] = kr; - ROLDQ(kl, kr, 15); - /* k9 */ - subRL[12] = kl; - ROLDQ(kl, kr, 15); - /* k11, k12 */ - subRL[14] = kl; - subRL[15] = kr; - ROLDQ(kl, kr, 34); - /* k15, k16 */ - subRL[20] = kl; - subRL[21] = kr; - ROLDQ(kl, kr, 17); - /* kw3, kw4 */ - subRL[24] = kl; - subRL[25] = kr; - - camellia_setup_tail(subkey, subRL, 24); -} - -static void camellia_setup256(const unsigned char *key, u64 *subkey) -{ - u64 kl, kr; /* left half of key */ - u64 krl, krr; /* right half of key */ - u64 ww; /* temporary variables */ - u64 subRL[34]; - - /** - * key = (kl || kr || krl || krr) (|| is concatenation) - */ - kl = get_unaligned_be64(key); - kr = get_unaligned_be64(key + 8); - krl = get_unaligned_be64(key + 16); - krr = get_unaligned_be64(key + 24); - - /* generate KL dependent subkeys */ - /* kw1 */ - subRL[0] = kl; - /* kw2 */ - subRL[1] = kr; - ROLDQ(kl, kr, 45); - /* k9 */ - subRL[12] = kl; - /* k10 */ - subRL[13] = kr; - ROLDQ(kl, kr, 15); - /* kl3 */ - subRL[16] = kl; - /* kl4 */ - subRL[17] = kr; - ROLDQ(kl, kr, 17); - /* k17 */ - subRL[22] = kl; - /* k18 */ - subRL[23] = kr; - ROLDQ(kl, kr, 34); - /* k23 */ - subRL[30] = kl; - /* k24 */ - subRL[31] = kr; - - /* generate KR dependent subkeys */ - ROLDQ(krl, krr, 15); - /* k3 */ - subRL[4] = krl; - /* k4 */ - subRL[5] = krr; - ROLDQ(krl, krr, 15); - /* kl1 */ - subRL[8] = krl; - /* kl2 */ - subRL[9] = krr; - ROLDQ(krl, krr, 30); - /* k13 */ - subRL[18] = krl; - /* k14 */ - subRL[19] = krr; - ROLDQ(krl, krr, 34); - /* k19 */ - subRL[26] = krl; - /* k20 */ - subRL[27] = krr; - ROLDQ(krl, krr, 34); - - /* generate KA */ - kl = subRL[0] ^ krl; - kr = subRL[1] ^ krr; - - CAMELLIA_F(kl, CAMELLIA_SIGMA1L, CAMELLIA_SIGMA1R, ww); - kr ^= ww; - CAMELLIA_F(kr, CAMELLIA_SIGMA2L, CAMELLIA_SIGMA2R, kl); - kl ^= krl; - CAMELLIA_F(kl, CAMELLIA_SIGMA3L, CAMELLIA_SIGMA3R, kr); - kr ^= ww ^ krr; - CAMELLIA_F(kr, CAMELLIA_SIGMA4L, CAMELLIA_SIGMA4R, ww); - kl ^= ww; - - /* generate KB */ - krl ^= kl; - krr ^= kr; - CAMELLIA_F(krl, CAMELLIA_SIGMA5L, CAMELLIA_SIGMA5R, ww); - krr ^= ww; - CAMELLIA_F(krr, CAMELLIA_SIGMA6L, CAMELLIA_SIGMA6R, ww); - krl ^= ww; - - /* generate KA dependent subkeys */ - ROLDQ(kl, kr, 15); - /* k5 */ - subRL[6] = kl; - /* k6 */ - subRL[7] = kr; - ROLDQ(kl, kr, 30); - /* k11 */ - subRL[14] = kl; - /* k12 */ - subRL[15] = kr; - /* rotation left shift 32bit */ - ROLDQ(kl, kr, 32); - /* kl5 */ - subRL[24] = kl; - /* kl6 */ - subRL[25] = kr; - /* rotation left shift 17 from k11,k12 -> k21,k22 */ - ROLDQ(kl, kr, 17); - /* k21 */ - subRL[28] = kl; - /* k22 */ - subRL[29] = kr; - - /* generate KB dependent subkeys */ - /* k1 */ - subRL[2] = krl; - /* k2 */ - subRL[3] = krr; - ROLDQ(krl, krr, 30); - /* k7 */ - subRL[10] = krl; - /* k8 */ - subRL[11] = krr; - ROLDQ(krl, krr, 30); - /* k15 */ - subRL[20] = krl; - /* k16 */ - subRL[21] = krr; - ROLDQ(krl, krr, 51); - /* kw3 */ - subRL[32] = krl; - /* kw4 */ - subRL[33] = krr; - - camellia_setup_tail(subkey, subRL, 32); -} - -static void camellia_setup192(const unsigned char *key, u64 *subkey) -{ - unsigned char kk[32]; - u64 krl, krr; - - memcpy(kk, key, 24); - memcpy((unsigned char *)&krl, key+16, 8); - krr = ~krl; - memcpy(kk+24, (unsigned char *)&krr, 8); - camellia_setup256(kk, subkey); -} - -static int __camellia_setkey(struct camellia_ctx *cctx, - const unsigned char *key, - unsigned int key_len, u32 *flags) -{ - if (key_len != 16 && key_len != 24 && key_len != 32) { - *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; - } - - cctx->key_length = key_len; - - switch (key_len) { - case 16: - camellia_setup128(key, cctx->key_table); - break; - case 24: - camellia_setup192(key, cctx->key_table); - break; - case 32: - camellia_setup256(key, cctx->key_table); - break; - } - - return 0; -} - -static int camellia_setkey(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len) -{ - return __camellia_setkey(crypto_tfm_ctx(tfm), in_key, key_len, - &tfm->crt_flags); -} - -static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, - void (*fn)(struct camellia_ctx *, u8 *, const u8 *), - void (*fn_2way)(struct camellia_ctx *, u8 *, const u8 *)) -{ - struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); - unsigned int bsize = CAMELLIA_BLOCK_SIZE; - unsigned int nbytes; - int err; - - err = blkcipher_walk_virt(desc, walk); - - while ((nbytes = walk->nbytes)) { - u8 *wsrc = walk->src.virt.addr; - u8 *wdst = walk->dst.virt.addr; - - /* Process two block batch */ - if (nbytes >= bsize * 2) { - do { - fn_2way(ctx, wdst, wsrc); - - wsrc += bsize * 2; - wdst += bsize * 2; - nbytes -= bsize * 2; - } while (nbytes >= bsize * 2); - - if (nbytes < bsize) - goto done; - } - - /* Handle leftovers */ - do { - fn(ctx, wdst, wsrc); - - wsrc += bsize; - wdst += bsize; - nbytes -= bsize; - } while (nbytes >= bsize); - -done: - err = blkcipher_walk_done(desc, walk, nbytes); - } - - return err; -} - -static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct blkcipher_walk walk; - - blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_crypt(desc, &walk, camellia_enc_blk, camellia_enc_blk_2way); -} - -static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct blkcipher_walk walk; - - blkcipher_walk_init(&walk, dst, src, nbytes); - return ecb_crypt(desc, &walk, camellia_dec_blk, camellia_dec_blk_2way); -} - -static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, - struct blkcipher_walk *walk) -{ - struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); - unsigned int bsize = CAMELLIA_BLOCK_SIZE; - unsigned int nbytes = walk->nbytes; - u128 *src = (u128 *)walk->src.virt.addr; - u128 *dst = (u128 *)walk->dst.virt.addr; - u128 *iv = (u128 *)walk->iv; - - do { - u128_xor(dst, src, iv); - camellia_enc_blk(ctx, (u8 *)dst, (u8 *)dst); - iv = dst; - - src += 1; - dst += 1; - nbytes -= bsize; - } while (nbytes >= bsize); - - u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv); - return nbytes; -} - -static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct blkcipher_walk walk; - int err; - - blkcipher_walk_init(&walk, dst, src, nbytes); - err = blkcipher_walk_virt(desc, &walk); - - while ((nbytes = walk.nbytes)) { - nbytes = __cbc_encrypt(desc, &walk); - err = blkcipher_walk_done(desc, &walk, nbytes); - } - - return err; -} - -static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, - struct blkcipher_walk *walk) -{ - struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); - unsigned int bsize = CAMELLIA_BLOCK_SIZE; - unsigned int nbytes = walk->nbytes; - u128 *src = (u128 *)walk->src.virt.addr; - u128 *dst = (u128 *)walk->dst.virt.addr; - u128 ivs[2 - 1]; - u128 last_iv; - - /* Start of the last block. */ - src += nbytes / bsize - 1; - dst += nbytes / bsize - 1; - - last_iv = *src; - - /* Process two block batch */ - if (nbytes >= bsize * 2) { - do { - nbytes -= bsize * (2 - 1); - src -= 2 - 1; - dst -= 2 - 1; - - ivs[0] = src[0]; - - camellia_dec_blk_2way(ctx, (u8 *)dst, (u8 *)src); - - u128_xor(dst + 1, dst + 1, ivs + 0); - - nbytes -= bsize; - if (nbytes < bsize) - goto done; - - u128_xor(dst, dst, src - 1); - src -= 1; - dst -= 1; - } while (nbytes >= bsize * 2); - - if (nbytes < bsize) - goto done; - } - - /* Handle leftovers */ - for (;;) { - camellia_dec_blk(ctx, (u8 *)dst, (u8 *)src); - - nbytes -= bsize; - if (nbytes < bsize) - break; - - u128_xor(dst, dst, src - 1); - src -= 1; - dst -= 1; - } - -done: - u128_xor(dst, dst, (u128 *)walk->iv); - *(u128 *)walk->iv = last_iv; - - return nbytes; -} - -static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct blkcipher_walk walk; - int err; - - blkcipher_walk_init(&walk, dst, src, nbytes); - err = blkcipher_walk_virt(desc, &walk); - - while ((nbytes = walk.nbytes)) { - nbytes = __cbc_decrypt(desc, &walk); - err = blkcipher_walk_done(desc, &walk, nbytes); - } - - return err; -} - -static inline void u128_to_be128(be128 *dst, const u128 *src) -{ - dst->a = cpu_to_be64(src->a); - dst->b = cpu_to_be64(src->b); -} - -static inline void be128_to_u128(u128 *dst, const be128 *src) -{ - dst->a = be64_to_cpu(src->a); - dst->b = be64_to_cpu(src->b); -} - -static inline void u128_inc(u128 *i) -{ - i->b++; - if (!i->b) - i->a++; -} - -static void ctr_crypt_final(struct blkcipher_desc *desc, - struct blkcipher_walk *walk) -{ - struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); - u8 keystream[CAMELLIA_BLOCK_SIZE]; - u8 *src = walk->src.virt.addr; - u8 *dst = walk->dst.virt.addr; - unsigned int nbytes = walk->nbytes; - u128 ctrblk; - - memcpy(keystream, src, nbytes); - camellia_enc_blk_xor(ctx, keystream, walk->iv); - memcpy(dst, keystream, nbytes); - - be128_to_u128(&ctrblk, (be128 *)walk->iv); - u128_inc(&ctrblk); - u128_to_be128((be128 *)walk->iv, &ctrblk); -} - -static unsigned int __ctr_crypt(struct blkcipher_desc *desc, - struct blkcipher_walk *walk) -{ - struct camellia_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); - unsigned int bsize = CAMELLIA_BLOCK_SIZE; - unsigned int nbytes = walk->nbytes; - u128 *src = (u128 *)walk->src.virt.addr; - u128 *dst = (u128 *)walk->dst.virt.addr; - u128 ctrblk; - be128 ctrblocks[2]; - - be128_to_u128(&ctrblk, (be128 *)walk->iv); - - /* Process two block batch */ - if (nbytes >= bsize * 2) { - do { - if (dst != src) { - dst[0] = src[0]; - dst[1] = src[1]; - } - - /* create ctrblks for parallel encrypt */ - u128_to_be128(&ctrblocks[0], &ctrblk); - u128_inc(&ctrblk); - u128_to_be128(&ctrblocks[1], &ctrblk); - u128_inc(&ctrblk); - - camellia_enc_blk_xor_2way(ctx, (u8 *)dst, - (u8 *)ctrblocks); - - src += 2; - dst += 2; - nbytes -= bsize * 2; - } while (nbytes >= bsize * 2); - - if (nbytes < bsize) - goto done; - } - - /* Handle leftovers */ - do { - if (dst != src) - *dst = *src; - - u128_to_be128(&ctrblocks[0], &ctrblk); - u128_inc(&ctrblk); - - camellia_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks); - - src += 1; - dst += 1; - nbytes -= bsize; - } while (nbytes >= bsize); - -done: - u128_to_be128((be128 *)walk->iv, &ctrblk); - return nbytes; -} - -static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct blkcipher_walk walk; - int err; - - blkcipher_walk_init(&walk, dst, src, nbytes); - err = blkcipher_walk_virt_block(desc, &walk, CAMELLIA_BLOCK_SIZE); - - while ((nbytes = walk.nbytes) >= CAMELLIA_BLOCK_SIZE) { - nbytes = __ctr_crypt(desc, &walk); - err = blkcipher_walk_done(desc, &walk, nbytes); - } - - if (walk.nbytes) { - ctr_crypt_final(desc, &walk); - err = blkcipher_walk_done(desc, &walk, 0); - } - - return err; -} - -static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) -{ - const unsigned int bsize = CAMELLIA_BLOCK_SIZE; - struct camellia_ctx *ctx = priv; - int i; - - while (nbytes >= 2 * bsize) { - camellia_enc_blk_2way(ctx, srcdst, srcdst); - srcdst += bsize * 2; - nbytes -= bsize * 2; - } - - for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) - camellia_enc_blk(ctx, srcdst, srcdst); -} - -static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) -{ - const unsigned int bsize = CAMELLIA_BLOCK_SIZE; - struct camellia_ctx *ctx = priv; - int i; - - while (nbytes >= 2 * bsize) { - camellia_dec_blk_2way(ctx, srcdst, srcdst); - srcdst += bsize * 2; - nbytes -= bsize * 2; - } - - for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) - camellia_dec_blk(ctx, srcdst, srcdst); -} - -struct camellia_lrw_ctx { - struct lrw_table_ctx lrw_table; - struct camellia_ctx camellia_ctx; -}; - -static int lrw_camellia_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) -{ - struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm); - int err; - - err = __camellia_setkey(&ctx->camellia_ctx, key, - keylen - CAMELLIA_BLOCK_SIZE, - &tfm->crt_flags); - if (err) - return err; - - return lrw_init_table(&ctx->lrw_table, - key + keylen - CAMELLIA_BLOCK_SIZE); -} - -static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); - be128 buf[2 * 4]; - struct lrw_crypt_req req = { - .tbuf = buf, - .tbuflen = sizeof(buf), - - .table_ctx = &ctx->lrw_table, - .crypt_ctx = &ctx->camellia_ctx, - .crypt_fn = encrypt_callback, - }; - - return lrw_crypt(desc, dst, src, nbytes, &req); -} - -static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct camellia_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); - be128 buf[2 * 4]; - struct lrw_crypt_req req = { - .tbuf = buf, - .tbuflen = sizeof(buf), - - .table_ctx = &ctx->lrw_table, - .crypt_ctx = &ctx->camellia_ctx, - .crypt_fn = decrypt_callback, - }; - - return lrw_crypt(desc, dst, src, nbytes, &req); -} - -static void lrw_exit_tfm(struct crypto_tfm *tfm) -{ - struct camellia_lrw_ctx *ctx = crypto_tfm_ctx(tfm); - - lrw_free_table(&ctx->lrw_table); -} - -struct camellia_xts_ctx { - struct camellia_ctx tweak_ctx; - struct camellia_ctx crypt_ctx; -}; - -static int xts_camellia_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) -{ - struct camellia_xts_ctx *ctx = crypto_tfm_ctx(tfm); - u32 *flags = &tfm->crt_flags; - int err; - - /* key consists of keys of equal size concatenated, therefore - * the length must be even - */ - if (keylen % 2) { - *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; - } - - /* first half of xts-key is for crypt */ - err = __camellia_setkey(&ctx->crypt_ctx, key, keylen / 2, flags); - if (err) - return err; - - /* second half of xts-key is for tweak */ - return __camellia_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2, - flags); -} - -static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); - be128 buf[2 * 4]; - struct xts_crypt_req req = { - .tbuf = buf, - .tbuflen = sizeof(buf), - - .tweak_ctx = &ctx->tweak_ctx, - .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk), - .crypt_ctx = &ctx->crypt_ctx, - .crypt_fn = encrypt_callback, - }; - - return xts_crypt(desc, dst, src, nbytes, &req); -} - -static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct camellia_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); - be128 buf[2 * 4]; - struct xts_crypt_req req = { - .tbuf = buf, - .tbuflen = sizeof(buf), - - .tweak_ctx = &ctx->tweak_ctx, - .tweak_fn = XTS_TWEAK_CAST(camellia_enc_blk), - .crypt_ctx = &ctx->crypt_ctx, - .crypt_fn = decrypt_callback, - }; - - return xts_crypt(desc, dst, src, nbytes, &req); -} - -static struct crypto_alg camellia_algs[6] = { { - .cra_name = "camellia", - .cra_driver_name = "camellia-asm", - .cra_priority = 200, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = CAMELLIA_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct camellia_ctx), - .cra_alignmask = 0, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[0].cra_list), - .cra_u = { - .cipher = { - .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, - .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE, - .cia_setkey = camellia_setkey, - .cia_encrypt = camellia_encrypt, - .cia_decrypt = camellia_decrypt - } - } -}, { - .cra_name = "ecb(camellia)", - .cra_driver_name = "ecb-camellia-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = CAMELLIA_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct camellia_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[1].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = CAMELLIA_MIN_KEY_SIZE, - .max_keysize = CAMELLIA_MAX_KEY_SIZE, - .setkey = camellia_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}, { - .cra_name = "cbc(camellia)", - .cra_driver_name = "cbc-camellia-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = CAMELLIA_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct camellia_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[2].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = CAMELLIA_MIN_KEY_SIZE, - .max_keysize = CAMELLIA_MAX_KEY_SIZE, - .ivsize = CAMELLIA_BLOCK_SIZE, - .setkey = camellia_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}, { - .cra_name = "ctr(camellia)", - .cra_driver_name = "ctr-camellia-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct camellia_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[3].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = CAMELLIA_MIN_KEY_SIZE, - .max_keysize = CAMELLIA_MAX_KEY_SIZE, - .ivsize = CAMELLIA_BLOCK_SIZE, - .setkey = camellia_setkey, - .encrypt = ctr_crypt, - .decrypt = ctr_crypt, - }, - }, -}, { - .cra_name = "lrw(camellia)", - .cra_driver_name = "lrw-camellia-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = CAMELLIA_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct camellia_lrw_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[4].cra_list), - .cra_exit = lrw_exit_tfm, - .cra_u = { - .blkcipher = { - .min_keysize = CAMELLIA_MIN_KEY_SIZE + - CAMELLIA_BLOCK_SIZE, - .max_keysize = CAMELLIA_MAX_KEY_SIZE + - CAMELLIA_BLOCK_SIZE, - .ivsize = CAMELLIA_BLOCK_SIZE, - .setkey = lrw_camellia_setkey, - .encrypt = lrw_encrypt, - .decrypt = lrw_decrypt, - }, - }, -}, { - .cra_name = "xts(camellia)", - .cra_driver_name = "xts-camellia-asm", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = CAMELLIA_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct camellia_xts_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(camellia_algs[5].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = CAMELLIA_MIN_KEY_SIZE * 2, - .max_keysize = CAMELLIA_MAX_KEY_SIZE * 2, - .ivsize = CAMELLIA_BLOCK_SIZE, - .setkey = xts_camellia_setkey, - .encrypt = xts_encrypt, - .decrypt = xts_decrypt, - }, - }, -} }; - -static bool is_blacklisted_cpu(void) -{ - if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) - return false; - - if (boot_cpu_data.x86 == 0x0f) { - /* - * On Pentium 4, camellia-asm is slower than original assembler - * implementation because excessive uses of 64bit rotate and - * left-shifts (which are really slow on P4) needed to store and - * handle 128bit block in two 64bit registers. - */ - return true; - } - - return false; -} - -static int force; -module_param(force, int, 0); -MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); - -int __init init(void) -{ - if (!force && is_blacklisted_cpu()) { - printk(KERN_INFO - "camellia-x86_64: performance on this CPU " - "would be suboptimal: disabling " - "camellia-x86_64.\n"); - return -ENODEV; - } - - return crypto_register_algs(camellia_algs, ARRAY_SIZE(camellia_algs)); -} - -void __exit fini(void) -{ - crypto_unregister_algs(camellia_algs, ARRAY_SIZE(camellia_algs)); -} - -module_init(init); -module_exit(fini); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Camellia Cipher Algorithm, asm optimized"); -MODULE_ALIAS("camellia"); -MODULE_ALIAS("camellia-asm"); diff --git a/trunk/arch/x86/crypto/serpent-sse2-i586-asm_32.S b/trunk/arch/x86/crypto/serpent-sse2-i586-asm_32.S index c00053d42f99..4e37677ca851 100644 --- a/trunk/arch/x86/crypto/serpent-sse2-i586-asm_32.S +++ b/trunk/arch/x86/crypto/serpent-sse2-i586-asm_32.S @@ -463,20 +463,23 @@ pand x0, x4; \ pxor x2, x4; -#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ +#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ + movdqa x2, t3; \ + movdqa x0, t1; \ + unpcklps x3, t3; \ movdqa x0, t2; \ - punpckldq x1, x0; \ - punpckhdq x1, t2; \ - movdqa x2, t1; \ - punpckhdq x3, x2; \ - punpckldq x3, t1; \ - movdqa x0, x1; \ - punpcklqdq t1, x0; \ - punpckhqdq t1, x1; \ - movdqa t2, x3; \ - punpcklqdq x2, t2; \ - punpckhqdq x2, x3; \ - movdqa t2, x2; + unpcklps x1, t1; \ + unpckhps x1, t2; \ + movdqa t3, x1; \ + unpckhps x3, x2; \ + movdqa t1, x0; \ + movhlps t1, x1; \ + movdqa t2, t1; \ + movlhps t3, x0; \ + movlhps x2, t1; \ + movhlps t2, x2; \ + movdqa x2, x3; \ + movdqa t1, x2; #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \ movdqu (0*4*4)(in), x0; \ diff --git a/trunk/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S b/trunk/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S index 3ee1ff04d3e9..7f24a1540821 100644 --- a/trunk/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S +++ b/trunk/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S @@ -585,20 +585,23 @@ get_key(i, 1, RK1); \ SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \ -#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ +#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ + movdqa x2, t3; \ + movdqa x0, t1; \ + unpcklps x3, t3; \ movdqa x0, t2; \ - punpckldq x1, x0; \ - punpckhdq x1, t2; \ - movdqa x2, t1; \ - punpckhdq x3, x2; \ - punpckldq x3, t1; \ - movdqa x0, x1; \ - punpcklqdq t1, x0; \ - punpckhqdq t1, x1; \ - movdqa t2, x3; \ - punpcklqdq x2, t2; \ - punpckhqdq x2, x3; \ - movdqa t2, x2; + unpcklps x1, t1; \ + unpckhps x1, t2; \ + movdqa t3, x1; \ + unpckhps x3, x2; \ + movdqa t1, x0; \ + movhlps t1, x1; \ + movdqa t2, t1; \ + movlhps t3, x0; \ + movlhps x2, t1; \ + movhlps t2, x2; \ + movdqa x2, x3; \ + movdqa t1, x2; #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \ movdqu (0*4*4)(in), x0; \ diff --git a/trunk/arch/x86/crypto/serpent_sse2_glue.c b/trunk/arch/x86/crypto/serpent_sse2_glue.c index 4b21be85e0a1..7955a9b76b91 100644 --- a/trunk/arch/x86/crypto/serpent_sse2_glue.c +++ b/trunk/arch/x86/crypto/serpent_sse2_glue.c @@ -145,6 +145,28 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ecb_crypt(desc, &walk, false); } +static struct crypto_alg blk_ecb_alg = { + .cra_name = "__ecb-serpent-sse2", + .cra_driver_name = "__driver-ecb-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE, + .setkey = serpent_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}; + static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { @@ -273,6 +295,28 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } +static struct crypto_alg blk_cbc_alg = { + .cra_name = "__cbc-serpent-sse2", + .cra_driver_name = "__driver-cbc-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE, + .setkey = serpent_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}; + static inline void u128_to_be128(be128 *dst, const u128 *src) { dst->a = cpu_to_be64(src->a); @@ -395,6 +439,29 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } +static struct crypto_alg blk_ctr_alg = { + .cra_name = "__ctr-serpent-sse2", + .cra_driver_name = "__driver-ctr-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct serpent_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE, + .ivsize = SERPENT_BLOCK_SIZE, + .setkey = serpent_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}; + struct crypt_priv { struct serpent_ctx *ctx; bool fpu_enabled; @@ -513,6 +580,32 @@ static void lrw_exit_tfm(struct crypto_tfm *tfm) lrw_free_table(&ctx->lrw_table); } +static struct crypto_alg blk_lrw_alg = { + .cra_name = "__lrw-serpent-sse2", + .cra_driver_name = "__driver-lrw-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_lrw_alg.cra_list), + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE + + SERPENT_BLOCK_SIZE, + .max_keysize = SERPENT_MAX_KEY_SIZE + + SERPENT_BLOCK_SIZE, + .ivsize = SERPENT_BLOCK_SIZE, + .setkey = lrw_serpent_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}; + struct serpent_xts_ctx { struct serpent_ctx tweak_ctx; struct serpent_ctx crypt_ctx; @@ -596,6 +689,29 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ret; } +static struct crypto_alg blk_xts_alg = { + .cra_name = "__xts-serpent-sse2", + .cra_driver_name = "__driver-xts-serpent-sse2", + .cra_priority = 0, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = SERPENT_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct serpent_xts_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = SERPENT_MIN_KEY_SIZE * 2, + .max_keysize = SERPENT_MAX_KEY_SIZE * 2, + .ivsize = SERPENT_BLOCK_SIZE, + .setkey = xts_serpent_setkey, + .encrypt = xts_encrypt, + .decrypt = xts_decrypt, + }, + }, +}; + static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, unsigned int key_len) { @@ -676,133 +792,28 @@ static void ablk_exit(struct crypto_tfm *tfm) cryptd_free_ablkcipher(ctx->cryptd_tfm); } -static int ablk_init(struct crypto_tfm *tfm) +static void ablk_init_common(struct crypto_tfm *tfm, + struct cryptd_ablkcipher *cryptd_tfm) { struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); - struct cryptd_ablkcipher *cryptd_tfm; - char drv_name[CRYPTO_MAX_ALG_NAME]; - - snprintf(drv_name, sizeof(drv_name), "__driver-%s", - crypto_tfm_alg_driver_name(tfm)); - - cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0); - if (IS_ERR(cryptd_tfm)) - return PTR_ERR(cryptd_tfm); ctx->cryptd_tfm = cryptd_tfm; tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) + crypto_ablkcipher_reqsize(&cryptd_tfm->base); +} + +static int ablk_ecb_init(struct crypto_tfm *tfm) +{ + struct cryptd_ablkcipher *cryptd_tfm; + cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-serpent-sse2", 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ablk_init_common(tfm, cryptd_tfm); return 0; } -static struct crypto_alg serpent_algs[10] = { { - .cra_name = "__ecb-serpent-sse2", - .cra_driver_name = "__driver-ecb-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[0].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE, - .setkey = serpent_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}, { - .cra_name = "__cbc-serpent-sse2", - .cra_driver_name = "__driver-cbc-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[1].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE, - .setkey = serpent_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}, { - .cra_name = "__ctr-serpent-sse2", - .cra_driver_name = "__driver-ctr-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct serpent_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[2].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE, - .ivsize = SERPENT_BLOCK_SIZE, - .setkey = serpent_setkey, - .encrypt = ctr_crypt, - .decrypt = ctr_crypt, - }, - }, -}, { - .cra_name = "__lrw-serpent-sse2", - .cra_driver_name = "__driver-lrw-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_lrw_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[3].cra_list), - .cra_exit = lrw_exit_tfm, - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE + - SERPENT_BLOCK_SIZE, - .max_keysize = SERPENT_MAX_KEY_SIZE + - SERPENT_BLOCK_SIZE, - .ivsize = SERPENT_BLOCK_SIZE, - .setkey = lrw_serpent_setkey, - .encrypt = lrw_encrypt, - .decrypt = lrw_decrypt, - }, - }, -}, { - .cra_name = "__xts-serpent-sse2", - .cra_driver_name = "__driver-xts-serpent-sse2", - .cra_priority = 0, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = SERPENT_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct serpent_xts_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[4].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = SERPENT_MIN_KEY_SIZE * 2, - .max_keysize = SERPENT_MAX_KEY_SIZE * 2, - .ivsize = SERPENT_BLOCK_SIZE, - .setkey = xts_serpent_setkey, - .encrypt = xts_encrypt, - .decrypt = xts_decrypt, - }, - }, -}, { +static struct crypto_alg ablk_ecb_alg = { .cra_name = "ecb(serpent)", .cra_driver_name = "ecb-serpent-sse2", .cra_priority = 400, @@ -812,8 +823,8 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), - .cra_init = ablk_init, + .cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list), + .cra_init = ablk_ecb_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -824,7 +835,20 @@ static struct crypto_alg serpent_algs[10] = { { .decrypt = ablk_decrypt, }, }, -}, { +}; + +static int ablk_cbc_init(struct crypto_tfm *tfm) +{ + struct cryptd_ablkcipher *cryptd_tfm; + + cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-serpent-sse2", 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ablk_init_common(tfm, cryptd_tfm); + return 0; +} + +static struct crypto_alg ablk_cbc_alg = { .cra_name = "cbc(serpent)", .cra_driver_name = "cbc-serpent-sse2", .cra_priority = 400, @@ -834,8 +858,8 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), - .cra_init = ablk_init, + .cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list), + .cra_init = ablk_cbc_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -847,7 +871,20 @@ static struct crypto_alg serpent_algs[10] = { { .decrypt = ablk_decrypt, }, }, -}, { +}; + +static int ablk_ctr_init(struct crypto_tfm *tfm) +{ + struct cryptd_ablkcipher *cryptd_tfm; + + cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-serpent-sse2", 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ablk_init_common(tfm, cryptd_tfm); + return 0; +} + +static struct crypto_alg ablk_ctr_alg = { .cra_name = "ctr(serpent)", .cra_driver_name = "ctr-serpent-sse2", .cra_priority = 400, @@ -857,8 +894,8 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), - .cra_init = ablk_init, + .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list), + .cra_init = ablk_ctr_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -871,7 +908,20 @@ static struct crypto_alg serpent_algs[10] = { { .geniv = "chainiv", }, }, -}, { +}; + +static int ablk_lrw_init(struct crypto_tfm *tfm) +{ + struct cryptd_ablkcipher *cryptd_tfm; + + cryptd_tfm = cryptd_alloc_ablkcipher("__driver-lrw-serpent-sse2", 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ablk_init_common(tfm, cryptd_tfm); + return 0; +} + +static struct crypto_alg ablk_lrw_alg = { .cra_name = "lrw(serpent)", .cra_driver_name = "lrw-serpent-sse2", .cra_priority = 400, @@ -881,8 +931,8 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), - .cra_init = ablk_init, + .cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list), + .cra_init = ablk_lrw_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -896,7 +946,20 @@ static struct crypto_alg serpent_algs[10] = { { .decrypt = ablk_decrypt, }, }, -}, { +}; + +static int ablk_xts_init(struct crypto_tfm *tfm) +{ + struct cryptd_ablkcipher *cryptd_tfm; + + cryptd_tfm = cryptd_alloc_ablkcipher("__driver-xts-serpent-sse2", 0, 0); + if (IS_ERR(cryptd_tfm)) + return PTR_ERR(cryptd_tfm); + ablk_init_common(tfm, cryptd_tfm); + return 0; +} + +static struct crypto_alg ablk_xts_alg = { .cra_name = "xts(serpent)", .cra_driver_name = "xts-serpent-sse2", .cra_priority = 400, @@ -906,8 +969,8 @@ static struct crypto_alg serpent_algs[10] = { { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), - .cra_init = ablk_init, + .cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list), + .cra_init = ablk_xts_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -919,21 +982,84 @@ static struct crypto_alg serpent_algs[10] = { { .decrypt = ablk_decrypt, }, }, -} }; +}; static int __init serpent_sse2_init(void) { + int err; + if (!cpu_has_xmm2) { printk(KERN_INFO "SSE2 instructions are not detected.\n"); return -ENODEV; } - return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); + err = crypto_register_alg(&blk_ecb_alg); + if (err) + goto blk_ecb_err; + err = crypto_register_alg(&blk_cbc_alg); + if (err) + goto blk_cbc_err; + err = crypto_register_alg(&blk_ctr_alg); + if (err) + goto blk_ctr_err; + err = crypto_register_alg(&ablk_ecb_alg); + if (err) + goto ablk_ecb_err; + err = crypto_register_alg(&ablk_cbc_alg); + if (err) + goto ablk_cbc_err; + err = crypto_register_alg(&ablk_ctr_alg); + if (err) + goto ablk_ctr_err; + err = crypto_register_alg(&blk_lrw_alg); + if (err) + goto blk_lrw_err; + err = crypto_register_alg(&ablk_lrw_alg); + if (err) + goto ablk_lrw_err; + err = crypto_register_alg(&blk_xts_alg); + if (err) + goto blk_xts_err; + err = crypto_register_alg(&ablk_xts_alg); + if (err) + goto ablk_xts_err; + return err; + + crypto_unregister_alg(&ablk_xts_alg); +ablk_xts_err: + crypto_unregister_alg(&blk_xts_alg); +blk_xts_err: + crypto_unregister_alg(&ablk_lrw_alg); +ablk_lrw_err: + crypto_unregister_alg(&blk_lrw_alg); +blk_lrw_err: + crypto_unregister_alg(&ablk_ctr_alg); +ablk_ctr_err: + crypto_unregister_alg(&ablk_cbc_alg); +ablk_cbc_err: + crypto_unregister_alg(&ablk_ecb_alg); +ablk_ecb_err: + crypto_unregister_alg(&blk_ctr_alg); +blk_ctr_err: + crypto_unregister_alg(&blk_cbc_alg); +blk_cbc_err: + crypto_unregister_alg(&blk_ecb_alg); +blk_ecb_err: + return err; } static void __exit serpent_sse2_exit(void) { - crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); + crypto_unregister_alg(&ablk_xts_alg); + crypto_unregister_alg(&blk_xts_alg); + crypto_unregister_alg(&ablk_lrw_alg); + crypto_unregister_alg(&blk_lrw_alg); + crypto_unregister_alg(&ablk_ctr_alg); + crypto_unregister_alg(&ablk_cbc_alg); + crypto_unregister_alg(&ablk_ecb_alg); + crypto_unregister_alg(&blk_ctr_alg); + crypto_unregister_alg(&blk_cbc_alg); + crypto_unregister_alg(&blk_ecb_alg); } module_init(serpent_sse2_init); diff --git a/trunk/arch/x86/crypto/twofish_glue.c b/trunk/arch/x86/crypto/twofish_glue.c index 359ae084275c..dc6b3fb817fc 100644 --- a/trunk/arch/x86/crypto/twofish_glue.c +++ b/trunk/arch/x86/crypto/twofish_glue.c @@ -68,7 +68,7 @@ static struct crypto_alg alg = { .cra_flags = CRYPTO_ALG_TYPE_CIPHER, .cra_blocksize = TF_BLOCK_SIZE, .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, + .cra_alignmask = 3, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { diff --git a/trunk/arch/x86/crypto/twofish_glue_3way.c b/trunk/arch/x86/crypto/twofish_glue_3way.c index 408fc0c5814e..7fee8c152f93 100644 --- a/trunk/arch/x86/crypto/twofish_glue_3way.c +++ b/trunk/arch/x86/crypto/twofish_glue_3way.c @@ -25,7 +25,6 @@ * */ -#include #include #include #include @@ -123,6 +122,28 @@ static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return ecb_crypt(desc, &walk, twofish_dec_blk, twofish_dec_blk_3way); } +static struct crypto_alg blk_ecb_alg = { + .cra_name = "ecb(twofish)", + .cra_driver_name = "ecb-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE, + .max_keysize = TF_MAX_KEY_SIZE, + .setkey = twofish_setkey, + .encrypt = ecb_encrypt, + .decrypt = ecb_decrypt, + }, + }, +}; + static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk) { @@ -246,6 +267,29 @@ static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } +static struct crypto_alg blk_cbc_alg = { + .cra_name = "cbc(twofish)", + .cra_driver_name = "cbc-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE, + .max_keysize = TF_MAX_KEY_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = twofish_setkey, + .encrypt = cbc_encrypt, + .decrypt = cbc_decrypt, + }, + }, +}; + static inline void u128_to_be128(be128 *dst, const u128 *src) { dst->a = cpu_to_be64(src->a); @@ -367,6 +411,29 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } +static struct crypto_alg blk_ctr_alg = { + .cra_name = "ctr(twofish)", + .cra_driver_name = "ctr-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct twofish_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE, + .max_keysize = TF_MAX_KEY_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = twofish_setkey, + .encrypt = ctr_crypt, + .decrypt = ctr_crypt, + }, + }, +}; + static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) { const unsigned int bsize = TF_BLOCK_SIZE; @@ -457,6 +524,30 @@ static void lrw_exit_tfm(struct crypto_tfm *tfm) lrw_free_table(&ctx->lrw_table); } +static struct crypto_alg blk_lrw_alg = { + .cra_name = "lrw(twofish)", + .cra_driver_name = "lrw-twofish-3way", + .cra_priority = 300, + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_blocksize = TF_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct twofish_lrw_ctx), + .cra_alignmask = 0, + .cra_type = &crypto_blkcipher_type, + .cra_module = THIS_MODULE, + .cra_list = LIST_HEAD_INIT(blk_lrw_alg.cra_list), + .cra_exit = lrw_exit_tfm, + .cra_u = { + .blkcipher = { + .min_keysize = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE, + .max_keysize = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE, + .ivsize = TF_BLOCK_SIZE, + .setkey = lrw_twofish_setkey, + .encrypt = lrw_encrypt, + .decrypt = lrw_decrypt, + }, + }, +}; + struct twofish_xts_ctx { struct twofish_ctx tweak_ctx; struct twofish_ctx crypt_ctx; @@ -523,91 +614,7 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return xts_crypt(desc, dst, src, nbytes, &req); } -static struct crypto_alg tf_algs[5] = { { - .cra_name = "ecb(twofish)", - .cra_driver_name = "ecb-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[0].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE, - .max_keysize = TF_MAX_KEY_SIZE, - .setkey = twofish_setkey, - .encrypt = ecb_encrypt, - .decrypt = ecb_decrypt, - }, - }, -}, { - .cra_name = "cbc(twofish)", - .cra_driver_name = "cbc-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[1].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE, - .max_keysize = TF_MAX_KEY_SIZE, - .ivsize = TF_BLOCK_SIZE, - .setkey = twofish_setkey, - .encrypt = cbc_encrypt, - .decrypt = cbc_decrypt, - }, - }, -}, { - .cra_name = "ctr(twofish)", - .cra_driver_name = "ctr-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = 1, - .cra_ctxsize = sizeof(struct twofish_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[2].cra_list), - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE, - .max_keysize = TF_MAX_KEY_SIZE, - .ivsize = TF_BLOCK_SIZE, - .setkey = twofish_setkey, - .encrypt = ctr_crypt, - .decrypt = ctr_crypt, - }, - }, -}, { - .cra_name = "lrw(twofish)", - .cra_driver_name = "lrw-twofish-3way", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = TF_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct twofish_lrw_ctx), - .cra_alignmask = 0, - .cra_type = &crypto_blkcipher_type, - .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[3].cra_list), - .cra_exit = lrw_exit_tfm, - .cra_u = { - .blkcipher = { - .min_keysize = TF_MIN_KEY_SIZE + TF_BLOCK_SIZE, - .max_keysize = TF_MAX_KEY_SIZE + TF_BLOCK_SIZE, - .ivsize = TF_BLOCK_SIZE, - .setkey = lrw_twofish_setkey, - .encrypt = lrw_encrypt, - .decrypt = lrw_decrypt, - }, - }, -}, { +static struct crypto_alg blk_xts_alg = { .cra_name = "xts(twofish)", .cra_driver_name = "xts-twofish-3way", .cra_priority = 300, @@ -617,7 +624,7 @@ static struct crypto_alg tf_algs[5] = { { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(tf_algs[4].cra_list), + .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE * 2, @@ -628,62 +635,50 @@ static struct crypto_alg tf_algs[5] = { { .decrypt = xts_decrypt, }, }, -} }; - -static bool is_blacklisted_cpu(void) -{ - if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) - return false; - - if (boot_cpu_data.x86 == 0x06 && - (boot_cpu_data.x86_model == 0x1c || - boot_cpu_data.x86_model == 0x26 || - boot_cpu_data.x86_model == 0x36)) { - /* - * On Atom, twofish-3way is slower than original assembler - * implementation. Twofish-3way trades off some performance in - * storing blocks in 64bit registers to allow three blocks to - * be processed parallel. Parallel operation then allows gaining - * more performance than was trade off, on out-of-order CPUs. - * However Atom does not benefit from this parallellism and - * should be blacklisted. - */ - return true; - } - - if (boot_cpu_data.x86 == 0x0f) { - /* - * On Pentium 4, twofish-3way is slower than original assembler - * implementation because excessive uses of 64bit rotate and - * left-shifts (which are really slow on P4) needed to store and - * handle 128bit block in two 64bit registers. - */ - return true; - } - - return false; -} - -static int force; -module_param(force, int, 0); -MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); +}; int __init init(void) { - if (!force && is_blacklisted_cpu()) { - printk(KERN_INFO - "twofish-x86_64-3way: performance on this CPU " - "would be suboptimal: disabling " - "twofish-x86_64-3way.\n"); - return -ENODEV; - } + int err; - return crypto_register_algs(tf_algs, ARRAY_SIZE(tf_algs)); + err = crypto_register_alg(&blk_ecb_alg); + if (err) + goto ecb_err; + err = crypto_register_alg(&blk_cbc_alg); + if (err) + goto cbc_err; + err = crypto_register_alg(&blk_ctr_alg); + if (err) + goto ctr_err; + err = crypto_register_alg(&blk_lrw_alg); + if (err) + goto blk_lrw_err; + err = crypto_register_alg(&blk_xts_alg); + if (err) + goto blk_xts_err; + + return 0; + + crypto_unregister_alg(&blk_xts_alg); +blk_xts_err: + crypto_unregister_alg(&blk_lrw_alg); +blk_lrw_err: + crypto_unregister_alg(&blk_ctr_alg); +ctr_err: + crypto_unregister_alg(&blk_cbc_alg); +cbc_err: + crypto_unregister_alg(&blk_ecb_alg); +ecb_err: + return err; } void __exit fini(void) { - crypto_unregister_algs(tf_algs, ARRAY_SIZE(tf_algs)); + crypto_unregister_alg(&blk_xts_alg); + crypto_unregister_alg(&blk_lrw_alg); + crypto_unregister_alg(&blk_ctr_alg); + crypto_unregister_alg(&blk_cbc_alg); + crypto_unregister_alg(&blk_ecb_alg); } module_init(init); diff --git a/trunk/arch/x86/ia32/ia32_aout.c b/trunk/arch/x86/ia32/ia32_aout.c index 4c2e59a420b9..39e49091f648 100644 --- a/trunk/arch/x86/ia32/ia32_aout.c +++ b/trunk/arch/x86/ia32/ia32_aout.c @@ -323,6 +323,7 @@ static int load_aout_binary(struct linux_binprm *bprm, struct pt_regs *regs) } install_exec_creds(bprm); + current->flags &= ~PF_FORKNOEXEC; if (N_MAGIC(ex) == OMAGIC) { unsigned long text_addr, map_size; @@ -518,8 +519,7 @@ static int load_aout_library(struct file *file) static int __init init_aout_binfmt(void) { - register_binfmt(&aout_format); - return 0; + return register_binfmt(&aout_format); } static void __exit exit_aout_binfmt(void) diff --git a/trunk/arch/x86/kernel/vm86_32.c b/trunk/arch/x86/kernel/vm86_32.c index b466cab5ba15..328cb37bb827 100644 --- a/trunk/arch/x86/kernel/vm86_32.c +++ b/trunk/arch/x86/kernel/vm86_32.c @@ -172,6 +172,7 @@ static void mark_screen_rdonly(struct mm_struct *mm) spinlock_t *ptl; int i; + down_write(&mm->mmap_sem); pgd = pgd_offset(mm, 0xA0000); if (pgd_none_or_clear_bad(pgd)) goto out; @@ -190,6 +191,7 @@ static void mark_screen_rdonly(struct mm_struct *mm) } pte_unmap_unlock(pte, ptl); out: + up_write(&mm->mmap_sem); flush_tlb(); } diff --git a/trunk/crypto/Kconfig b/trunk/crypto/Kconfig index 6318edd6a457..e6cfe1a25137 100644 --- a/trunk/crypto/Kconfig +++ b/trunk/crypto/Kconfig @@ -654,24 +654,6 @@ config CRYPTO_CAMELLIA See also: -config CRYPTO_CAMELLIA_X86_64 - tristate "Camellia cipher algorithm (x86_64)" - depends on (X86 || UML_X86) && 64BIT - depends on CRYPTO - select CRYPTO_ALGAPI - select CRYPTO_LRW - select CRYPTO_XTS - help - Camellia cipher algorithm module (x86_64). - - Camellia is a symmetric key block cipher developed jointly - at NTT and Mitsubishi Electric Corporation. - - The Camellia specifies three key sizes: 128, 192 and 256 bits. - - See also: - - config CRYPTO_CAST5 tristate "CAST5 (CAST-128) cipher algorithm" select CRYPTO_ALGAPI diff --git a/trunk/crypto/Makefile b/trunk/crypto/Makefile index 30f33d675330..f638063f4ea9 100644 --- a/trunk/crypto/Makefile +++ b/trunk/crypto/Makefile @@ -67,7 +67,7 @@ obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o obj-$(CONFIG_CRYPTO_AES) += aes_generic.o -obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o +obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia.o obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o diff --git a/trunk/crypto/algapi.c b/trunk/crypto/algapi.c index 056571b85445..9d4a9fe913f8 100644 --- a/trunk/crypto/algapi.c +++ b/trunk/crypto/algapi.c @@ -405,41 +405,6 @@ int crypto_unregister_alg(struct crypto_alg *alg) } EXPORT_SYMBOL_GPL(crypto_unregister_alg); -int crypto_register_algs(struct crypto_alg *algs, int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = crypto_register_alg(&algs[i]); - if (ret) - goto err; - } - - return 0; - -err: - for (--i; i >= 0; --i) - crypto_unregister_alg(&algs[i]); - - return ret; -} -EXPORT_SYMBOL_GPL(crypto_register_algs); - -int crypto_unregister_algs(struct crypto_alg *algs, int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = crypto_unregister_alg(&algs[i]); - if (ret) - pr_err("Failed to unregister %s %s: %d\n", - algs[i].cra_driver_name, algs[i].cra_name, ret); - } - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_unregister_algs); - int crypto_register_template(struct crypto_template *tmpl) { struct crypto_template *q; diff --git a/trunk/crypto/camellia_generic.c b/trunk/crypto/camellia.c similarity index 94% rename from trunk/crypto/camellia_generic.c rename to trunk/crypto/camellia.c index f7aaaaf86982..64cff46ea5e4 100644 --- a/trunk/crypto/camellia_generic.c +++ b/trunk/crypto/camellia.c @@ -337,40 +337,43 @@ static const u32 camellia_sp4404[256] = { /* * macros */ -#define ROLDQ(ll, lr, rl, rr, w0, w1, bits) ({ \ +#define ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ + do { \ w0 = ll; \ ll = (ll << bits) + (lr >> (32 - bits)); \ lr = (lr << bits) + (rl >> (32 - bits)); \ rl = (rl << bits) + (rr >> (32 - bits)); \ rr = (rr << bits) + (w0 >> (32 - bits)); \ -}) + } while (0) -#define ROLDQo32(ll, lr, rl, rr, w0, w1, bits) ({ \ +#define ROLDQo32(ll, lr, rl, rr, w0, w1, bits) \ + do { \ w0 = ll; \ w1 = lr; \ ll = (lr << (bits - 32)) + (rl >> (64 - bits)); \ lr = (rl << (bits - 32)) + (rr >> (64 - bits)); \ rl = (rr << (bits - 32)) + (w0 >> (64 - bits)); \ rr = (w0 << (bits - 32)) + (w1 >> (64 - bits)); \ -}) + } while (0) -#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) ({ \ +#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) \ + do { \ il = xl ^ kl; \ ir = xr ^ kr; \ t0 = il >> 16; \ t1 = ir >> 16; \ - yl = camellia_sp1110[(u8)(ir)] \ - ^ camellia_sp0222[(u8)(t1 >> 8)] \ - ^ camellia_sp3033[(u8)(t1)] \ + yl = camellia_sp1110[(u8)(ir )] \ + ^ camellia_sp0222[ (t1 >> 8)] \ + ^ camellia_sp3033[(u8)(t1 )] \ ^ camellia_sp4404[(u8)(ir >> 8)]; \ - yr = camellia_sp1110[(u8)(t0 >> 8)] \ - ^ camellia_sp0222[(u8)(t0)] \ + yr = camellia_sp1110[ (t0 >> 8)] \ + ^ camellia_sp0222[(u8)(t0 )] \ ^ camellia_sp3033[(u8)(il >> 8)] \ - ^ camellia_sp4404[(u8)(il)]; \ + ^ camellia_sp4404[(u8)(il )]; \ yl ^= yr; \ yr = ror32(yr, 8); \ yr ^= yl; \ -}) + } while (0) #define SUBKEY_L(INDEX) (subkey[(INDEX)*2]) #define SUBKEY_R(INDEX) (subkey[(INDEX)*2 + 1]) @@ -379,6 +382,7 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) { u32 dw, tl, tr; u32 kw4l, kw4r; + int i; /* absorb kw2 to other subkeys */ /* round 2 */ @@ -553,6 +557,24 @@ static void camellia_setup_tail(u32 *subkey, u32 *subL, u32 *subR, int max) SUBKEY_L(32) = subL[32] ^ subL[31]; /* kw3 */ SUBKEY_R(32) = subR[32] ^ subR[31]; } + + /* apply the inverse of the last half of P-function */ + i = 2; + do { + dw = SUBKEY_L(i + 0) ^ SUBKEY_R(i + 0); dw = rol32(dw, 8);/* round 1 */ + SUBKEY_R(i + 0) = SUBKEY_L(i + 0) ^ dw; SUBKEY_L(i + 0) = dw; + dw = SUBKEY_L(i + 1) ^ SUBKEY_R(i + 1); dw = rol32(dw, 8);/* round 2 */ + SUBKEY_R(i + 1) = SUBKEY_L(i + 1) ^ dw; SUBKEY_L(i + 1) = dw; + dw = SUBKEY_L(i + 2) ^ SUBKEY_R(i + 2); dw = rol32(dw, 8);/* round 3 */ + SUBKEY_R(i + 2) = SUBKEY_L(i + 2) ^ dw; SUBKEY_L(i + 2) = dw; + dw = SUBKEY_L(i + 3) ^ SUBKEY_R(i + 3); dw = rol32(dw, 8);/* round 4 */ + SUBKEY_R(i + 3) = SUBKEY_L(i + 3) ^ dw; SUBKEY_L(i + 3) = dw; + dw = SUBKEY_L(i + 4) ^ SUBKEY_R(i + 4); dw = rol32(dw, 8);/* round 5 */ + SUBKEY_R(i + 4) = SUBKEY_L(i + 4) ^ dw; SUBKEY_L(i + 4) = dw; + dw = SUBKEY_L(i + 5) ^ SUBKEY_R(i + 5); dw = rol32(dw, 8);/* round 6 */ + SUBKEY_R(i + 5) = SUBKEY_L(i + 5) ^ dw; SUBKEY_L(i + 5) = dw; + i += 8; + } while (i < max); } static void camellia_setup128(const unsigned char *key, u32 *subkey) @@ -829,7 +851,8 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey) /* * Encrypt/decrypt */ -#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) ({ \ +#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) \ + do { \ t0 = kll; \ t2 = krr; \ t0 &= ll; \ @@ -842,23 +865,23 @@ static void camellia_setup192(const unsigned char *key, u32 *subkey) t1 |= lr; \ ll ^= t1; \ rr ^= rol32(t3, 1); \ -}) + } while (0) -#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir) ({ \ - yl ^= kl; \ - yr ^= kr; \ +#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir) \ + do { \ ir = camellia_sp1110[(u8)xr]; \ - il = camellia_sp1110[(u8)(xl >> 24)]; \ - ir ^= camellia_sp0222[(u8)(xr >> 24)]; \ + il = camellia_sp1110[ (xl >> 24)]; \ + ir ^= camellia_sp0222[ (xr >> 24)]; \ il ^= camellia_sp0222[(u8)(xl >> 16)]; \ ir ^= camellia_sp3033[(u8)(xr >> 16)]; \ il ^= camellia_sp3033[(u8)(xl >> 8)]; \ ir ^= camellia_sp4404[(u8)(xr >> 8)]; \ il ^= camellia_sp4404[(u8)xl]; \ - ir ^= il; \ + il ^= kl; \ + ir ^= il ^ kr; \ yl ^= ir; \ - yr ^= ror32(il, 8) ^ ir; \ -}) + yr ^= ror32(il, 8) ^ ir; \ + } while (0) /* max = 24: 128bit encrypt, max = 32: 256bit encrypt */ static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max) @@ -870,7 +893,7 @@ static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max) io[1] ^= SUBKEY_R(0); /* main iteration */ -#define ROUNDS(i) ({ \ +#define ROUNDS(i) do { \ CAMELLIA_ROUNDSM(io[0], io[1], \ SUBKEY_L(i + 2), SUBKEY_R(i + 2), \ io[2], io[3], il, ir); \ @@ -889,13 +912,13 @@ static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max) CAMELLIA_ROUNDSM(io[2], io[3], \ SUBKEY_L(i + 7), SUBKEY_R(i + 7), \ io[0], io[1], il, ir); \ -}) -#define FLS(i) ({ \ +} while (0) +#define FLS(i) do { \ CAMELLIA_FLS(io[0], io[1], io[2], io[3], \ SUBKEY_L(i + 0), SUBKEY_R(i + 0), \ SUBKEY_L(i + 1), SUBKEY_R(i + 1), \ t0, t1, il, ir); \ -}) +} while (0) ROUNDS(0); FLS(8); @@ -925,7 +948,7 @@ static void camellia_do_decrypt(const u32 *subkey, u32 *io, unsigned i) io[1] ^= SUBKEY_R(i); /* main iteration */ -#define ROUNDS(i) ({ \ +#define ROUNDS(i) do { \ CAMELLIA_ROUNDSM(io[0], io[1], \ SUBKEY_L(i + 7), SUBKEY_R(i + 7), \ io[2], io[3], il, ir); \ @@ -944,13 +967,13 @@ static void camellia_do_decrypt(const u32 *subkey, u32 *io, unsigned i) CAMELLIA_ROUNDSM(io[2], io[3], \ SUBKEY_L(i + 2), SUBKEY_R(i + 2), \ io[0], io[1], il, ir); \ -}) -#define FLS(i) ({ \ +} while (0) +#define FLS(i) do { \ CAMELLIA_FLS(io[0], io[1], io[2], io[3], \ SUBKEY_L(i + 1), SUBKEY_R(i + 1), \ SUBKEY_L(i + 0), SUBKEY_R(i + 0), \ t0, t1, il, ir); \ -}) +} while (0) if (i == 32) { ROUNDS(24); @@ -1012,7 +1035,6 @@ static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)in; __be32 *dst = (__be32 *)out; - unsigned int max; u32 tmp[4]; @@ -1021,12 +1043,9 @@ static void camellia_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) tmp[2] = be32_to_cpu(src[2]); tmp[3] = be32_to_cpu(src[3]); - if (cctx->key_length == 16) - max = 24; - else - max = 32; /* for key lengths of 24 and 32 */ - - camellia_do_encrypt(cctx->key_table, tmp, max); + camellia_do_encrypt(cctx->key_table, tmp, + cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */ + ); /* do_encrypt returns 0,1 swapped with 2,3 */ dst[0] = cpu_to_be32(tmp[2]); @@ -1040,7 +1059,6 @@ static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) const struct camellia_ctx *cctx = crypto_tfm_ctx(tfm); const __be32 *src = (const __be32 *)in; __be32 *dst = (__be32 *)out; - unsigned int max; u32 tmp[4]; @@ -1049,12 +1067,9 @@ static void camellia_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) tmp[2] = be32_to_cpu(src[2]); tmp[3] = be32_to_cpu(src[3]); - if (cctx->key_length == 16) - max = 24; - else - max = 32; /* for key lengths of 24 and 32 */ - - camellia_do_decrypt(cctx->key_table, tmp, max); + camellia_do_decrypt(cctx->key_table, tmp, + cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */ + ); /* do_decrypt returns 0,1 swapped with 2,3 */ dst[0] = cpu_to_be32(tmp[2]); @@ -1099,4 +1114,3 @@ module_exit(camellia_fini); MODULE_DESCRIPTION("Camellia Cipher Algorithm"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("camellia"); diff --git a/trunk/crypto/crypto_user.c b/trunk/crypto/crypto_user.c index f76e42bcc6e7..b6ac1387770c 100644 --- a/trunk/crypto/crypto_user.c +++ b/trunk/crypto/crypto_user.c @@ -304,7 +304,7 @@ static int crypto_del_alg(struct sk_buff *skb, struct nlmsghdr *nlh, static int crypto_add_alg(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { - int exact = 0; + int exact; const char *name; struct crypto_alg *alg; struct crypto_user_alg *p = nlmsg_data(nlh); diff --git a/trunk/crypto/tcrypt.c b/trunk/crypto/tcrypt.c index 8f147bff0980..7736a9f05aba 100644 --- a/trunk/crypto/tcrypt.c +++ b/trunk/crypto/tcrypt.c @@ -1297,18 +1297,6 @@ static int do_test(int m) speed_template_16_24_32); test_cipher_speed("cbc(camellia)", DECRYPT, sec, NULL, 0, speed_template_16_24_32); - test_cipher_speed("ctr(camellia)", ENCRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_cipher_speed("ctr(camellia)", DECRYPT, sec, NULL, 0, - speed_template_16_24_32); - test_cipher_speed("lrw(camellia)", ENCRYPT, sec, NULL, 0, - speed_template_32_40_48); - test_cipher_speed("lrw(camellia)", DECRYPT, sec, NULL, 0, - speed_template_32_40_48); - test_cipher_speed("xts(camellia)", ENCRYPT, sec, NULL, 0, - speed_template_32_48_64); - test_cipher_speed("xts(camellia)", DECRYPT, sec, NULL, 0, - speed_template_32_48_64); break; case 206: diff --git a/trunk/crypto/testmgr.c b/trunk/crypto/testmgr.c index 5674878ff6c1..bb54b882d738 100644 --- a/trunk/crypto/testmgr.c +++ b/trunk/crypto/testmgr.c @@ -1845,21 +1845,6 @@ static const struct alg_test_desc alg_test_descs[] = { } } } - }, { - .alg = "ctr(camellia)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = camellia_ctr_enc_tv_template, - .count = CAMELLIA_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = camellia_ctr_dec_tv_template, - .count = CAMELLIA_CTR_DEC_TEST_VECTORS - } - } - } }, { .alg = "ctr(serpent)", .test = alg_test_skcipher, @@ -2311,21 +2296,6 @@ static const struct alg_test_desc alg_test_descs[] = { } } } - }, { - .alg = "lrw(camellia)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = camellia_lrw_enc_tv_template, - .count = CAMELLIA_LRW_ENC_TEST_VECTORS - }, - .dec = { - .vecs = camellia_lrw_dec_tv_template, - .count = CAMELLIA_LRW_DEC_TEST_VECTORS - } - } - } }, { .alg = "lrw(serpent)", .test = alg_test_skcipher, @@ -2663,21 +2633,6 @@ static const struct alg_test_desc alg_test_descs[] = { } } } - }, { - .alg = "xts(camellia)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = camellia_xts_enc_tv_template, - .count = CAMELLIA_XTS_ENC_TEST_VECTORS - }, - .dec = { - .vecs = camellia_xts_dec_tv_template, - .count = CAMELLIA_XTS_DEC_TEST_VECTORS - } - } - } }, { .alg = "xts(serpent)", .test = alg_test_skcipher, diff --git a/trunk/crypto/testmgr.h b/trunk/crypto/testmgr.h index 36e5a8ee0e1e..43e84d32b341 100644 --- a/trunk/crypto/testmgr.h +++ b/trunk/crypto/testmgr.h @@ -11332,16 +11332,10 @@ static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = { /* * CAMELLIA test vectors. */ -#define CAMELLIA_ENC_TEST_VECTORS 4 -#define CAMELLIA_DEC_TEST_VECTORS 4 -#define CAMELLIA_CBC_ENC_TEST_VECTORS 3 -#define CAMELLIA_CBC_DEC_TEST_VECTORS 3 -#define CAMELLIA_CTR_ENC_TEST_VECTORS 2 -#define CAMELLIA_CTR_DEC_TEST_VECTORS 2 -#define CAMELLIA_LRW_ENC_TEST_VECTORS 8 -#define CAMELLIA_LRW_DEC_TEST_VECTORS 8 -#define CAMELLIA_XTS_ENC_TEST_VECTORS 5 -#define CAMELLIA_XTS_DEC_TEST_VECTORS 5 +#define CAMELLIA_ENC_TEST_VECTORS 3 +#define CAMELLIA_DEC_TEST_VECTORS 3 +#define CAMELLIA_CBC_ENC_TEST_VECTORS 2 +#define CAMELLIA_CBC_DEC_TEST_VECTORS 2 static struct cipher_testvec camellia_enc_tv_template[] = { { @@ -11378,27 +11372,6 @@ static struct cipher_testvec camellia_enc_tv_template[] = { "\x20\xef\x7c\x91\x9e\x3a\x75\x09", .rlen = 16, }, - { /* Generated with Crypto++ */ - .key = "\x3F\x85\x62\x3F\x1C\xF9\xD6\x1C" - "\xF9\xD6\xB3\x90\x6D\x4A\x90\x6D" - "\x4A\x27\x04\xE1\x27\x04\xE1\xBE" - "\x9B\x78\xBE\x9B\x78\x55\x32\x0F", - .klen = 32, - .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" - "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" - "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" - "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" - "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" - "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", - .ilen = 48, - .result = "\xED\xCD\xDB\xB8\x68\xCE\xBD\xEA" - "\x9D\x9D\xCD\x9F\x4F\xFC\x4D\xB7" - "\xA5\xFF\x6F\x43\x0F\xBA\x32\x04" - "\xB3\xC2\xB9\x03\xAA\x91\x56\x29" - "\x0D\xD0\xFD\xC4\x65\xA5\x69\xB9" - "\xF1\xF6\xB1\xA5\xB2\x75\x4F\x8A", - .rlen = 48, - }, }; static struct cipher_testvec camellia_dec_tv_template[] = { @@ -11436,27 +11409,6 @@ static struct cipher_testvec camellia_dec_tv_template[] = { "\xfe\xdc\xba\x98\x76\x54\x32\x10", .rlen = 16, }, - { /* Generated with Crypto++ */ - .key = "\x3F\x85\x62\x3F\x1C\xF9\xD6\x1C" - "\xF9\xD6\xB3\x90\x6D\x4A\x90\x6D" - "\x4A\x27\x04\xE1\x27\x04\xE1\xBE" - "\x9B\x78\xBE\x9B\x78\x55\x32\x0F", - .klen = 32, - .input = "\xED\xCD\xDB\xB8\x68\xCE\xBD\xEA" - "\x9D\x9D\xCD\x9F\x4F\xFC\x4D\xB7" - "\xA5\xFF\x6F\x43\x0F\xBA\x32\x04" - "\xB3\xC2\xB9\x03\xAA\x91\x56\x29" - "\x0D\xD0\xFD\xC4\x65\xA5\x69\xB9" - "\xF1\xF6\xB1\xA5\xB2\x75\x4F\x8A", - .ilen = 48, - .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" - "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" - "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" - "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" - "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" - "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", - .rlen = 48, - }, }; static struct cipher_testvec camellia_cbc_enc_tv_template[] = { @@ -11488,29 +11440,6 @@ static struct cipher_testvec camellia_cbc_enc_tv_template[] = { "\x15\x78\xe0\x5e\xf2\xcb\x87\x16", .rlen = 32, }, - { /* Generated with Crypto++ */ - .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" - "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" - "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" - "\x78\xBE\x9B\x78\x55\x32\x0F\x55", - .klen = 32, - .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" - "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", - .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" - "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" - "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" - "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" - "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" - "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", - .ilen = 48, - .result = "\xCD\x3E\x2A\x3B\x3E\x94\xC5\x77" - "\xBA\xBB\x5B\xB1\xDE\x7B\xA4\x40" - "\x88\x39\xE3\xFD\x94\x4B\x25\x58" - "\xE1\x4B\xC4\x18\x7A\xFD\x17\x2B" - "\xB9\xF9\xC2\x27\x6A\xB6\x31\x27" - "\xA6\xAD\xEF\xE5\x5D\xE4\x02\x01", - .rlen = 48, - }, }; static struct cipher_testvec camellia_cbc_dec_tv_template[] = { @@ -11542,1310 +11471,6 @@ static struct cipher_testvec camellia_cbc_dec_tv_template[] = { "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", .rlen = 32, }, - { /* Generated with Crypto++ */ - .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" - "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" - "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" - "\x78\xBE\x9B\x78\x55\x32\x0F\x55", - .klen = 32, - .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" - "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", - .input = "\xCD\x3E\x2A\x3B\x3E\x94\xC5\x77" - "\xBA\xBB\x5B\xB1\xDE\x7B\xA4\x40" - "\x88\x39\xE3\xFD\x94\x4B\x25\x58" - "\xE1\x4B\xC4\x18\x7A\xFD\x17\x2B" - "\xB9\xF9\xC2\x27\x6A\xB6\x31\x27" - "\xA6\xAD\xEF\xE5\x5D\xE4\x02\x01", - .ilen = 48, - .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" - "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" - "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" - "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" - "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" - "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", - .rlen = 48, - }, -}; - -static struct cipher_testvec camellia_ctr_enc_tv_template[] = { - { /* Generated with Crypto++ */ - .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" - "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" - "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" - "\x78\xBE\x9B\x78\x55\x32\x0F\x55", - .klen = 32, - .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" - "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", - .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" - "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" - "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" - "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" - "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" - "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", - .ilen = 48, - .result = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11" - "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE" - "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4" - "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6" - "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85" - "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C", - .rlen = 48, - }, - { /* Generated with Crypto++ */ - .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" - "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" - "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" - "\x78\xBE\x9B\x78\x55\x32\x0F\x55", - .klen = 32, - .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" - "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", - .input = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" - "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" - "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" - "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" - "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" - "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" - "\xDF\x76\x0D", - .ilen = 51, - .result = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11" - "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE" - "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4" - "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6" - "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85" - "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C" - "\x1E\x43\xEF", - .rlen = 51, - }, -}; - -static struct cipher_testvec camellia_ctr_dec_tv_template[] = { - { /* Generated with Crypto++ */ - .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" - "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" - "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" - "\x78\xBE\x9B\x78\x55\x32\x0F\x55", - .klen = 32, - .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" - "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", - .input = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11" - "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE" - "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4" - "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6" - "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85" - "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C", - .ilen = 48, - .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" - "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" - "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" - "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" - "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" - "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48", - .rlen = 48, - }, - { /* Generated with Crypto++ */ - .key = "\x85\x62\x3F\x1C\xF9\xD6\x1C\xF9" - "\xD6\xB3\x90\x6D\x4A\x90\x6D\x4A" - "\x27\x04\xE1\x27\x04\xE1\xBE\x9B" - "\x78\xBE\x9B\x78\x55\x32\x0F\x55", - .klen = 32, - .iv = "\xE2\x24\x89\xEE\x53\xB8\x1D\x5F" - "\xC4\x29\x8E\xF3\x35\x9A\xFF\x64", - .input = "\xF3\x06\x3A\x84\xCD\xBA\x8E\x11" - "\xB7\x74\x6F\x5C\x97\xFB\x36\xFE" - "\xDE\x71\x58\xD4\x15\xD1\xC1\xA4" - "\xC9\x28\x74\xA6\x6B\xC7\x95\xA6" - "\x6C\x77\xF7\x2F\xDF\xC7\xBB\x85" - "\x60\xFC\xE8\x94\xE8\xB5\x09\x2C" - "\x1E\x43\xEF", - .ilen = 51, - .result = "\x56\xED\x84\x1B\x8F\x26\xBD\x31" - "\xC8\x5F\xF6\x6A\x01\x98\x0C\xA3" - "\x3A\xD1\x45\xDC\x73\x0A\x7E\x15" - "\xAC\x20\xB7\x4E\xE5\x59\xF0\x87" - "\x1E\x92\x29\xC0\x34\xCB\x62\xF9" - "\x6D\x04\x9B\x0F\xA6\x3D\xD4\x48" - "\xDF\x76\x0D", - .rlen = 51, - }, - -}; - -static struct cipher_testvec camellia_lrw_enc_tv_template[] = { - /* Generated from AES-LRW test vectors */ - { - .key = "\x45\x62\xac\x25\xf8\x28\x17\x6d" - "\x4c\x26\x84\x14\xb5\x68\x01\x85" - "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03" - "\xee\x5a\x83\x0c\xcc\x09\x4c\x87", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x01", - .input = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .ilen = 16, - .result = "\x92\x68\x19\xd7\xb7\x5b\x0a\x31" - "\x97\xcc\x72\xbe\x99\x17\xeb\x3e", - .rlen = 16, - }, { - .key = "\x59\x70\x47\x14\xf5\x57\x47\x8c" - "\xd7\x79\xe8\x0f\x54\x88\x79\x44" - "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea" - "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x02", - .input = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .ilen = 16, - .result = "\x73\x09\xb7\x50\xb6\x77\x30\x50" - "\x5c\x8a\x9c\x26\x77\x9d\xfc\x4a", - .rlen = 16, - }, { - .key = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50" - "\x30\xfe\x69\xe2\x37\x7f\x98\x47" - "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6" - "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x02\x00\x00\x00\x00", - .input = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .ilen = 16, - .result = "\x90\xae\x83\xe0\x22\xb9\x60\x91" - "\xfa\xa9\xb7\x98\xe3\xed\x87\x01", - .rlen = 16, - }, { - .key = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15" - "\x25\x83\xf7\x3c\x1f\x01\x28\x74" - "\xca\xc6\xbc\x35\x4d\x4a\x65\x54" - "\x90\xae\x61\xcf\x7b\xae\xbd\xcc" - "\xad\xe4\x94\xc5\x4a\x29\xae\x70", - .klen = 40, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x01", - .input = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .ilen = 16, - .result = "\x99\xe9\x6e\xd4\xc9\x21\xa5\xf0" - "\xd8\x83\xef\xd9\x07\x16\x5f\x35", - .rlen = 16, - }, { - .key = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff" - "\xf8\x86\xce\xac\x93\xc5\xad\xc6" - "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd" - "\x52\x13\xb2\xb7\xf0\xff\x11\xd8" - "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f", - .klen = 40, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x02\x00\x00\x00\x00", - .input = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .ilen = 16, - .result = "\x42\x88\xf4\xcb\x21\x11\x6d\x8e" - "\xde\x1a\xf2\x29\xf1\x4a\xe0\x15", - .rlen = 16, - }, { - .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" - "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" - "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" - "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" - "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" - "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", - .klen = 48, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x01", - .input = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .ilen = 16, - .result = "\x40\xaa\x34\x86\x4a\x8f\x78\xb9" - "\xdb\xdb\x0f\x3d\x48\x70\xbe\x8d", - .rlen = 16, - }, { - .key = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d" - "\xd4\x70\x98\x0b\xc7\x95\x84\xc8" - "\xb2\xfb\x64\xce\x60\x97\x87\x8d" - "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7" - "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4" - "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c", - .klen = 48, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x02\x00\x00\x00\x00", - .input = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .ilen = 16, - .result = "\x04\xab\x28\x37\x31\x7a\x26\xab" - "\xa1\x70\x1b\x9c\xe7\xdd\x83\xff", - .rlen = 16, - }, { - .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" - "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" - "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" - "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" - "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" - "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", - .klen = 48, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x01", - .input = "\x05\x11\xb7\x18\xab\xc6\x2d\xac" - "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c" - "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8" - "\x50\x38\x1f\x71\x49\xb6\x57\xd6" - "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90" - "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6" - "\xad\x1e\x9e\x20\x5f\x38\xbe\x04" - "\xda\x10\x8e\xed\xa2\xa4\x87\xab" - "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c" - "\xc9\xac\x42\x31\x95\x7c\xc9\x04" - "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6" - "\x15\xd7\x3f\x4f\x2f\x66\x69\x03" - "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65" - "\x4c\x96\x12\xed\x7c\x92\x03\x01" - "\x6f\xbc\x35\x93\xac\xf1\x27\xf1" - "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50" - "\x89\xa4\x8e\x66\x44\x85\xcc\xfd" - "\x33\x14\x70\xe3\x96\xb2\xc3\xd3" - "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5" - "\x2d\x64\x75\xdd\xb4\x54\xe6\x74" - "\x8c\xd3\x9d\x9e\x86\xab\x51\x53" - "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40" - "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5" - "\x76\x12\x73\x44\x1a\x56\xd7\x72" - "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda" - "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd" - "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60" - "\x1a\xe2\x70\x85\x58\xc2\x1b\x09" - "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9" - "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8" - "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8" - "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10" - "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1" - "\x90\x3e\x76\x4a\x74\xa4\x21\x2c" - "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e" - "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f" - "\x8d\x23\x31\x74\x84\xeb\x88\x6e" - "\xcc\xb9\xbc\x22\x83\x19\x07\x22" - "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78" - "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5" - "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41" - "\x3c\xce\x8f\x42\x60\x71\xa7\x75" - "\x08\x40\x65\x8a\x82\xbf\xf5\x43" - "\x71\x96\xa9\x4d\x44\x8a\x20\xbe" - "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65" - "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9" - "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4" - "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a" - "\x62\x73\x65\xfd\x46\x63\x25\x3d" - "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf" - "\x24\xf3\xb4\xac\x64\xba\xdf\x4b" - "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7" - "\xc5\x68\x77\x84\x32\x2b\xcc\x85" - "\x74\x96\xf0\x12\x77\x61\xb9\xeb" - "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8" - "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24" - "\xda\x39\x87\x45\xc0\x2b\xbb\x01" - "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce" - "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6" - "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32" - "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45" - "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6" - "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" - "\x21\xc4\xc2\x75\x67\x89\x37\x0a", - .ilen = 512, - .result = "\x90\x69\x8e\xf2\x14\x86\x59\xf9" - "\xec\xe7\xfa\x3f\x48\x9d\x7f\x96" - "\x67\x76\xac\x2c\xd2\x63\x18\x93" - "\x13\xf8\xf1\xf6\x71\x77\xb3\xee" - "\x93\xb2\xcc\xf3\x26\xc1\x16\x4f" - "\xd4\xe8\x43\xc1\x68\xa3\x3e\x06" - "\x38\x51\xff\xa8\xb9\xa4\xeb\xb1" - "\x62\xdd\x78\x81\xea\x1d\xef\x04" - "\x1d\x07\xc1\x67\xc8\xd6\x77\xa1" - "\x84\x95\xf4\x9a\xd9\xbc\x2d\xe2" - "\xf6\x80\xfc\x91\x2a\xbc\x42\xa0" - "\x40\x41\x69\xaa\x71\xc0\x37\xec" - "\x39\xf3\xf2\xec\x82\xc3\x88\x79" - "\xbc\xc3\xaa\xb7\xcf\x6a\x72\x80" - "\x4c\xf4\x84\x8f\x13\x9e\x94\x5c" - "\xe5\xb2\x91\xbb\x92\x51\x4d\xf1" - "\xd6\x0d\x71\x6b\x7a\xc2\x2f\x12" - "\x6f\x75\xc7\x80\x99\x50\x84\xcf" - "\xa8\xeb\xd6\xe1\x1c\x59\x81\x7e" - "\xb9\xb3\xde\x7a\x93\x14\x12\xa2" - "\xf7\x43\xb3\x9d\x1a\x87\x65\x91" - "\x42\x08\x40\x82\x06\x1c\x2d\x55" - "\x6e\x48\xd5\x74\x07\x6e\x9d\x80" - "\xeb\xb4\x97\xa1\x36\xdf\xfa\x74" - "\x79\x7f\x5a\x75\xe7\x71\xc8\x8c" - "\x7e\xf8\x3a\x77\xcd\x32\x05\xf9" - "\x3d\xd4\xe9\xa2\xbb\xc4\x8b\x83" - "\x42\x5c\x82\xfa\xe9\x4b\x96\x3b" - "\x7f\x89\x8b\xf9\xf1\x87\xda\xf0" - "\x87\xef\x13\x5d\xf0\xe2\xc5\xc1" - "\xed\x14\xa9\x57\x19\x63\x40\x04" - "\x24\xeb\x6e\x19\xd1\x3d\x70\x78" - "\xeb\xda\x55\x70\x2c\x4f\x41\x5b" - "\x56\x9f\x1a\xd3\xac\xf1\xc0\xc3" - "\x21\xec\xd7\xd2\x55\x32\x7c\x2e" - "\x3c\x48\x8e\xb4\x85\x35\x47\xfe" - "\xe2\x88\x79\x98\x6a\xc9\x8d\xff" - "\xe9\x89\x6e\xb8\xe2\x97\x00\xbd" - "\xa4\x8f\xba\xd0\x8c\xcb\x79\x99" - "\xb3\xb2\xb2\x7a\xc3\xb7\xef\x75" - "\x23\x52\x76\xc3\x50\x6e\x66\xf8" - "\xa2\xe2\xce\xba\x40\x21\x3f\xc9" - "\x0a\x32\x7f\xf7\x08\x8c\x66\xcf" - "\xd3\xdf\x57\x59\x83\xb8\xe1\x85" - "\xd6\x8f\xfb\x48\x1f\x3a\xc4\x2f" - "\xb4\x2d\x58\xab\xd8\x7f\x5e\x3a" - "\xbc\x62\x3e\xe2\x6a\x52\x0d\x76" - "\x2f\x1c\x1a\x30\xed\x95\x2a\x44" - "\x35\xa5\x83\x04\x84\x01\x99\x56" - "\xb7\xe3\x10\x96\xfa\xdc\x19\xdd" - "\xe2\x7f\xcb\xa0\x49\x1b\xff\x4c" - "\x73\xf6\xbb\x94\x00\xe8\xa9\x3d" - "\xe2\x20\xe9\x3f\xfa\x07\x5d\x77" - "\x06\xd5\x4f\x4d\x02\xb8\x40\x1b" - "\x30\xed\x1a\x50\x19\xef\xc4\x2c" - "\x02\xd9\xc5\xd3\x11\x33\x37\xe5" - "\x2b\xa3\x95\xa6\xee\xd8\x74\x1d" - "\x68\xa0\xeb\xbf\xdd\x5e\x99\x96" - "\x91\xc3\x94\x24\xa5\x12\xa2\x37" - "\xb3\xac\xcf\x2a\xfd\x55\x34\xfe" - "\x79\x92\x3e\xe6\x1b\x49\x57\x5d" - "\x93\x6c\x01\xf7\xcc\x4e\x20\xd1" - "\xb2\x1a\xd8\x4c\xbd\x1d\x10\xe9" - "\x5a\xa8\x92\x7f\xba\xe6\x0c\x95", - .rlen = 512, - }, -}; - -static struct cipher_testvec camellia_lrw_dec_tv_template[] = { - /* Generated from AES-LRW test vectors */ - /* same as enc vectors with input and result reversed */ - { - .key = "\x45\x62\xac\x25\xf8\x28\x17\x6d" - "\x4c\x26\x84\x14\xb5\x68\x01\x85" - "\x25\x8e\x2a\x05\xe7\x3e\x9d\x03" - "\xee\x5a\x83\x0c\xcc\x09\x4c\x87", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x01", - .input = "\x92\x68\x19\xd7\xb7\x5b\x0a\x31" - "\x97\xcc\x72\xbe\x99\x17\xeb\x3e", - .ilen = 16, - .result = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .rlen = 16, - }, { - .key = "\x59\x70\x47\x14\xf5\x57\x47\x8c" - "\xd7\x79\xe8\x0f\x54\x88\x79\x44" - "\x0d\x48\xf0\xb7\xb1\x5a\x53\xea" - "\x1c\xaa\x6b\x29\xc2\xca\xfb\xaf", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x02", - .input = "\x73\x09\xb7\x50\xb6\x77\x30\x50" - "\x5c\x8a\x9c\x26\x77\x9d\xfc\x4a", - .ilen = 16, - .result = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .rlen = 16, - }, { - .key = "\xd8\x2a\x91\x34\xb2\x6a\x56\x50" - "\x30\xfe\x69\xe2\x37\x7f\x98\x47" - "\xcd\xf9\x0b\x16\x0c\x64\x8f\xb6" - "\xb0\x0d\x0d\x1b\xae\x85\x87\x1f", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x02\x00\x00\x00\x00", - .input = "\x90\xae\x83\xe0\x22\xb9\x60\x91" - "\xfa\xa9\xb7\x98\xe3\xed\x87\x01", - .ilen = 16, - .result = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .rlen = 16, - }, { - .key = "\x0f\x6a\xef\xf8\xd3\xd2\xbb\x15" - "\x25\x83\xf7\x3c\x1f\x01\x28\x74" - "\xca\xc6\xbc\x35\x4d\x4a\x65\x54" - "\x90\xae\x61\xcf\x7b\xae\xbd\xcc" - "\xad\xe4\x94\xc5\x4a\x29\xae\x70", - .klen = 40, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x01", - .input = "\x99\xe9\x6e\xd4\xc9\x21\xa5\xf0" - "\xd8\x83\xef\xd9\x07\x16\x5f\x35", - .ilen = 16, - .result = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .rlen = 16, - }, { - .key = "\x8a\xd4\xee\x10\x2f\xbd\x81\xff" - "\xf8\x86\xce\xac\x93\xc5\xad\xc6" - "\xa0\x19\x07\xc0\x9d\xf7\xbb\xdd" - "\x52\x13\xb2\xb7\xf0\xff\x11\xd8" - "\xd6\x08\xd0\xcd\x2e\xb1\x17\x6f", - .klen = 40, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x02\x00\x00\x00\x00", - .input = "\x42\x88\xf4\xcb\x21\x11\x6d\x8e" - "\xde\x1a\xf2\x29\xf1\x4a\xe0\x15", - .ilen = 16, - .result = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .rlen = 16, - }, { - .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" - "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" - "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" - "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" - "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" - "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", - .klen = 48, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x01", - .input = "\x40\xaa\x34\x86\x4a\x8f\x78\xb9" - "\xdb\xdb\x0f\x3d\x48\x70\xbe\x8d", - .ilen = 16, - .result = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .rlen = 16, - }, { - .key = "\xfb\x76\x15\xb2\x3d\x80\x89\x1d" - "\xd4\x70\x98\x0b\xc7\x95\x84\xc8" - "\xb2\xfb\x64\xce\x60\x97\x87\x8d" - "\x17\xfc\xe4\x5a\x49\xe8\x30\xb7" - "\x6e\x78\x17\xe7\x2d\x5e\x12\xd4" - "\x60\x64\x04\x7a\xf1\x2f\x9e\x0c", - .klen = 48, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x02\x00\x00\x00\x00", - .input = "\x04\xab\x28\x37\x31\x7a\x26\xab" - "\xa1\x70\x1b\x9c\xe7\xdd\x83\xff", - .ilen = 16, - .result = "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x41\x42\x43\x44\x45\x46", - .rlen = 16, - }, { - .key = "\xf8\xd4\x76\xff\xd6\x46\xee\x6c" - "\x23\x84\xcb\x1c\x77\xd6\x19\x5d" - "\xfe\xf1\xa9\xf3\x7b\xbc\x8d\x21" - "\xa7\x9c\x21\xf8\xcb\x90\x02\x89" - "\xa8\x45\x34\x8e\xc8\xc5\xb5\xf1" - "\x26\xf5\x0e\x76\xfe\xfd\x1b\x1e", - .klen = 48, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x01", - .input = "\x90\x69\x8e\xf2\x14\x86\x59\xf9" - "\xec\xe7\xfa\x3f\x48\x9d\x7f\x96" - "\x67\x76\xac\x2c\xd2\x63\x18\x93" - "\x13\xf8\xf1\xf6\x71\x77\xb3\xee" - "\x93\xb2\xcc\xf3\x26\xc1\x16\x4f" - "\xd4\xe8\x43\xc1\x68\xa3\x3e\x06" - "\x38\x51\xff\xa8\xb9\xa4\xeb\xb1" - "\x62\xdd\x78\x81\xea\x1d\xef\x04" - "\x1d\x07\xc1\x67\xc8\xd6\x77\xa1" - "\x84\x95\xf4\x9a\xd9\xbc\x2d\xe2" - "\xf6\x80\xfc\x91\x2a\xbc\x42\xa0" - "\x40\x41\x69\xaa\x71\xc0\x37\xec" - "\x39\xf3\xf2\xec\x82\xc3\x88\x79" - "\xbc\xc3\xaa\xb7\xcf\x6a\x72\x80" - "\x4c\xf4\x84\x8f\x13\x9e\x94\x5c" - "\xe5\xb2\x91\xbb\x92\x51\x4d\xf1" - "\xd6\x0d\x71\x6b\x7a\xc2\x2f\x12" - "\x6f\x75\xc7\x80\x99\x50\x84\xcf" - "\xa8\xeb\xd6\xe1\x1c\x59\x81\x7e" - "\xb9\xb3\xde\x7a\x93\x14\x12\xa2" - "\xf7\x43\xb3\x9d\x1a\x87\x65\x91" - "\x42\x08\x40\x82\x06\x1c\x2d\x55" - "\x6e\x48\xd5\x74\x07\x6e\x9d\x80" - "\xeb\xb4\x97\xa1\x36\xdf\xfa\x74" - "\x79\x7f\x5a\x75\xe7\x71\xc8\x8c" - "\x7e\xf8\x3a\x77\xcd\x32\x05\xf9" - "\x3d\xd4\xe9\xa2\xbb\xc4\x8b\x83" - "\x42\x5c\x82\xfa\xe9\x4b\x96\x3b" - "\x7f\x89\x8b\xf9\xf1\x87\xda\xf0" - "\x87\xef\x13\x5d\xf0\xe2\xc5\xc1" - "\xed\x14\xa9\x57\x19\x63\x40\x04" - "\x24\xeb\x6e\x19\xd1\x3d\x70\x78" - "\xeb\xda\x55\x70\x2c\x4f\x41\x5b" - "\x56\x9f\x1a\xd3\xac\xf1\xc0\xc3" - "\x21\xec\xd7\xd2\x55\x32\x7c\x2e" - "\x3c\x48\x8e\xb4\x85\x35\x47\xfe" - "\xe2\x88\x79\x98\x6a\xc9\x8d\xff" - "\xe9\x89\x6e\xb8\xe2\x97\x00\xbd" - "\xa4\x8f\xba\xd0\x8c\xcb\x79\x99" - "\xb3\xb2\xb2\x7a\xc3\xb7\xef\x75" - "\x23\x52\x76\xc3\x50\x6e\x66\xf8" - "\xa2\xe2\xce\xba\x40\x21\x3f\xc9" - "\x0a\x32\x7f\xf7\x08\x8c\x66\xcf" - "\xd3\xdf\x57\x59\x83\xb8\xe1\x85" - "\xd6\x8f\xfb\x48\x1f\x3a\xc4\x2f" - "\xb4\x2d\x58\xab\xd8\x7f\x5e\x3a" - "\xbc\x62\x3e\xe2\x6a\x52\x0d\x76" - "\x2f\x1c\x1a\x30\xed\x95\x2a\x44" - "\x35\xa5\x83\x04\x84\x01\x99\x56" - "\xb7\xe3\x10\x96\xfa\xdc\x19\xdd" - "\xe2\x7f\xcb\xa0\x49\x1b\xff\x4c" - "\x73\xf6\xbb\x94\x00\xe8\xa9\x3d" - "\xe2\x20\xe9\x3f\xfa\x07\x5d\x77" - "\x06\xd5\x4f\x4d\x02\xb8\x40\x1b" - "\x30\xed\x1a\x50\x19\xef\xc4\x2c" - "\x02\xd9\xc5\xd3\x11\x33\x37\xe5" - "\x2b\xa3\x95\xa6\xee\xd8\x74\x1d" - "\x68\xa0\xeb\xbf\xdd\x5e\x99\x96" - "\x91\xc3\x94\x24\xa5\x12\xa2\x37" - "\xb3\xac\xcf\x2a\xfd\x55\x34\xfe" - "\x79\x92\x3e\xe6\x1b\x49\x57\x5d" - "\x93\x6c\x01\xf7\xcc\x4e\x20\xd1" - "\xb2\x1a\xd8\x4c\xbd\x1d\x10\xe9" - "\x5a\xa8\x92\x7f\xba\xe6\x0c\x95", - .ilen = 512, - .result = "\x05\x11\xb7\x18\xab\xc6\x2d\xac" - "\x70\x5d\xf6\x22\x94\xcd\xe5\x6c" - "\x17\x6b\xf6\x1c\xf0\xf3\x6e\xf8" - "\x50\x38\x1f\x71\x49\xb6\x57\xd6" - "\x8f\xcb\x8d\x6b\xe3\xa6\x29\x90" - "\xfe\x2a\x62\x82\xae\x6d\x8b\xf6" - "\xad\x1e\x9e\x20\x5f\x38\xbe\x04" - "\xda\x10\x8e\xed\xa2\xa4\x87\xab" - "\xda\x6b\xb4\x0c\x75\xba\xd3\x7c" - "\xc9\xac\x42\x31\x95\x7c\xc9\x04" - "\xeb\xd5\x6e\x32\x69\x8a\xdb\xa6" - "\x15\xd7\x3f\x4f\x2f\x66\x69\x03" - "\x9c\x1f\x54\x0f\xde\x1f\xf3\x65" - "\x4c\x96\x12\xed\x7c\x92\x03\x01" - "\x6f\xbc\x35\x93\xac\xf1\x27\xf1" - "\xb4\x96\x82\x5a\x5f\xb0\xa0\x50" - "\x89\xa4\x8e\x66\x44\x85\xcc\xfd" - "\x33\x14\x70\xe3\x96\xb2\xc3\xd3" - "\xbb\x54\x5a\x1a\xf9\x74\xa2\xc5" - "\x2d\x64\x75\xdd\xb4\x54\xe6\x74" - "\x8c\xd3\x9d\x9e\x86\xab\x51\x53" - "\xb7\x93\x3e\x6f\xd0\x4e\x2c\x40" - "\xf6\xa8\x2e\x3e\x9d\xf4\x66\xa5" - "\x76\x12\x73\x44\x1a\x56\xd7\x72" - "\x88\xcd\x21\x8c\x4c\x0f\xfe\xda" - "\x95\xe0\x3a\xa6\xa5\x84\x46\xcd" - "\xd5\x3e\x9d\x3a\xe2\x67\xe6\x60" - "\x1a\xe2\x70\x85\x58\xc2\x1b\x09" - "\xe1\xd7\x2c\xca\xad\xa8\x8f\xf9" - "\xac\xb3\x0e\xdb\xca\x2e\xe2\xb8" - "\x51\x71\xd9\x3c\x6c\xf1\x56\xf8" - "\xea\x9c\xf1\xfb\x0c\xe6\xb7\x10" - "\x1c\xf8\xa9\x7c\xe8\x53\x35\xc1" - "\x90\x3e\x76\x4a\x74\xa4\x21\x2c" - "\xf6\x2c\x4e\x0f\x94\x3a\x88\x2e" - "\x41\x09\x6a\x33\x7d\xf6\xdd\x3f" - "\x8d\x23\x31\x74\x84\xeb\x88\x6e" - "\xcc\xb9\xbc\x22\x83\x19\x07\x22" - "\xa5\x2d\xdf\xa5\xf3\x80\x85\x78" - "\x84\x39\x6a\x6d\x6a\x99\x4f\xa5" - "\x15\xfe\x46\xb0\xe4\x6c\xa5\x41" - "\x3c\xce\x8f\x42\x60\x71\xa7\x75" - "\x08\x40\x65\x8a\x82\xbf\xf5\x43" - "\x71\x96\xa9\x4d\x44\x8a\x20\xbe" - "\xfa\x4d\xbb\xc0\x7d\x31\x96\x65" - "\xe7\x75\xe5\x3e\xfd\x92\x3b\xc9" - "\x55\xbb\x16\x7e\xf7\xc2\x8c\xa4" - "\x40\x1d\xe5\xef\x0e\xdf\xe4\x9a" - "\x62\x73\x65\xfd\x46\x63\x25\x3d" - "\x2b\xaf\xe5\x64\xfe\xa5\x5c\xcf" - "\x24\xf3\xb4\xac\x64\xba\xdf\x4b" - "\xc6\x96\x7d\x81\x2d\x8d\x97\xf7" - "\xc5\x68\x77\x84\x32\x2b\xcc\x85" - "\x74\x96\xf0\x12\x77\x61\xb9\xeb" - "\x71\xaa\x82\xcb\x1c\xdb\x89\xc8" - "\xc6\xb5\xe3\x5c\x7d\x39\x07\x24" - "\xda\x39\x87\x45\xc0\x2b\xbb\x01" - "\xac\xbc\x2a\x5c\x7f\xfc\xe8\xce" - "\x6d\x9c\x6f\xed\xd3\xc1\xa1\xd6" - "\xc5\x55\xa9\x66\x2f\xe1\xc8\x32" - "\xa6\x5d\xa4\x3a\x98\x73\xe8\x45" - "\xa4\xc7\xa8\xb4\xf6\x13\x03\xf6" - "\xe9\x2e\xc4\x29\x0f\x84\xdb\xc4" - "\x21\xc4\xc2\x75\x67\x89\x37\x0a", - .rlen = 512, - }, -}; - -static struct cipher_testvec camellia_xts_enc_tv_template[] = { - /* Generated from AES-XTS test vectors */ - { - .key = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .ilen = 32, - .result = "\x06\xcb\xa5\xf1\x04\x63\xb2\x41" - "\xdc\xca\xfa\x09\xba\x74\xb9\x05" - "\x78\xba\xa4\xf8\x67\x4d\x7e\xad" - "\x20\x18\xf5\x0c\x41\x16\x2a\x61", - .rlen = 32, - }, { - .key = "\x11\x11\x11\x11\x11\x11\x11\x11" - "\x11\x11\x11\x11\x11\x11\x11\x11" - "\x22\x22\x22\x22\x22\x22\x22\x22" - "\x22\x22\x22\x22\x22\x22\x22\x22", - .klen = 32, - .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44", - .ilen = 32, - .result = "\xc2\xb9\xdc\x44\x1d\xdf\xf2\x86" - "\x8d\x35\x42\x0a\xa5\x5e\x3d\x4f" - "\xb5\x37\x06\xff\xbd\xd4\x91\x70" - "\x80\x1f\xb2\x39\x10\x89\x44\xf5", - .rlen = 32, - }, { - .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" - "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" - "\x22\x22\x22\x22\x22\x22\x22\x22" - "\x22\x22\x22\x22\x22\x22\x22\x22", - .klen = 32, - .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44", - .ilen = 32, - .result = "\x52\x1f\x9d\xf5\x5a\x58\x5a\x7e" - "\x9f\xd0\x8e\x02\x9c\x9a\x6a\xa7" - "\xb4\x3b\xce\xe7\x17\xaa\x89\x6a" - "\x35\x3c\x6b\xb5\x61\x1c\x79\x38", - .rlen = 32, - }, { - .key = "\x27\x18\x28\x18\x28\x45\x90\x45" - "\x23\x53\x60\x28\x74\x71\x35\x26" - "\x31\x41\x59\x26\x53\x58\x97\x93" - "\x23\x84\x62\x64\x33\x83\x27\x95", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - .ilen = 512, - .result = "\xc7\xf9\x0a\xaa\xcb\xb5\x8f\x33" - "\x60\xc3\xe9\x47\x90\xb7\x50\x57" - "\xa3\xad\x81\x2f\xf5\x22\x96\x02" - "\xaa\x7f\xea\xac\x29\x78\xca\x2a" - "\x7c\xcd\x31\x1a\x3c\x40\x0a\x73" - "\x09\x66\xad\x72\x0e\x4d\x5d\x77" - "\xbc\xb8\x76\x80\x37\x59\xa9\x01" - "\x9e\xfb\xdb\x6c\x93\xef\xb6\x8d" - "\x1e\xc1\x94\xa8\xd4\xb5\xb0\x01" - "\xd5\x01\x97\x28\xcd\x7a\x1f\xe8" - "\x08\xda\x76\x00\x65\xcf\x7b\x31" - "\xc6\xfa\xf2\x3b\x00\xa7\x6a\x9e" - "\x6c\x43\x80\x87\xe0\xbb\x4e\xe5" - "\xdc\x8a\xdf\xc3\x1d\x1b\x41\x04" - "\xfb\x54\xdd\x29\x27\xc2\x65\x17" - "\x36\x88\xb0\x85\x8d\x73\x7e\x4b" - "\x1d\x16\x8a\x52\xbc\xa6\xbc\xa4" - "\x8c\xd1\x04\x16\xbf\x8c\x01\x0f" - "\x7e\x6b\x59\x15\x29\xd1\x9b\xd3" - "\x6c\xee\xac\xdc\x45\x58\xca\x5b" - "\x70\x0e\x6a\x12\x86\x82\x79\x9f" - "\x16\xd4\x9d\x67\xcd\x70\x65\x26" - "\x21\x72\x1e\xa1\x94\x8a\x83\x0c" - "\x92\x42\x58\x5e\xa2\xc5\x31\xf3" - "\x7b\xd1\x31\xd4\x15\x80\x31\x61" - "\x5c\x53\x10\xdd\xea\xc8\x83\x5c" - "\x7d\xa7\x05\x66\xcc\x1e\xbb\x05" - "\x47\xae\xb4\x0f\x84\xd8\xf6\xb5" - "\xa1\xc6\x52\x00\x52\xe8\xdc\xd9" - "\x16\x31\xb2\x47\x91\x67\xaa\x28" - "\x2c\x29\x85\xa3\xf7\xf2\x24\x93" - "\x23\x80\x1f\xa8\x1b\x82\x8d\xdc" - "\x9f\x0b\xcd\xb4\x3c\x20\xbc\xec" - "\x4f\xc7\xee\xf8\xfd\xd9\xfb\x7e" - "\x3f\x0d\x23\xfa\x3f\xa7\xcc\x66" - "\x1c\xfe\xa6\x86\xf6\xf7\x85\xc7" - "\x43\xc1\xd4\xfc\xe4\x79\xc9\x1d" - "\xf8\x89\xcd\x20\x27\x84\x5d\x5c" - "\x8e\x4f\x1f\xeb\x08\x21\x4f\xa3" - "\xe0\x7e\x0b\x9c\xe7\x42\xcf\xb7" - "\x3f\x43\xcc\x86\x71\x34\x6a\xd9" - "\x5e\xec\x8f\x36\xc9\x0a\x03\xfe" - "\x18\x41\xdc\x9e\x2e\x75\x20\x3e" - "\xcc\x77\xe0\x8f\xe8\x43\x37\x4c" - "\xed\x1a\x5a\xb3\xfa\x43\xc9\x71" - "\x9f\xc5\xce\xcf\xff\xe7\x77\x1e" - "\x35\x93\xde\x6b\xc0\x6a\x7e\xa9" - "\x34\xb8\x27\x74\x08\xda\xf2\x4a" - "\x23\x5b\x9f\x55\x3a\x57\x82\x52" - "\xea\x6d\xc3\xc7\xf2\xc8\xb5\xdc" - "\xc5\xb9\xbb\xaa\xf2\x29\x9f\x49" - "\x7a\xef\xfe\xdc\x9f\xc9\x28\xe2" - "\x96\x0b\x35\x84\x05\x0d\xd6\x2a" - "\xea\x5a\xbf\x69\xde\xee\x4f\x8f" - "\x84\xb9\xcf\xa7\x57\xea\xe0\xe8" - "\x96\xef\x0f\x0e\xec\xc7\xa6\x74" - "\xb1\xfe\x7a\x6d\x11\xdd\x0e\x15" - "\x4a\x1e\x73\x7f\x55\xea\xf6\xe1" - "\x5b\xb6\x71\xda\xb0\x0c\xba\x26" - "\x5c\x48\x38\x6d\x1c\x32\xb2\x7d" - "\x05\x87\xc2\x1e\x7e\x2d\xd4\x33" - "\xcc\x06\xdb\xe7\x82\x29\x63\xd1" - "\x52\x84\x4f\xee\x27\xe8\x02\xd4" - "\x34\x3c\x69\xc2\xbd\x20\xe6\x7a", - .rlen = 512, - }, { - .key = "\x27\x18\x28\x18\x28\x45\x90\x45" - "\x23\x53\x60\x28\x74\x71\x35\x26" - "\x62\x49\x77\x57\x24\x70\x93\x69" - "\x99\x59\x57\x49\x66\x96\x76\x27" - "\x31\x41\x59\x26\x53\x58\x97\x93" - "\x23\x84\x62\x64\x33\x83\x27\x95" - "\x02\x88\x41\x97\x16\x93\x99\x37" - "\x51\x05\x82\x09\x74\x94\x45\x92", - .klen = 64, - .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - .ilen = 512, - .result = "\x49\xcd\xb8\xbf\x2f\x73\x37\x28" - "\x9a\x7f\x6e\x57\x55\xb8\x07\x88" - "\x4a\x0d\x8b\x55\x60\xed\xb6\x7b" - "\xf1\x74\xac\x96\x05\x7b\x32\xca" - "\xd1\x4e\xf1\x58\x29\x16\x24\x6c" - "\xf2\xb3\xe4\x88\x84\xac\x4d\xee" - "\x97\x07\x82\xf0\x07\x12\x38\x0a" - "\x67\x62\xaf\xfd\x85\x9f\x0a\x55" - "\xa5\x20\xc5\x60\xe4\x68\x53\xa4" - "\x0e\x2e\x65\xe3\xe4\x0c\x30\x7c" - "\x1c\x01\x4f\x55\xa9\x13\xeb\x25" - "\x21\x87\xbc\xd3\xe7\x67\x4f\x38" - "\xa8\x14\x25\x71\xe9\x2e\x4c\x21" - "\x41\x82\x0c\x45\x39\x35\xa8\x75" - "\x03\x29\x01\x84\x8c\xab\x48\xbe" - "\x11\x56\x22\x67\xb7\x67\x1a\x09" - "\xa1\x72\x25\x41\x3c\x39\x65\x80" - "\x7d\x2f\xf8\x2c\x73\x04\x58\x9d" - "\xdd\x16\x8b\x63\x70\x4e\xc5\x17" - "\x21\xe0\x84\x51\x4b\x6f\x05\x52" - "\xe3\x63\x34\xfa\xa4\xaf\x33\x20" - "\xc1\xae\x32\xc4\xb8\x2b\xdb\x76" - "\xd9\x02\x31\x2f\xa3\xc6\xd0\x7b" - "\xaf\x1b\x84\xe3\x9b\xbf\xa6\xe0" - "\xb8\x8a\x13\x88\x71\xf4\x11\xa5" - "\xe9\xa9\x10\x33\xe0\xbe\x49\x89" - "\x41\x22\xf5\x9d\x80\x3e\x3b\x76" - "\x01\x16\x50\x6e\x7c\x6a\x81\xe9" - "\x13\x2c\xde\xb2\x5f\x79\xba\xb2" - "\xb1\x75\xae\xd2\x07\x98\x4b\x69" - "\xae\x7d\x5b\x90\xc2\x6c\xe6\x98" - "\xd3\x4c\xa1\xa3\x9c\xc9\x33\x6a" - "\x0d\x23\xb1\x79\x25\x13\x4b\xe5" - "\xaf\x93\x20\x5c\x7f\x06\x7a\x34" - "\x0b\x78\xe3\x67\x26\xe0\xad\x95" - "\xc5\x4e\x26\x22\xcf\x73\x77\x62" - "\x3e\x10\xd7\x90\x4b\x52\x1c\xc9" - "\xef\x38\x52\x18\x0e\x29\x7e\xef" - "\x34\xfe\x31\x95\xc5\xbc\xa8\xe2" - "\xa8\x4e\x9f\xea\xa6\xf0\xfe\x5d" - "\xc5\x39\x86\xed\x2f\x6d\xa0\xfe" - "\x96\xcd\x41\x10\x78\x4e\x0c\xc9" - "\xc3\x6d\x0f\xb7\xe8\xe0\x62\xab" - "\x8b\xf1\x21\x89\xa1\x12\xaa\xfa" - "\x9d\x70\xbe\x4c\xa8\x98\x89\x01" - "\xb9\xe2\x61\xde\x0c\x4a\x0b\xaa" - "\x89\xf5\x14\x79\x18\x8f\x3b\x0d" - "\x21\x17\xf8\x59\x15\x24\x64\x22" - "\x57\x48\x80\xd5\x3d\x92\x30\x07" - "\xd9\xa1\x4a\x23\x16\x43\x48\x0e" - "\x2b\x2d\x1b\x87\xef\x7e\xbd\xfa" - "\x49\xbc\x7e\x68\x6e\xa8\x46\x95" - "\xad\x5e\xfe\x0a\xa8\xd3\x1a\x5d" - "\x6b\x84\xf3\x00\xba\x52\x05\x02" - "\xe3\x96\x4e\xb6\x79\x3f\x43\xd3" - "\x4d\x3f\xd6\xab\x0a\xc4\x75\x2d" - "\xd1\x08\xc3\x6a\xc8\x37\x29\xa0" - "\xcc\x9a\x05\xdd\x5c\xe1\xff\x66" - "\xf2\x7a\x1d\xf2\xaf\xa9\x48\x89" - "\xf5\x21\x0f\x02\x48\x83\x74\xbf" - "\x2e\xe6\x93\x7b\xa0\xf4\xb1\x2b" - "\xb1\x02\x0a\x5c\x79\x19\x3b\x75" - "\xb7\x16\xd8\x12\x5c\xcd\x7d\x4e" - "\xd5\xc6\x99\xcc\x4e\x6c\x94\x95", - .rlen = 512, - }, -}; - -static struct cipher_testvec camellia_xts_dec_tv_template[] = { - /* Generated from AES-XTS test vectors */ - /* same as enc vectors with input and result reversed */ - { - .key = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\x06\xcb\xa5\xf1\x04\x63\xb2\x41" - "\xdc\xca\xfa\x09\xba\x74\xb9\x05" - "\x78\xba\xa4\xf8\x67\x4d\x7e\xad" - "\x20\x18\xf5\x0c\x41\x16\x2a\x61", - .ilen = 32, - .result = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .rlen = 32, - }, { - .key = "\x11\x11\x11\x11\x11\x11\x11\x11" - "\x11\x11\x11\x11\x11\x11\x11\x11" - "\x22\x22\x22\x22\x22\x22\x22\x22" - "\x22\x22\x22\x22\x22\x22\x22\x22", - .klen = 32, - .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\xc2\xb9\xdc\x44\x1d\xdf\xf2\x86" - "\x8d\x35\x42\x0a\xa5\x5e\x3d\x4f" - "\xb5\x37\x06\xff\xbd\xd4\x91\x70" - "\x80\x1f\xb2\x39\x10\x89\x44\xf5", - .ilen = 32, - .result = "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44", - .rlen = 32, - }, { - .key = "\xff\xfe\xfd\xfc\xfb\xfa\xf9\xf8" - "\xf7\xf6\xf5\xf4\xf3\xf2\xf1\xf0" - "\x22\x22\x22\x22\x22\x22\x22\x22" - "\x22\x22\x22\x22\x22\x22\x22\x22", - .klen = 32, - .iv = "\x33\x33\x33\x33\x33\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\x52\x1f\x9d\xf5\x5a\x58\x5a\x7e" - "\x9f\xd0\x8e\x02\x9c\x9a\x6a\xa7" - "\xb4\x3b\xce\xe7\x17\xaa\x89\x6a" - "\x35\x3c\x6b\xb5\x61\x1c\x79\x38", - .ilen = 32, - .result = "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44" - "\x44\x44\x44\x44\x44\x44\x44\x44", - .rlen = 32, - }, { - .key = "\x27\x18\x28\x18\x28\x45\x90\x45" - "\x23\x53\x60\x28\x74\x71\x35\x26" - "\x31\x41\x59\x26\x53\x58\x97\x93" - "\x23\x84\x62\x64\x33\x83\x27\x95", - .klen = 32, - .iv = "\x00\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\xc7\xf9\x0a\xaa\xcb\xb5\x8f\x33" - "\x60\xc3\xe9\x47\x90\xb7\x50\x57" - "\xa3\xad\x81\x2f\xf5\x22\x96\x02" - "\xaa\x7f\xea\xac\x29\x78\xca\x2a" - "\x7c\xcd\x31\x1a\x3c\x40\x0a\x73" - "\x09\x66\xad\x72\x0e\x4d\x5d\x77" - "\xbc\xb8\x76\x80\x37\x59\xa9\x01" - "\x9e\xfb\xdb\x6c\x93\xef\xb6\x8d" - "\x1e\xc1\x94\xa8\xd4\xb5\xb0\x01" - "\xd5\x01\x97\x28\xcd\x7a\x1f\xe8" - "\x08\xda\x76\x00\x65\xcf\x7b\x31" - "\xc6\xfa\xf2\x3b\x00\xa7\x6a\x9e" - "\x6c\x43\x80\x87\xe0\xbb\x4e\xe5" - "\xdc\x8a\xdf\xc3\x1d\x1b\x41\x04" - "\xfb\x54\xdd\x29\x27\xc2\x65\x17" - "\x36\x88\xb0\x85\x8d\x73\x7e\x4b" - "\x1d\x16\x8a\x52\xbc\xa6\xbc\xa4" - "\x8c\xd1\x04\x16\xbf\x8c\x01\x0f" - "\x7e\x6b\x59\x15\x29\xd1\x9b\xd3" - "\x6c\xee\xac\xdc\x45\x58\xca\x5b" - "\x70\x0e\x6a\x12\x86\x82\x79\x9f" - "\x16\xd4\x9d\x67\xcd\x70\x65\x26" - "\x21\x72\x1e\xa1\x94\x8a\x83\x0c" - "\x92\x42\x58\x5e\xa2\xc5\x31\xf3" - "\x7b\xd1\x31\xd4\x15\x80\x31\x61" - "\x5c\x53\x10\xdd\xea\xc8\x83\x5c" - "\x7d\xa7\x05\x66\xcc\x1e\xbb\x05" - "\x47\xae\xb4\x0f\x84\xd8\xf6\xb5" - "\xa1\xc6\x52\x00\x52\xe8\xdc\xd9" - "\x16\x31\xb2\x47\x91\x67\xaa\x28" - "\x2c\x29\x85\xa3\xf7\xf2\x24\x93" - "\x23\x80\x1f\xa8\x1b\x82\x8d\xdc" - "\x9f\x0b\xcd\xb4\x3c\x20\xbc\xec" - "\x4f\xc7\xee\xf8\xfd\xd9\xfb\x7e" - "\x3f\x0d\x23\xfa\x3f\xa7\xcc\x66" - "\x1c\xfe\xa6\x86\xf6\xf7\x85\xc7" - "\x43\xc1\xd4\xfc\xe4\x79\xc9\x1d" - "\xf8\x89\xcd\x20\x27\x84\x5d\x5c" - "\x8e\x4f\x1f\xeb\x08\x21\x4f\xa3" - "\xe0\x7e\x0b\x9c\xe7\x42\xcf\xb7" - "\x3f\x43\xcc\x86\x71\x34\x6a\xd9" - "\x5e\xec\x8f\x36\xc9\x0a\x03\xfe" - "\x18\x41\xdc\x9e\x2e\x75\x20\x3e" - "\xcc\x77\xe0\x8f\xe8\x43\x37\x4c" - "\xed\x1a\x5a\xb3\xfa\x43\xc9\x71" - "\x9f\xc5\xce\xcf\xff\xe7\x77\x1e" - "\x35\x93\xde\x6b\xc0\x6a\x7e\xa9" - "\x34\xb8\x27\x74\x08\xda\xf2\x4a" - "\x23\x5b\x9f\x55\x3a\x57\x82\x52" - "\xea\x6d\xc3\xc7\xf2\xc8\xb5\xdc" - "\xc5\xb9\xbb\xaa\xf2\x29\x9f\x49" - "\x7a\xef\xfe\xdc\x9f\xc9\x28\xe2" - "\x96\x0b\x35\x84\x05\x0d\xd6\x2a" - "\xea\x5a\xbf\x69\xde\xee\x4f\x8f" - "\x84\xb9\xcf\xa7\x57\xea\xe0\xe8" - "\x96\xef\x0f\x0e\xec\xc7\xa6\x74" - "\xb1\xfe\x7a\x6d\x11\xdd\x0e\x15" - "\x4a\x1e\x73\x7f\x55\xea\xf6\xe1" - "\x5b\xb6\x71\xda\xb0\x0c\xba\x26" - "\x5c\x48\x38\x6d\x1c\x32\xb2\x7d" - "\x05\x87\xc2\x1e\x7e\x2d\xd4\x33" - "\xcc\x06\xdb\xe7\x82\x29\x63\xd1" - "\x52\x84\x4f\xee\x27\xe8\x02\xd4" - "\x34\x3c\x69\xc2\xbd\x20\xe6\x7a", - .ilen = 512, - .result = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - .rlen = 512, - }, { - .key = "\x27\x18\x28\x18\x28\x45\x90\x45" - "\x23\x53\x60\x28\x74\x71\x35\x26" - "\x62\x49\x77\x57\x24\x70\x93\x69" - "\x99\x59\x57\x49\x66\x96\x76\x27" - "\x31\x41\x59\x26\x53\x58\x97\x93" - "\x23\x84\x62\x64\x33\x83\x27\x95" - "\x02\x88\x41\x97\x16\x93\x99\x37" - "\x51\x05\x82\x09\x74\x94\x45\x92", - .klen = 64, - .iv = "\xff\x00\x00\x00\x00\x00\x00\x00" - "\x00\x00\x00\x00\x00\x00\x00\x00", - .input = "\x49\xcd\xb8\xbf\x2f\x73\x37\x28" - "\x9a\x7f\x6e\x57\x55\xb8\x07\x88" - "\x4a\x0d\x8b\x55\x60\xed\xb6\x7b" - "\xf1\x74\xac\x96\x05\x7b\x32\xca" - "\xd1\x4e\xf1\x58\x29\x16\x24\x6c" - "\xf2\xb3\xe4\x88\x84\xac\x4d\xee" - "\x97\x07\x82\xf0\x07\x12\x38\x0a" - "\x67\x62\xaf\xfd\x85\x9f\x0a\x55" - "\xa5\x20\xc5\x60\xe4\x68\x53\xa4" - "\x0e\x2e\x65\xe3\xe4\x0c\x30\x7c" - "\x1c\x01\x4f\x55\xa9\x13\xeb\x25" - "\x21\x87\xbc\xd3\xe7\x67\x4f\x38" - "\xa8\x14\x25\x71\xe9\x2e\x4c\x21" - "\x41\x82\x0c\x45\x39\x35\xa8\x75" - "\x03\x29\x01\x84\x8c\xab\x48\xbe" - "\x11\x56\x22\x67\xb7\x67\x1a\x09" - "\xa1\x72\x25\x41\x3c\x39\x65\x80" - "\x7d\x2f\xf8\x2c\x73\x04\x58\x9d" - "\xdd\x16\x8b\x63\x70\x4e\xc5\x17" - "\x21\xe0\x84\x51\x4b\x6f\x05\x52" - "\xe3\x63\x34\xfa\xa4\xaf\x33\x20" - "\xc1\xae\x32\xc4\xb8\x2b\xdb\x76" - "\xd9\x02\x31\x2f\xa3\xc6\xd0\x7b" - "\xaf\x1b\x84\xe3\x9b\xbf\xa6\xe0" - "\xb8\x8a\x13\x88\x71\xf4\x11\xa5" - "\xe9\xa9\x10\x33\xe0\xbe\x49\x89" - "\x41\x22\xf5\x9d\x80\x3e\x3b\x76" - "\x01\x16\x50\x6e\x7c\x6a\x81\xe9" - "\x13\x2c\xde\xb2\x5f\x79\xba\xb2" - "\xb1\x75\xae\xd2\x07\x98\x4b\x69" - "\xae\x7d\x5b\x90\xc2\x6c\xe6\x98" - "\xd3\x4c\xa1\xa3\x9c\xc9\x33\x6a" - "\x0d\x23\xb1\x79\x25\x13\x4b\xe5" - "\xaf\x93\x20\x5c\x7f\x06\x7a\x34" - "\x0b\x78\xe3\x67\x26\xe0\xad\x95" - "\xc5\x4e\x26\x22\xcf\x73\x77\x62" - "\x3e\x10\xd7\x90\x4b\x52\x1c\xc9" - "\xef\x38\x52\x18\x0e\x29\x7e\xef" - "\x34\xfe\x31\x95\xc5\xbc\xa8\xe2" - "\xa8\x4e\x9f\xea\xa6\xf0\xfe\x5d" - "\xc5\x39\x86\xed\x2f\x6d\xa0\xfe" - "\x96\xcd\x41\x10\x78\x4e\x0c\xc9" - "\xc3\x6d\x0f\xb7\xe8\xe0\x62\xab" - "\x8b\xf1\x21\x89\xa1\x12\xaa\xfa" - "\x9d\x70\xbe\x4c\xa8\x98\x89\x01" - "\xb9\xe2\x61\xde\x0c\x4a\x0b\xaa" - "\x89\xf5\x14\x79\x18\x8f\x3b\x0d" - "\x21\x17\xf8\x59\x15\x24\x64\x22" - "\x57\x48\x80\xd5\x3d\x92\x30\x07" - "\xd9\xa1\x4a\x23\x16\x43\x48\x0e" - "\x2b\x2d\x1b\x87\xef\x7e\xbd\xfa" - "\x49\xbc\x7e\x68\x6e\xa8\x46\x95" - "\xad\x5e\xfe\x0a\xa8\xd3\x1a\x5d" - "\x6b\x84\xf3\x00\xba\x52\x05\x02" - "\xe3\x96\x4e\xb6\x79\x3f\x43\xd3" - "\x4d\x3f\xd6\xab\x0a\xc4\x75\x2d" - "\xd1\x08\xc3\x6a\xc8\x37\x29\xa0" - "\xcc\x9a\x05\xdd\x5c\xe1\xff\x66" - "\xf2\x7a\x1d\xf2\xaf\xa9\x48\x89" - "\xf5\x21\x0f\x02\x48\x83\x74\xbf" - "\x2e\xe6\x93\x7b\xa0\xf4\xb1\x2b" - "\xb1\x02\x0a\x5c\x79\x19\x3b\x75" - "\xb7\x16\xd8\x12\x5c\xcd\x7d\x4e" - "\xd5\xc6\x99\xcc\x4e\x6c\x94\x95", - .ilen = 512, - .result = "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "\x20\x21\x22\x23\x24\x25\x26\x27" - "\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f" - "\x30\x31\x32\x33\x34\x35\x36\x37" - "\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f" - "\x40\x41\x42\x43\x44\x45\x46\x47" - "\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f" - "\x50\x51\x52\x53\x54\x55\x56\x57" - "\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f" - "\x60\x61\x62\x63\x64\x65\x66\x67" - "\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f" - "\x70\x71\x72\x73\x74\x75\x76\x77" - "\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f" - "\x80\x81\x82\x83\x84\x85\x86\x87" - "\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" - "\x90\x91\x92\x93\x94\x95\x96\x97" - "\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" - "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7" - "\xa8\xa9\xaa\xab\xac\xad\xae\xaf" - "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7" - "\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf" - "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7" - "\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf" - "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7" - "\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf" - "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7" - "\xe8\xe9\xea\xeb\xec\xed\xee\xef" - "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" - "\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff", - .rlen = 512, - }, }; /* diff --git a/trunk/drivers/base/driver.c b/trunk/drivers/base/driver.c index 3ec3896c83a6..60e4f77ca662 100644 --- a/trunk/drivers/base/driver.c +++ b/trunk/drivers/base/driver.c @@ -123,6 +123,36 @@ void driver_remove_file(struct device_driver *drv, } EXPORT_SYMBOL_GPL(driver_remove_file); +/** + * driver_add_kobj - add a kobject below the specified driver + * @drv: requesting device driver + * @kobj: kobject to add below this driver + * @fmt: format string that names the kobject + * + * You really don't want to do this, this is only here due to one looney + * iseries driver, go poke those developers if you are annoyed about + * this... + */ +int driver_add_kobj(struct device_driver *drv, struct kobject *kobj, + const char *fmt, ...) +{ + va_list args; + char *name; + int ret; + + va_start(args, fmt); + name = kvasprintf(GFP_KERNEL, fmt, args); + va_end(args); + + if (!name) + return -ENOMEM; + + ret = kobject_add(kobj, &drv->p->kobj, "%s", name); + kfree(name); + return ret; +} +EXPORT_SYMBOL_GPL(driver_add_kobj); + static int driver_add_groups(struct device_driver *drv, const struct attribute_group **groups) { diff --git a/trunk/drivers/block/viodasd.c b/trunk/drivers/block/viodasd.c new file mode 100644 index 000000000000..9a5b2a2d616d --- /dev/null +++ b/trunk/drivers/block/viodasd.c @@ -0,0 +1,809 @@ +/* -*- linux-c -*- + * viodasd.c + * Authors: Dave Boutcher + * Ryan Arnold + * Colin Devilbiss + * Stephen Rothwell + * + * (C) Copyright 2000-2004 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This routine provides access to disk space (termed "DASD" in historical + * IBM terms) owned and managed by an OS/400 partition running on the + * same box as this Linux partition. + * + * All disk operations are performed by sending messages back and forth to + * the OS/400 partition. + */ + +#define pr_fmt(fmt) "viod: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("iSeries Virtual DASD"); +MODULE_AUTHOR("Dave Boutcher"); +MODULE_LICENSE("GPL"); + +/* + * We only support 7 partitions per physical disk....so with minor + * numbers 0-255 we get a maximum of 32 disks. + */ +#define VIOD_GENHD_NAME "iseries/vd" + +#define VIOD_VERS "1.64" + +enum { + PARTITION_SHIFT = 3, + MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS, + MAX_DISK_NAME = FIELD_SIZEOF(struct gendisk, disk_name) +}; + +static DEFINE_MUTEX(viodasd_mutex); +static DEFINE_SPINLOCK(viodasd_spinlock); + +#define VIOMAXREQ 16 + +#define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0]) + +struct viodasd_waitevent { + struct completion com; + int rc; + u16 sub_result; + int max_disk; /* open */ +}; + +static const struct vio_error_entry viodasd_err_table[] = { + { 0x0201, EINVAL, "Invalid Range" }, + { 0x0202, EINVAL, "Invalid Token" }, + { 0x0203, EIO, "DMA Error" }, + { 0x0204, EIO, "Use Error" }, + { 0x0205, EIO, "Release Error" }, + { 0x0206, EINVAL, "Invalid Disk" }, + { 0x0207, EBUSY, "Can't Lock" }, + { 0x0208, EIO, "Already Locked" }, + { 0x0209, EIO, "Already Unlocked" }, + { 0x020A, EIO, "Invalid Arg" }, + { 0x020B, EIO, "Bad IFS File" }, + { 0x020C, EROFS, "Read Only Device" }, + { 0x02FF, EIO, "Internal Error" }, + { 0x0000, 0, NULL }, +}; + +/* + * Figure out the biggest I/O request (in sectors) we can accept + */ +#define VIODASD_MAXSECTORS (4096 / 512 * VIOMAXBLOCKDMA) + +/* + * Number of disk I/O requests we've sent to OS/400 + */ +static int num_req_outstanding; + +/* + * This is our internal structure for keeping track of disk devices + */ +struct viodasd_device { + u16 cylinders; + u16 tracks; + u16 sectors; + u16 bytes_per_sector; + u64 size; + int read_only; + spinlock_t q_lock; + struct gendisk *disk; + struct device *dev; +} viodasd_devices[MAX_DISKNO]; + +/* + * External open entry point. + */ +static int viodasd_open(struct block_device *bdev, fmode_t mode) +{ + struct viodasd_device *d = bdev->bd_disk->private_data; + HvLpEvent_Rc hvrc; + struct viodasd_waitevent we; + u16 flags = 0; + + if (d->read_only) { + if (mode & FMODE_WRITE) + return -EROFS; + flags = vioblockflags_ro; + } + + init_completion(&we.com); + + /* Send the open event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + ((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32), + 0, 0, 0); + if (hvrc != 0) { + pr_warning("HV open failed %d\n", (int)hvrc); + return -EIO; + } + + wait_for_completion(&we.com); + + /* Check the return code */ + if (we.rc != 0) { + const struct vio_error_entry *err = + vio_lookup_rc(viodasd_err_table, we.sub_result); + + pr_warning("bad rc opening disk: %d:0x%04x (%s)\n", + (int)we.rc, we.sub_result, err->msg); + return -EIO; + } + + return 0; +} + +static int viodasd_unlocked_open(struct block_device *bdev, fmode_t mode) +{ + int ret; + + mutex_lock(&viodasd_mutex); + ret = viodasd_open(bdev, mode); + mutex_unlock(&viodasd_mutex); + + return ret; +} + + +/* + * External release entry point. + */ +static int viodasd_release(struct gendisk *disk, fmode_t mode) +{ + struct viodasd_device *d = disk->private_data; + HvLpEvent_Rc hvrc; + + mutex_lock(&viodasd_mutex); + /* Send the event to OS/400. We DON'T expect a response */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockclose, + HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + 0, VIOVERSION << 16, + ((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */, + 0, 0, 0); + if (hvrc != 0) + pr_warning("HV close call failed %d\n", (int)hvrc); + + mutex_unlock(&viodasd_mutex); + + return 0; +} + + +/* External ioctl entry point. + */ +static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct gendisk *disk = bdev->bd_disk; + struct viodasd_device *d = disk->private_data; + + geo->sectors = d->sectors ? d->sectors : 32; + geo->heads = d->tracks ? d->tracks : 64; + geo->cylinders = d->cylinders ? d->cylinders : + get_capacity(disk) / (geo->sectors * geo->heads); + + return 0; +} + +/* + * Our file operations table + */ +static const struct block_device_operations viodasd_fops = { + .owner = THIS_MODULE, + .open = viodasd_unlocked_open, + .release = viodasd_release, + .getgeo = viodasd_getgeo, +}; + +/* + * End a request + */ +static void viodasd_end_request(struct request *req, int error, + int num_sectors) +{ + __blk_end_request(req, error, num_sectors << 9); +} + +/* + * Send an actual I/O request to OS/400 + */ +static int send_request(struct request *req) +{ + u64 start; + int direction; + int nsg; + u16 viocmd; + HvLpEvent_Rc hvrc; + struct vioblocklpevent *bevent; + struct HvLpEvent *hev; + struct scatterlist sg[VIOMAXBLOCKDMA]; + int sgindex; + struct viodasd_device *d; + unsigned long flags; + + start = (u64)blk_rq_pos(req) << 9; + + if (rq_data_dir(req) == READ) { + direction = DMA_FROM_DEVICE; + viocmd = viomajorsubtype_blockio | vioblockread; + } else { + direction = DMA_TO_DEVICE; + viocmd = viomajorsubtype_blockio | vioblockwrite; + } + + d = req->rq_disk->private_data; + + /* Now build the scatter-gather list */ + sg_init_table(sg, VIOMAXBLOCKDMA); + nsg = blk_rq_map_sg(req->q, req, sg); + nsg = dma_map_sg(d->dev, sg, nsg, direction); + + spin_lock_irqsave(&viodasd_spinlock, flags); + num_req_outstanding++; + + /* This optimization handles a single DMA block */ + if (nsg == 1) + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, viocmd, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)req, VIOVERSION << 16, + ((u64)DEVICE_NO(d) << 48), start, + ((u64)sg_dma_address(&sg[0])) << 32, + sg_dma_len(&sg[0])); + else { + bevent = (struct vioblocklpevent *) + vio_get_event_buffer(viomajorsubtype_blockio); + if (bevent == NULL) { + pr_warning("error allocating disk event buffer\n"); + goto error_ret; + } + + /* + * Now build up the actual request. Note that we store + * the pointer to the request in the correlation + * token so we can match the response up later + */ + memset(bevent, 0, sizeof(struct vioblocklpevent)); + hev = &bevent->event; + hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | + HV_LP_EVENT_INT; + hev->xType = HvLpEvent_Type_VirtualIo; + hev->xSubtype = viocmd; + hev->xSourceLp = HvLpConfig_getLpIndex(); + hev->xTargetLp = viopath_hostLp; + hev->xSizeMinus1 = + offsetof(struct vioblocklpevent, u.rw_data.dma_info) + + (sizeof(bevent->u.rw_data.dma_info[0]) * nsg) - 1; + hev->xSourceInstanceId = viopath_sourceinst(viopath_hostLp); + hev->xTargetInstanceId = viopath_targetinst(viopath_hostLp); + hev->xCorrelationToken = (u64)req; + bevent->version = VIOVERSION; + bevent->disk = DEVICE_NO(d); + bevent->u.rw_data.offset = start; + + /* + * Copy just the dma information from the sg list + * into the request + */ + for (sgindex = 0; sgindex < nsg; sgindex++) { + bevent->u.rw_data.dma_info[sgindex].token = + sg_dma_address(&sg[sgindex]); + bevent->u.rw_data.dma_info[sgindex].len = + sg_dma_len(&sg[sgindex]); + } + + /* Send the request */ + hvrc = HvCallEvent_signalLpEvent(&bevent->event); + vio_free_event_buffer(viomajorsubtype_blockio, bevent); + } + + if (hvrc != HvLpEvent_Rc_Good) { + pr_warning("error sending disk event to OS/400 (rc %d)\n", + (int)hvrc); + goto error_ret; + } + spin_unlock_irqrestore(&viodasd_spinlock, flags); + return 0; + +error_ret: + num_req_outstanding--; + spin_unlock_irqrestore(&viodasd_spinlock, flags); + dma_unmap_sg(d->dev, sg, nsg, direction); + return -1; +} + +/* + * This is the external request processing routine + */ +static void do_viodasd_request(struct request_queue *q) +{ + struct request *req; + + /* + * If we already have the maximum number of requests + * outstanding to OS/400 just bail out. We'll come + * back later. + */ + while (num_req_outstanding < VIOMAXREQ) { + req = blk_fetch_request(q); + if (req == NULL) + return; + /* check that request contains a valid command */ + if (req->cmd_type != REQ_TYPE_FS) { + viodasd_end_request(req, -EIO, blk_rq_sectors(req)); + continue; + } + /* Try sending the request */ + if (send_request(req) != 0) + viodasd_end_request(req, -EIO, blk_rq_sectors(req)); + } +} + +/* + * Probe a single disk and fill in the viodasd_device structure + * for it. + */ +static int probe_disk(struct viodasd_device *d) +{ + HvLpEvent_Rc hvrc; + struct viodasd_waitevent we; + int dev_no = DEVICE_NO(d); + struct gendisk *g; + struct request_queue *q; + u16 flags = 0; + +retry: + init_completion(&we.com); + + /* Send the open event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)&we, VIOVERSION << 16, + ((u64)dev_no << 48) | ((u64)flags<< 32), + 0, 0, 0); + if (hvrc != 0) { + pr_warning("bad rc on HV open %d\n", (int)hvrc); + return 0; + } + + wait_for_completion(&we.com); + + if (we.rc != 0) { + if (flags != 0) + return 0; + /* try again with read only flag set */ + flags = vioblockflags_ro; + goto retry; + } + if (we.max_disk > (MAX_DISKNO - 1)) { + printk_once(KERN_INFO pr_fmt("Only examining the first %d of %d disks connected\n"), + MAX_DISKNO, we.max_disk + 1); + } + + /* Send the close event to OS/400. We DON'T expect a response */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_blockio | vioblockclose, + HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + 0, VIOVERSION << 16, + ((u64)dev_no << 48) | ((u64)flags << 32), + 0, 0, 0); + if (hvrc != 0) { + pr_warning("bad rc sending event to OS/400 %d\n", (int)hvrc); + return 0; + } + + if (d->dev == NULL) { + /* this is when we reprobe for new disks */ + if (vio_create_viodasd(dev_no) == NULL) { + pr_warning("cannot allocate virtual device for disk %d\n", + dev_no); + return 0; + } + /* + * The vio_create_viodasd will have recursed into this + * routine with d->dev set to the new vio device and + * will finish the setup of the disk below. + */ + return 1; + } + + /* create the request queue for the disk */ + spin_lock_init(&d->q_lock); + q = blk_init_queue(do_viodasd_request, &d->q_lock); + if (q == NULL) { + pr_warning("cannot allocate queue for disk %d\n", dev_no); + return 0; + } + g = alloc_disk(1 << PARTITION_SHIFT); + if (g == NULL) { + pr_warning("cannot allocate disk structure for disk %d\n", + dev_no); + blk_cleanup_queue(q); + return 0; + } + + d->disk = g; + blk_queue_max_segments(q, VIOMAXBLOCKDMA); + blk_queue_max_hw_sectors(q, VIODASD_MAXSECTORS); + g->major = VIODASD_MAJOR; + g->first_minor = dev_no << PARTITION_SHIFT; + if (dev_no >= 26) + snprintf(g->disk_name, sizeof(g->disk_name), + VIOD_GENHD_NAME "%c%c", + 'a' + (dev_no / 26) - 1, 'a' + (dev_no % 26)); + else + snprintf(g->disk_name, sizeof(g->disk_name), + VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26)); + g->fops = &viodasd_fops; + g->queue = q; + g->private_data = d; + g->driverfs_dev = d->dev; + set_capacity(g, d->size >> 9); + + pr_info("disk %d: %lu sectors (%lu MB) CHS=%d/%d/%d sector size %d%s\n", + dev_no, (unsigned long)(d->size >> 9), + (unsigned long)(d->size >> 20), + (int)d->cylinders, (int)d->tracks, + (int)d->sectors, (int)d->bytes_per_sector, + d->read_only ? " (RO)" : ""); + + /* register us in the global list */ + add_disk(g); + return 1; +} + +/* returns the total number of scatterlist elements converted */ +static int block_event_to_scatterlist(const struct vioblocklpevent *bevent, + struct scatterlist *sg, int *total_len) +{ + int i, numsg; + const struct rw_data *rw_data = &bevent->u.rw_data; + static const int offset = + offsetof(struct vioblocklpevent, u.rw_data.dma_info); + static const int element_size = sizeof(rw_data->dma_info[0]); + + numsg = ((bevent->event.xSizeMinus1 + 1) - offset) / element_size; + if (numsg > VIOMAXBLOCKDMA) + numsg = VIOMAXBLOCKDMA; + + *total_len = 0; + sg_init_table(sg, VIOMAXBLOCKDMA); + for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) { + sg_dma_address(&sg[i]) = rw_data->dma_info[i].token; + sg_dma_len(&sg[i]) = rw_data->dma_info[i].len; + *total_len += rw_data->dma_info[i].len; + } + return i; +} + +/* + * Restart all queues, starting with the one _after_ the disk given, + * thus reducing the chance of starvation of higher numbered disks. + */ +static void viodasd_restart_all_queues_starting_from(int first_index) +{ + int i; + + for (i = first_index + 1; i < MAX_DISKNO; ++i) + if (viodasd_devices[i].disk) + blk_run_queue(viodasd_devices[i].disk->queue); + for (i = 0; i <= first_index; ++i) + if (viodasd_devices[i].disk) + blk_run_queue(viodasd_devices[i].disk->queue); +} + +/* + * For read and write requests, decrement the number of outstanding requests, + * Free the DMA buffers we allocated. + */ +static int viodasd_handle_read_write(struct vioblocklpevent *bevent) +{ + int num_sg, num_sect, pci_direction, total_len; + struct request *req; + struct scatterlist sg[VIOMAXBLOCKDMA]; + struct HvLpEvent *event = &bevent->event; + unsigned long irq_flags; + struct viodasd_device *d; + int error; + spinlock_t *qlock; + + num_sg = block_event_to_scatterlist(bevent, sg, &total_len); + num_sect = total_len >> 9; + if (event->xSubtype == (viomajorsubtype_blockio | vioblockread)) + pci_direction = DMA_FROM_DEVICE; + else + pci_direction = DMA_TO_DEVICE; + req = (struct request *)bevent->event.xCorrelationToken; + d = req->rq_disk->private_data; + + dma_unmap_sg(d->dev, sg, num_sg, pci_direction); + + /* + * Since this is running in interrupt mode, we need to make sure + * we're not stepping on any global I/O operations + */ + spin_lock_irqsave(&viodasd_spinlock, irq_flags); + num_req_outstanding--; + spin_unlock_irqrestore(&viodasd_spinlock, irq_flags); + + error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO; + if (error) { + const struct vio_error_entry *err; + err = vio_lookup_rc(viodasd_err_table, bevent->sub_result); + pr_warning("read/write error %d:0x%04x (%s)\n", + event->xRc, bevent->sub_result, err->msg); + num_sect = blk_rq_sectors(req); + } + qlock = req->q->queue_lock; + spin_lock_irqsave(qlock, irq_flags); + viodasd_end_request(req, error, num_sect); + spin_unlock_irqrestore(qlock, irq_flags); + + /* Finally, try to get more requests off of this device's queue */ + viodasd_restart_all_queues_starting_from(DEVICE_NO(d)); + + return 0; +} + +/* This routine handles incoming block LP events */ +static void handle_block_event(struct HvLpEvent *event) +{ + struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; + struct viodasd_waitevent *pwe; + + if (event == NULL) + /* Notification that a partition went away! */ + return; + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + pr_warning("Yikes! got an int in viodasd event handler!\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case vioblockopen: + /* + * Handle a response to an open request. We get all the + * disk information in the response, so update it. The + * correlation token contains a pointer to a waitevent + * structure that has a completion in it. update the + * return code in the waitevent structure and post the + * completion to wake up the guy who sent the request + */ + pwe = (struct viodasd_waitevent *)event->xCorrelationToken; + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + if (event->xRc == HvLpEvent_Rc_Good) { + const struct open_data *data = &bevent->u.open_data; + struct viodasd_device *device = + &viodasd_devices[bevent->disk]; + device->read_only = + bevent->flags & vioblockflags_ro; + device->size = data->disk_size; + device->cylinders = data->cylinders; + device->tracks = data->tracks; + device->sectors = data->sectors; + device->bytes_per_sector = data->bytes_per_sector; + pwe->max_disk = data->max_disk; + } + complete(&pwe->com); + break; + case vioblockclose: + break; + case vioblockread: + case vioblockwrite: + viodasd_handle_read_write(bevent); + break; + + default: + pr_warning("invalid subtype!"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +/* + * Get the driver to reprobe for more disks. + */ +static ssize_t probe_disks(struct device_driver *drv, const char *buf, + size_t count) +{ + struct viodasd_device *d; + + for (d = viodasd_devices; d < &viodasd_devices[MAX_DISKNO]; d++) { + if (d->disk == NULL) + probe_disk(d); + } + return count; +} +static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks); + +static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id) +{ + struct viodasd_device *d = &viodasd_devices[vdev->unit_address]; + + d->dev = &vdev->dev; + if (!probe_disk(d)) + return -ENODEV; + return 0; +} + +static int viodasd_remove(struct vio_dev *vdev) +{ + struct viodasd_device *d; + + d = &viodasd_devices[vdev->unit_address]; + if (d->disk) { + del_gendisk(d->disk); + blk_cleanup_queue(d->disk->queue); + put_disk(d->disk); + d->disk = NULL; + } + d->dev = NULL; + return 0; +} + +/** + * viodasd_device_table: Used by vio.c to match devices that we + * support. + */ +static struct vio_device_id viodasd_device_table[] __devinitdata = { + { "block", "IBM,iSeries-viodasd" }, + { "", "" } +}; +MODULE_DEVICE_TABLE(vio, viodasd_device_table); + +static struct vio_driver viodasd_driver = { + .id_table = viodasd_device_table, + .probe = viodasd_probe, + .remove = viodasd_remove, + .driver = { + .name = "viodasd", + .owner = THIS_MODULE, + } +}; + +static int need_delete_probe; + +/* + * Initialize the whole device driver. Handle module and non-module + * versions + */ +static int __init viodasd_init(void) +{ + int rc; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) { + rc = -ENODEV; + goto early_fail; + } + + /* Try to open to our host lp */ + if (viopath_hostLp == HvLpIndexInvalid) + vio_set_hostlp(); + + if (viopath_hostLp == HvLpIndexInvalid) { + pr_warning("invalid hosting partition\n"); + rc = -EIO; + goto early_fail; + } + + pr_info("vers " VIOD_VERS ", hosting partition %d\n", viopath_hostLp); + + /* register the block device */ + rc = register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); + if (rc) { + pr_warning("Unable to get major number %d for %s\n", + VIODASD_MAJOR, VIOD_GENHD_NAME); + goto early_fail; + } + /* Actually open the path to the hosting partition */ + rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, + VIOMAXREQ + 2); + if (rc) { + pr_warning("error opening path to host partition %d\n", + viopath_hostLp); + goto unregister_blk; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_blockio, handle_block_event); + + rc = vio_register_driver(&viodasd_driver); + if (rc) { + pr_warning("vio_register_driver failed\n"); + goto unset_handler; + } + + /* + * If this call fails, it just means that we cannot dynamically + * add virtual disks, but the driver will still work fine for + * all existing disk, so ignore the failure. + */ + if (!driver_create_file(&viodasd_driver.driver, &driver_attr_probe)) + need_delete_probe = 1; + + return 0; + +unset_handler: + vio_clearHandler(viomajorsubtype_blockio); + viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2); +unregister_blk: + unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); +early_fail: + return rc; +} +module_init(viodasd_init); + +void __exit viodasd_exit(void) +{ + if (need_delete_probe) + driver_remove_file(&viodasd_driver.driver, &driver_attr_probe); + vio_unregister_driver(&viodasd_driver); + vio_clearHandler(viomajorsubtype_blockio); + viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2); + unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); +} +module_exit(viodasd_exit); diff --git a/trunk/drivers/cdrom/viocd.c b/trunk/drivers/cdrom/viocd.c new file mode 100644 index 000000000000..7878da89d29e --- /dev/null +++ b/trunk/drivers/cdrom/viocd.c @@ -0,0 +1,739 @@ +/* -*- linux-c -*- + * drivers/cdrom/viocd.c + * + * iSeries Virtual CD Rom + * + * Authors: Dave Boutcher + * Ryan Arnold + * Colin Devilbiss + * Stephen Rothwell + * + * (C) Copyright 2000-2004 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) anyu later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This routine provides access to CD ROM drives owned and managed by an + * OS/400 partition running on the same box as this Linux partition. + * + * All operations are performed by sending messages back and forth to + * the OS/400 partition. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define VIOCD_DEVICE "iseries/vcd" + +#define VIOCD_VERS "1.06" + +/* + * Should probably make this a module parameter....sigh + */ +#define VIOCD_MAX_CD HVMAXARCHITECTEDVIRTUALCDROMS + +static DEFINE_MUTEX(viocd_mutex); +static const struct vio_error_entry viocd_err_table[] = { + {0x0201, EINVAL, "Invalid Range"}, + {0x0202, EINVAL, "Invalid Token"}, + {0x0203, EIO, "DMA Error"}, + {0x0204, EIO, "Use Error"}, + {0x0205, EIO, "Release Error"}, + {0x0206, EINVAL, "Invalid CD"}, + {0x020C, EROFS, "Read Only Device"}, + {0x020D, ENOMEDIUM, "Changed or Missing Volume (or Varied Off?)"}, + {0x020E, EIO, "Optical System Error (Varied Off?)"}, + {0x02FF, EIO, "Internal Error"}, + {0x3010, EIO, "Changed Volume"}, + {0xC100, EIO, "Optical System Error"}, + {0x0000, 0, NULL}, +}; + +/* + * This is the structure we use to exchange info between driver and interrupt + * handler + */ +struct viocd_waitevent { + struct completion com; + int rc; + u16 sub_result; + int changed; +}; + +/* this is a lookup table for the true capabilities of a device */ +struct capability_entry { + char *type; + int capability; +}; + +static struct capability_entry capability_table[] __initdata = { + { "6330", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "6331", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "6333", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "632A", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, + { "6321", CDC_LOCK }, + { "632B", 0 }, + { NULL , CDC_LOCK }, +}; + +/* These are our internal structures for keeping track of devices */ +static int viocd_numdev; + +struct disk_info { + struct gendisk *viocd_disk; + struct cdrom_device_info viocd_info; + struct device *dev; + const char *rsrcname; + const char *type; + const char *model; +}; +static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; + +#define DEVICE_NR(di) ((di) - &viocd_diskinfo[0]) + +static spinlock_t viocd_reqlock; + +#define MAX_CD_REQ 1 + +/* procfs support */ +static int proc_viocd_show(struct seq_file *m, void *v) +{ + int i; + + for (i = 0; i < viocd_numdev; i++) { + seq_printf(m, "viocd device %d is iSeries resource %10.10s" + "type %4.4s, model %3.3s\n", + i, viocd_diskinfo[i].rsrcname, + viocd_diskinfo[i].type, + viocd_diskinfo[i].model); + } + return 0; +} + +static int proc_viocd_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_viocd_show, NULL); +} + +static const struct file_operations proc_viocd_operations = { + .owner = THIS_MODULE, + .open = proc_viocd_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int viocd_blk_open(struct block_device *bdev, fmode_t mode) +{ + struct disk_info *di = bdev->bd_disk->private_data; + int ret; + + mutex_lock(&viocd_mutex); + ret = cdrom_open(&di->viocd_info, bdev, mode); + mutex_unlock(&viocd_mutex); + + return ret; +} + +static int viocd_blk_release(struct gendisk *disk, fmode_t mode) +{ + struct disk_info *di = disk->private_data; + mutex_lock(&viocd_mutex); + cdrom_release(&di->viocd_info, mode); + mutex_unlock(&viocd_mutex); + return 0; +} + +static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode, + unsigned cmd, unsigned long arg) +{ + struct disk_info *di = bdev->bd_disk->private_data; + int ret; + + mutex_lock(&viocd_mutex); + ret = cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg); + mutex_unlock(&viocd_mutex); + + return ret; +} + +static unsigned int viocd_blk_check_events(struct gendisk *disk, + unsigned int clearing) +{ + struct disk_info *di = disk->private_data; + return cdrom_check_events(&di->viocd_info, clearing); +} + +static const struct block_device_operations viocd_fops = { + .owner = THIS_MODULE, + .open = viocd_blk_open, + .release = viocd_blk_release, + .ioctl = viocd_blk_ioctl, + .check_events = viocd_blk_check_events, +}; + +static int viocd_open(struct cdrom_device_info *cdi, int purpose) +{ + struct disk_info *diskinfo = cdi->handle; + int device_no = DEVICE_NR(diskinfo); + HvLpEvent_Rc hvrc; + struct viocd_waitevent we; + + init_completion(&we.com); + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, ((u64)device_no << 48), + 0, 0, 0); + if (hvrc != 0) { + pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", + (int)hvrc); + return -EIO; + } + + wait_for_completion(&we.com); + + if (we.rc) { + const struct vio_error_entry *err = + vio_lookup_rc(viocd_err_table, we.sub_result); + pr_warning("bad rc %d:0x%04X on open: %s\n", + we.rc, we.sub_result, err->msg); + return -err->errno; + } + + return 0; +} + +static void viocd_release(struct cdrom_device_info *cdi) +{ + int device_no = DEVICE_NR((struct disk_info *)cdi->handle); + HvLpEvent_Rc hvrc; + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdclose, + HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), 0, + VIOVERSION << 16, ((u64)device_no << 48), 0, 0, 0); + if (hvrc != 0) + pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", + (int)hvrc); +} + +/* Send a read or write request to OS/400 */ +static int send_request(struct request *req) +{ + HvLpEvent_Rc hvrc; + struct disk_info *diskinfo = req->rq_disk->private_data; + u64 len; + dma_addr_t dmaaddr; + int direction; + u16 cmd; + struct scatterlist sg; + + BUG_ON(req->nr_phys_segments > 1); + + if (rq_data_dir(req) == READ) { + direction = DMA_FROM_DEVICE; + cmd = viomajorsubtype_cdio | viocdread; + } else { + direction = DMA_TO_DEVICE; + cmd = viomajorsubtype_cdio | viocdwrite; + } + + sg_init_table(&sg, 1); + if (blk_rq_map_sg(req->q, req, &sg) == 0) { + pr_warning("error setting up scatter/gather list\n"); + return -1; + } + + if (dma_map_sg(diskinfo->dev, &sg, 1, direction) == 0) { + pr_warning("error allocating sg tce\n"); + return -1; + } + dmaaddr = sg_dma_address(&sg); + len = sg_dma_len(&sg); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, cmd, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)req, VIOVERSION << 16, + ((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr, + (u64)blk_rq_pos(req) * 512, len, 0); + if (hvrc != HvLpEvent_Rc_Good) { + pr_warning("hv error on op %d\n", (int)hvrc); + return -1; + } + + return 0; +} + +static int rwreq; + +static void do_viocd_request(struct request_queue *q) +{ + struct request *req; + + while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) { + if (req->cmd_type != REQ_TYPE_FS) + __blk_end_request_all(req, -EIO); + else if (send_request(req) < 0) { + pr_warning("unable to send message to OS/400!\n"); + __blk_end_request_all(req, -EIO); + } else + rwreq++; + } +} + +static unsigned int viocd_check_events(struct cdrom_device_info *cdi, + unsigned int clearing, int disc_nr) +{ + struct viocd_waitevent we; + HvLpEvent_Rc hvrc; + int device_no = DEVICE_NR((struct disk_info *)cdi->handle); + + init_completion(&we.com); + + /* Send the open event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdcheck, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, ((u64)device_no << 48), + 0, 0, 0); + if (hvrc != 0) { + pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", + (int)hvrc); + return 0; + } + + wait_for_completion(&we.com); + + /* Check the return code. If bad, assume no change */ + if (we.rc) { + const struct vio_error_entry *err = + vio_lookup_rc(viocd_err_table, we.sub_result); + pr_warning("bad rc %d:0x%04X on check_change: %s; Assuming no change\n", + we.rc, we.sub_result, err->msg); + return 0; + } + + return we.changed ? DISK_EVENT_MEDIA_CHANGE : 0; +} + +static int viocd_lock_door(struct cdrom_device_info *cdi, int locking) +{ + HvLpEvent_Rc hvrc; + u64 device_no = DEVICE_NR((struct disk_info *)cdi->handle); + /* NOTE: flags is 1 or 0 so it won't overwrite the device_no */ + u64 flags = !!locking; + struct viocd_waitevent we; + + init_completion(&we.com); + + /* Send the lockdoor event to OS/400 */ + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_cdio | viocdlockdoor, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)&we, VIOVERSION << 16, + (device_no << 48) | (flags << 32), 0, 0, 0); + if (hvrc != 0) { + pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", + (int)hvrc); + return -EIO; + } + + wait_for_completion(&we.com); + + if (we.rc != 0) + return -EIO; + return 0; +} + +static int viocd_packet(struct cdrom_device_info *cdi, + struct packet_command *cgc) +{ + unsigned int buflen = cgc->buflen; + int ret = -EIO; + + switch (cgc->cmd[0]) { + case GPCMD_READ_DISC_INFO: + { + disc_information *di = (disc_information *)cgc->buffer; + + if (buflen >= 2) { + di->disc_information_length = cpu_to_be16(1); + ret = 0; + } + if (buflen >= 3) + di->erasable = + (cdi->ops->capability & ~cdi->mask + & (CDC_DVD_RAM | CDC_RAM)) != 0; + } + break; + case GPCMD_GET_CONFIGURATION: + if (cgc->cmd[3] == CDF_RWRT) { + struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header)); + + if ((buflen >= + (sizeof(struct feature_header) + sizeof(*rfd))) && + (cdi->ops->capability & ~cdi->mask + & (CDC_DVD_RAM | CDC_RAM))) { + rfd->feature_code = cpu_to_be16(CDF_RWRT); + rfd->curr = 1; + ret = 0; + } + } + break; + default: + if (cgc->sense) { + /* indicate Unknown code */ + cgc->sense->sense_key = 0x05; + cgc->sense->asc = 0x20; + cgc->sense->ascq = 0x00; + } + break; + } + + cgc->stat = ret; + return ret; +} + +static void restart_all_queues(int first_index) +{ + int i; + + for (i = first_index + 1; i < viocd_numdev; i++) + if (viocd_diskinfo[i].viocd_disk) + blk_run_queue(viocd_diskinfo[i].viocd_disk->queue); + for (i = 0; i <= first_index; i++) + if (viocd_diskinfo[i].viocd_disk) + blk_run_queue(viocd_diskinfo[i].viocd_disk->queue); +} + +/* This routine handles incoming CD LP events */ +static void vio_handle_cd_event(struct HvLpEvent *event) +{ + struct viocdlpevent *bevent; + struct viocd_waitevent *pwe; + struct disk_info *di; + unsigned long flags; + struct request *req; + + + if (event == NULL) + /* Notification that a partition went away! */ + return; + /* First, we should NEVER get an int here...only acks */ + if (hvlpevent_is_int(event)) { + pr_warning("Yikes! got an int in viocd event handler!\n"); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } + + bevent = (struct viocdlpevent *)event; + + switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { + case viocdopen: + if (event->xRc == 0) { + di = &viocd_diskinfo[bevent->disk]; + blk_queue_logical_block_size(di->viocd_disk->queue, + bevent->block_size); + set_capacity(di->viocd_disk, + bevent->media_size * + bevent->block_size / 512); + } + /* FALLTHROUGH !! */ + case viocdlockdoor: + pwe = (struct viocd_waitevent *)event->xCorrelationToken; +return_complete: + pwe->rc = event->xRc; + pwe->sub_result = bevent->sub_result; + complete(&pwe->com); + break; + + case viocdcheck: + pwe = (struct viocd_waitevent *)event->xCorrelationToken; + pwe->changed = bevent->flags; + goto return_complete; + + case viocdclose: + break; + + case viocdwrite: + case viocdread: + /* + * Since this is running in interrupt mode, we need to + * make sure we're not stepping on any global I/O operations + */ + di = &viocd_diskinfo[bevent->disk]; + spin_lock_irqsave(&viocd_reqlock, flags); + dma_unmap_single(di->dev, bevent->token, bevent->len, + ((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread) + ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + req = (struct request *)bevent->event.xCorrelationToken; + rwreq--; + + if (event->xRc != HvLpEvent_Rc_Good) { + const struct vio_error_entry *err = + vio_lookup_rc(viocd_err_table, + bevent->sub_result); + pr_warning("request %p failed with rc %d:0x%04X: %s\n", + req, event->xRc, + bevent->sub_result, err->msg); + __blk_end_request_all(req, -EIO); + } else + __blk_end_request_all(req, 0); + + /* restart handling of incoming requests */ + spin_unlock_irqrestore(&viocd_reqlock, flags); + restart_all_queues(bevent->disk); + break; + + default: + pr_warning("message with invalid subtype %0x04X!\n", + event->xSubtype & VIOMINOR_SUBTYPE_MASK); + if (hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static int viocd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, + void *arg) +{ + return -EINVAL; +} + +static struct cdrom_device_ops viocd_dops = { + .open = viocd_open, + .release = viocd_release, + .check_events = viocd_check_events, + .lock_door = viocd_lock_door, + .generic_packet = viocd_packet, + .audio_ioctl = viocd_audio_ioctl, + .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM +}; + +static int find_capability(const char *type) +{ + struct capability_entry *entry; + + for(entry = capability_table; entry->type; ++entry) + if(!strncmp(entry->type, type, 4)) + break; + return entry->capability; +} + +static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) +{ + struct gendisk *gendisk; + int deviceno; + struct disk_info *d; + struct cdrom_device_info *c; + struct request_queue *q; + struct device_node *node = vdev->dev.of_node; + + deviceno = vdev->unit_address; + if (deviceno >= VIOCD_MAX_CD) + return -ENODEV; + if (!node) + return -ENODEV; + + if (deviceno >= viocd_numdev) + viocd_numdev = deviceno + 1; + + d = &viocd_diskinfo[deviceno]; + d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL); + d->type = of_get_property(node, "linux,vio_type", NULL); + d->model = of_get_property(node, "linux,vio_model", NULL); + + c = &d->viocd_info; + + c->ops = &viocd_dops; + c->speed = 4; + c->capacity = 1; + c->handle = d; + c->mask = ~find_capability(d->type); + sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); + + if (register_cdrom(c) != 0) { + pr_warning("Cannot register viocd CD-ROM %s!\n", c->name); + goto out; + } + pr_info("cd %s is iSeries resource %10.10s type %4.4s, model %3.3s\n", + c->name, d->rsrcname, d->type, d->model); + q = blk_init_queue(do_viocd_request, &viocd_reqlock); + if (q == NULL) { + pr_warning("Cannot allocate queue for %s!\n", c->name); + goto out_unregister_cdrom; + } + gendisk = alloc_disk(1); + if (gendisk == NULL) { + pr_warning("Cannot create gendisk for %s!\n", c->name); + goto out_cleanup_queue; + } + gendisk->major = VIOCD_MAJOR; + gendisk->first_minor = deviceno; + strncpy(gendisk->disk_name, c->name, + sizeof(gendisk->disk_name)); + blk_queue_max_segments(q, 1); + blk_queue_max_hw_sectors(q, 4096 / 512); + gendisk->queue = q; + gendisk->fops = &viocd_fops; + gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE | + GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE; + set_capacity(gendisk, 0); + gendisk->private_data = d; + d->viocd_disk = gendisk; + d->dev = &vdev->dev; + gendisk->driverfs_dev = d->dev; + add_disk(gendisk); + return 0; + +out_cleanup_queue: + blk_cleanup_queue(q); +out_unregister_cdrom: + unregister_cdrom(c); +out: + return -ENODEV; +} + +static int viocd_remove(struct vio_dev *vdev) +{ + struct disk_info *d = &viocd_diskinfo[vdev->unit_address]; + + unregister_cdrom(&d->viocd_info); + del_gendisk(d->viocd_disk); + blk_cleanup_queue(d->viocd_disk->queue); + put_disk(d->viocd_disk); + return 0; +} + +/** + * viocd_device_table: Used by vio.c to match devices that we + * support. + */ +static struct vio_device_id viocd_device_table[] __devinitdata = { + { "block", "IBM,iSeries-viocd" }, + { "", "" } +}; +MODULE_DEVICE_TABLE(vio, viocd_device_table); + +static struct vio_driver viocd_driver = { + .id_table = viocd_device_table, + .probe = viocd_probe, + .remove = viocd_remove, + .driver = { + .name = "viocd", + .owner = THIS_MODULE, + } +}; + +static int __init viocd_init(void) +{ + int ret = 0; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + + if (viopath_hostLp == HvLpIndexInvalid) { + vio_set_hostlp(); + /* If we don't have a host, bail out */ + if (viopath_hostLp == HvLpIndexInvalid) + return -ENODEV; + } + + pr_info("vers " VIOCD_VERS ", hosting partition %d\n", viopath_hostLp); + + if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) { + pr_warning("Unable to get major %d for %s\n", + VIOCD_MAJOR, VIOCD_DEVICE); + return -EIO; + } + + ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, + MAX_CD_REQ + 2); + if (ret) { + pr_warning("error opening path to host partition %d\n", + viopath_hostLp); + goto out_unregister; + } + + /* Initialize our request handler */ + vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); + + spin_lock_init(&viocd_reqlock); + + ret = vio_register_driver(&viocd_driver); + if (ret) + goto out_free_info; + + proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL, + &proc_viocd_operations); + return 0; + +out_free_info: + vio_clearHandler(viomajorsubtype_cdio); + viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); +out_unregister: + unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); + return ret; +} + +static void __exit viocd_exit(void) +{ + remove_proc_entry("iSeries/viocd", NULL); + vio_unregister_driver(&viocd_driver); + viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); + vio_clearHandler(viomajorsubtype_cdio); + unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); +} + +module_init(viocd_init); +module_exit(viocd_exit); +MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/char/hw_random/tx4939-rng.c b/trunk/drivers/char/hw_random/tx4939-rng.c index de473ef3882b..0bc0cb70210b 100644 --- a/trunk/drivers/char/hw_random/tx4939-rng.c +++ b/trunk/drivers/char/hw_random/tx4939-rng.c @@ -115,7 +115,10 @@ static int __init tx4939_rng_probe(struct platform_device *dev) rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL); if (!rngdev) return -ENOMEM; - rngdev->base = devm_request_and_ioremap(&dev->dev, r); + if (!devm_request_mem_region(&dev->dev, r->start, resource_size(r), + dev_name(&dev->dev))) + return -EBUSY; + rngdev->base = devm_ioremap(&dev->dev, r->start, resource_size(r)); if (!rngdev->base) return -EBUSY; diff --git a/trunk/drivers/char/tpm/Kconfig b/trunk/drivers/char/tpm/Kconfig index a048199ce866..7fc75e47e6d0 100644 --- a/trunk/drivers/char/tpm/Kconfig +++ b/trunk/drivers/char/tpm/Kconfig @@ -5,6 +5,7 @@ menuconfig TCG_TPM tristate "TPM Hardware Support" depends on HAS_IOMEM + depends on EXPERIMENTAL select SECURITYFS ---help--- If you have a TPM security chip in your system, which diff --git a/trunk/drivers/char/tpm/tpm.c b/trunk/drivers/char/tpm/tpm.c index ad7c7320dd1b..32362cf35b8d 100644 --- a/trunk/drivers/char/tpm/tpm.c +++ b/trunk/drivers/char/tpm/tpm.c @@ -1221,13 +1221,12 @@ ssize_t tpm_read(struct file *file, char __user *buf, ret_size = atomic_read(&chip->data_pending); atomic_set(&chip->data_pending, 0); if (ret_size > 0) { /* relay data */ - ssize_t orig_ret_size = ret_size; if (size < ret_size) ret_size = size; mutex_lock(&chip->buffer_mutex); rc = copy_to_user(buf, chip->data_buffer, ret_size); - memset(chip->data_buffer, 0, orig_ret_size); + memset(chip->data_buffer, 0, ret_size); if (rc) ret_size = -EFAULT; diff --git a/trunk/drivers/char/tpm/tpm.h b/trunk/drivers/char/tpm/tpm.h index b1c5280ac159..010547138281 100644 --- a/trunk/drivers/char/tpm/tpm.h +++ b/trunk/drivers/char/tpm/tpm.h @@ -99,8 +99,6 @@ struct tpm_vendor_specific { wait_queue_head_t int_queue; }; -#define TPM_VID_INTEL 0x8086 - struct tpm_chip { struct device *dev; /* Device stuff */ diff --git a/trunk/drivers/char/tpm/tpm_tis.c b/trunk/drivers/char/tpm/tpm_tis.c index d2a70cae76df..70fac9abb0e2 100644 --- a/trunk/drivers/char/tpm/tpm_tis.c +++ b/trunk/drivers/char/tpm/tpm_tis.c @@ -367,12 +367,7 @@ static int probe_itpm(struct tpm_chip *chip) 0x00, 0x00, 0x00, 0xf1 }; size_t len = sizeof(cmd_getticks); - bool rem_itpm = itpm; - u16 vendor = ioread16(chip->vendor.iobase + TPM_DID_VID(0)); - - /* probe only iTPMS */ - if (vendor != TPM_VID_INTEL) - return 0; + int rem_itpm = itpm; itpm = 0; @@ -395,6 +390,9 @@ static int probe_itpm(struct tpm_chip *chip) out: itpm = rem_itpm; tpm_tis_ready(chip); + /* some TPMs need a break here otherwise they will not work + * correctly on the immediately subsequent command */ + msleep(chip->vendor.timeout_b); release_locality(chip, chip->vendor.locality, 0); return rc; @@ -510,7 +508,7 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, resource_size_t len, unsigned int irq) { u32 vendor, intfcaps, intmask; - int rc, i, irq_s, irq_e, probe; + int rc, i, irq_s, irq_e; struct tpm_chip *chip; if (!(chip = tpm_register_hardware(dev, &tpm_tis))) @@ -540,12 +538,11 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); if (!itpm) { - probe = probe_itpm(chip); - if (probe < 0) { + itpm = probe_itpm(chip); + if (itpm < 0) { rc = -ENODEV; goto out_err; } - itpm = (probe == 0) ? 0 : 1; } if (itpm) diff --git a/trunk/drivers/char/viotape.c b/trunk/drivers/char/viotape.c new file mode 100644 index 000000000000..8b34c65511eb --- /dev/null +++ b/trunk/drivers/char/viotape.c @@ -0,0 +1,1041 @@ +/* -*- linux-c -*- + * drivers/char/viotape.c + * + * iSeries Virtual Tape + * + * Authors: Dave Boutcher + * Ryan Arnold + * Colin Devilbiss + * Stephen Rothwell + * + * (C) Copyright 2000-2004 IBM Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) anyu later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This routine provides access to tape drives owned and managed by an OS/400 + * partition running on the same box as this Linux partition. + * + * All tape operations are performed by sending messages back and forth to + * the OS/400 partition. The format of the messages is defined in + * iseries/vio.h + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define VIOTAPE_VERSION "1.2" +#define VIOTAPE_MAXREQ 1 + +#define VIOTAPE_KERN_WARN KERN_WARNING "viotape: " +#define VIOTAPE_KERN_INFO KERN_INFO "viotape: " + +static DEFINE_MUTEX(proc_viotape_mutex); +static int viotape_numdev; + +/* + * The minor number follows the conventions of the SCSI tape drives. The + * rewind and mode are encoded in the minor #. We use this struct to break + * them out + */ +struct viot_devinfo_struct { + int devno; + int mode; + int rewind; +}; + +#define VIOTAPOP_RESET 0 +#define VIOTAPOP_FSF 1 +#define VIOTAPOP_BSF 2 +#define VIOTAPOP_FSR 3 +#define VIOTAPOP_BSR 4 +#define VIOTAPOP_WEOF 5 +#define VIOTAPOP_REW 6 +#define VIOTAPOP_NOP 7 +#define VIOTAPOP_EOM 8 +#define VIOTAPOP_ERASE 9 +#define VIOTAPOP_SETBLK 10 +#define VIOTAPOP_SETDENSITY 11 +#define VIOTAPOP_SETPOS 12 +#define VIOTAPOP_GETPOS 13 +#define VIOTAPOP_SETPART 14 +#define VIOTAPOP_UNLOAD 15 + +enum viotaperc { + viotape_InvalidRange = 0x0601, + viotape_InvalidToken = 0x0602, + viotape_DMAError = 0x0603, + viotape_UseError = 0x0604, + viotape_ReleaseError = 0x0605, + viotape_InvalidTape = 0x0606, + viotape_InvalidOp = 0x0607, + viotape_TapeErr = 0x0608, + + viotape_AllocTimedOut = 0x0640, + viotape_BOTEnc = 0x0641, + viotape_BlankTape = 0x0642, + viotape_BufferEmpty = 0x0643, + viotape_CleanCartFound = 0x0644, + viotape_CmdNotAllowed = 0x0645, + viotape_CmdNotSupported = 0x0646, + viotape_DataCheck = 0x0647, + viotape_DecompressErr = 0x0648, + viotape_DeviceTimeout = 0x0649, + viotape_DeviceUnavail = 0x064a, + viotape_DeviceBusy = 0x064b, + viotape_EndOfMedia = 0x064c, + viotape_EndOfTape = 0x064d, + viotape_EquipCheck = 0x064e, + viotape_InsufficientRs = 0x064f, + viotape_InvalidLogBlk = 0x0650, + viotape_LengthError = 0x0651, + viotape_LibDoorOpen = 0x0652, + viotape_LoadFailure = 0x0653, + viotape_NotCapable = 0x0654, + viotape_NotOperational = 0x0655, + viotape_NotReady = 0x0656, + viotape_OpCancelled = 0x0657, + viotape_PhyLinkErr = 0x0658, + viotape_RdyNotBOT = 0x0659, + viotape_TapeMark = 0x065a, + viotape_WriteProt = 0x065b +}; + +static const struct vio_error_entry viotape_err_table[] = { + { viotape_InvalidRange, EIO, "Internal error" }, + { viotape_InvalidToken, EIO, "Internal error" }, + { viotape_DMAError, EIO, "DMA error" }, + { viotape_UseError, EIO, "Internal error" }, + { viotape_ReleaseError, EIO, "Internal error" }, + { viotape_InvalidTape, EIO, "Invalid tape device" }, + { viotape_InvalidOp, EIO, "Invalid operation" }, + { viotape_TapeErr, EIO, "Tape error" }, + { viotape_AllocTimedOut, EBUSY, "Allocate timed out" }, + { viotape_BOTEnc, EIO, "Beginning of tape encountered" }, + { viotape_BlankTape, EIO, "Blank tape" }, + { viotape_BufferEmpty, EIO, "Buffer empty" }, + { viotape_CleanCartFound, ENOMEDIUM, "Cleaning cartridge found" }, + { viotape_CmdNotAllowed, EIO, "Command not allowed" }, + { viotape_CmdNotSupported, EIO, "Command not supported" }, + { viotape_DataCheck, EIO, "Data check" }, + { viotape_DecompressErr, EIO, "Decompression error" }, + { viotape_DeviceTimeout, EBUSY, "Device timeout" }, + { viotape_DeviceUnavail, EIO, "Device unavailable" }, + { viotape_DeviceBusy, EBUSY, "Device busy" }, + { viotape_EndOfMedia, ENOSPC, "End of media" }, + { viotape_EndOfTape, ENOSPC, "End of tape" }, + { viotape_EquipCheck, EIO, "Equipment check" }, + { viotape_InsufficientRs, EOVERFLOW, "Insufficient tape resources" }, + { viotape_InvalidLogBlk, EIO, "Invalid logical block location" }, + { viotape_LengthError, EOVERFLOW, "Length error" }, + { viotape_LibDoorOpen, EBUSY, "Door open" }, + { viotape_LoadFailure, ENOMEDIUM, "Load failure" }, + { viotape_NotCapable, EIO, "Not capable" }, + { viotape_NotOperational, EIO, "Not operational" }, + { viotape_NotReady, EIO, "Not ready" }, + { viotape_OpCancelled, EIO, "Operation cancelled" }, + { viotape_PhyLinkErr, EIO, "Physical link error" }, + { viotape_RdyNotBOT, EIO, "Ready but not beginning of tape" }, + { viotape_TapeMark, EIO, "Tape mark" }, + { viotape_WriteProt, EROFS, "Write protection error" }, + { 0, 0, NULL }, +}; + +/* Maximum number of tapes we support */ +#define VIOTAPE_MAX_TAPE HVMAXARCHITECTEDVIRTUALTAPES +#define MAX_PARTITIONS 4 + +/* defines for current tape state */ +#define VIOT_IDLE 0 +#define VIOT_READING 1 +#define VIOT_WRITING 2 + +/* Our info on the tapes */ +static struct { + const char *rsrcname; + const char *type; + const char *model; +} viotape_unitinfo[VIOTAPE_MAX_TAPE]; + +static struct mtget viomtget[VIOTAPE_MAX_TAPE]; + +static struct class *tape_class; + +static struct device *tape_device[VIOTAPE_MAX_TAPE]; + +/* + * maintain the current state of each tape (and partition) + * so that we know when to write EOF marks. + */ +static struct { + unsigned char cur_part; + unsigned char part_stat_rwi[MAX_PARTITIONS]; +} state[VIOTAPE_MAX_TAPE]; + +/* We single-thread */ +static struct semaphore reqSem; + +/* + * When we send a request, we use this struct to get the response back + * from the interrupt handler + */ +struct op_struct { + void *buffer; + dma_addr_t dmaaddr; + size_t count; + int rc; + int non_blocking; + struct completion com; + struct device *dev; + struct op_struct *next; +}; + +static spinlock_t op_struct_list_lock; +static struct op_struct *op_struct_list; + +/* forward declaration to resolve interdependence */ +static int chg_state(int index, unsigned char new_state, struct file *file); + +/* procfs support */ +static int proc_viotape_show(struct seq_file *m, void *v) +{ + int i; + + seq_printf(m, "viotape driver version " VIOTAPE_VERSION "\n"); + for (i = 0; i < viotape_numdev; i++) { + seq_printf(m, "viotape device %d is iSeries resource %10.10s" + "type %4.4s, model %3.3s\n", + i, viotape_unitinfo[i].rsrcname, + viotape_unitinfo[i].type, + viotape_unitinfo[i].model); + } + return 0; +} + +static int proc_viotape_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_viotape_show, NULL); +} + +static const struct file_operations proc_viotape_operations = { + .owner = THIS_MODULE, + .open = proc_viotape_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/* Decode the device minor number into its parts */ +void get_dev_info(struct inode *ino, struct viot_devinfo_struct *devi) +{ + devi->devno = iminor(ino) & 0x1F; + devi->mode = (iminor(ino) & 0x60) >> 5; + /* if bit is set in the minor, do _not_ rewind automatically */ + devi->rewind = (iminor(ino) & 0x80) == 0; +} + +/* This is called only from the exit and init paths, so no need for locking */ +static void clear_op_struct_pool(void) +{ + while (op_struct_list) { + struct op_struct *toFree = op_struct_list; + op_struct_list = op_struct_list->next; + kfree(toFree); + } +} + +/* Likewise, this is only called from the init path */ +static int add_op_structs(int structs) +{ + int i; + + for (i = 0; i < structs; ++i) { + struct op_struct *new_struct = + kmalloc(sizeof(*new_struct), GFP_KERNEL); + if (!new_struct) { + clear_op_struct_pool(); + return -ENOMEM; + } + new_struct->next = op_struct_list; + op_struct_list = new_struct; + } + return 0; +} + +/* Allocate an op structure from our pool */ +static struct op_struct *get_op_struct(void) +{ + struct op_struct *retval; + unsigned long flags; + + spin_lock_irqsave(&op_struct_list_lock, flags); + retval = op_struct_list; + if (retval) + op_struct_list = retval->next; + spin_unlock_irqrestore(&op_struct_list_lock, flags); + if (retval) { + memset(retval, 0, sizeof(*retval)); + init_completion(&retval->com); + } + + return retval; +} + +/* Return an op structure to our pool */ +static void free_op_struct(struct op_struct *op_struct) +{ + unsigned long flags; + + spin_lock_irqsave(&op_struct_list_lock, flags); + op_struct->next = op_struct_list; + op_struct_list = op_struct; + spin_unlock_irqrestore(&op_struct_list_lock, flags); +} + +/* Map our tape return codes to errno values */ +int tape_rc_to_errno(int tape_rc, char *operation, int tapeno) +{ + const struct vio_error_entry *err; + + if (tape_rc == 0) + return 0; + + err = vio_lookup_rc(viotape_err_table, tape_rc); + printk(VIOTAPE_KERN_WARN "error(%s) 0x%04x on Device %d (%-10s): %s\n", + operation, tape_rc, tapeno, + viotape_unitinfo[tapeno].rsrcname, err->msg); + return -err->errno; +} + +/* Write */ +static ssize_t viotap_write(struct file *file, const char *buf, + size_t count, loff_t * ppos) +{ + HvLpEvent_Rc hvrc; + unsigned short flags = file->f_flags; + int noblock = ((flags & O_NONBLOCK) != 0); + ssize_t ret; + struct viot_devinfo_struct devi; + struct op_struct *op = get_op_struct(); + + if (op == NULL) + return -ENOMEM; + + get_dev_info(file->f_path.dentry->d_inode, &devi); + + /* + * We need to make sure we can send a request. We use + * a semaphore to keep track of # requests in use. If + * we are non-blocking, make sure we don't block on the + * semaphore + */ + if (noblock) { + if (down_trylock(&reqSem)) { + ret = -EWOULDBLOCK; + goto free_op; + } + } else + down(&reqSem); + + /* Allocate a DMA buffer */ + op->dev = tape_device[devi.devno]; + op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr, + GFP_ATOMIC); + + if (op->buffer == NULL) { + printk(VIOTAPE_KERN_WARN + "error allocating dma buffer for len %ld\n", + count); + ret = -EFAULT; + goto up_sem; + } + + /* Copy the data into the buffer */ + if (copy_from_user(op->buffer, buf, count)) { + printk(VIOTAPE_KERN_WARN "tape: error on copy from user\n"); + ret = -EFAULT; + goto free_dma; + } + + op->non_blocking = noblock; + init_completion(&op->com); + op->count = count; + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapewrite, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)op, VIOVERSION << 16, + ((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(VIOTAPE_KERN_WARN "hv error on op %d\n", + (int)hvrc); + ret = -EIO; + goto free_dma; + } + + if (noblock) + return count; + + wait_for_completion(&op->com); + + if (op->rc) + ret = tape_rc_to_errno(op->rc, "write", devi.devno); + else { + chg_state(devi.devno, VIOT_WRITING, file); + ret = op->count; + } + +free_dma: + dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr); +up_sem: + up(&reqSem); +free_op: + free_op_struct(op); + return ret; +} + +/* read */ +static ssize_t viotap_read(struct file *file, char *buf, size_t count, + loff_t *ptr) +{ + HvLpEvent_Rc hvrc; + unsigned short flags = file->f_flags; + struct op_struct *op = get_op_struct(); + int noblock = ((flags & O_NONBLOCK) != 0); + ssize_t ret; + struct viot_devinfo_struct devi; + + if (op == NULL) + return -ENOMEM; + + get_dev_info(file->f_path.dentry->d_inode, &devi); + + /* + * We need to make sure we can send a request. We use + * a semaphore to keep track of # requests in use. If + * we are non-blocking, make sure we don't block on the + * semaphore + */ + if (noblock) { + if (down_trylock(&reqSem)) { + ret = -EWOULDBLOCK; + goto free_op; + } + } else + down(&reqSem); + + chg_state(devi.devno, VIOT_READING, file); + + /* Allocate a DMA buffer */ + op->dev = tape_device[devi.devno]; + op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr, + GFP_ATOMIC); + if (op->buffer == NULL) { + ret = -EFAULT; + goto up_sem; + } + + op->count = count; + init_completion(&op->com); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotaperead, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)op, VIOVERSION << 16, + ((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(VIOTAPE_KERN_WARN "tape hv error on op %d\n", + (int)hvrc); + ret = -EIO; + goto free_dma; + } + + wait_for_completion(&op->com); + + if (op->rc) + ret = tape_rc_to_errno(op->rc, "read", devi.devno); + else { + ret = op->count; + if (ret && copy_to_user(buf, op->buffer, ret)) { + printk(VIOTAPE_KERN_WARN "error on copy_to_user\n"); + ret = -EFAULT; + } + } + +free_dma: + dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr); +up_sem: + up(&reqSem); +free_op: + free_op_struct(op); + return ret; +} + +/* ioctl */ +static int viotap_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + HvLpEvent_Rc hvrc; + int ret; + struct viot_devinfo_struct devi; + struct mtop mtc; + u32 myOp; + struct op_struct *op = get_op_struct(); + + if (op == NULL) + return -ENOMEM; + + get_dev_info(file->f_path.dentry->d_inode, &devi); + + down(&reqSem); + + ret = -EINVAL; + + switch (cmd) { + case MTIOCTOP: + ret = -EFAULT; + /* + * inode is null if and only if we (the kernel) + * made the request + */ + if (inode == NULL) + memcpy(&mtc, (void *) arg, sizeof(struct mtop)); + else if (copy_from_user((char *)&mtc, (char *)arg, + sizeof(struct mtop))) + goto free_op; + + ret = -EIO; + switch (mtc.mt_op) { + case MTRESET: + myOp = VIOTAPOP_RESET; + break; + case MTFSF: + myOp = VIOTAPOP_FSF; + break; + case MTBSF: + myOp = VIOTAPOP_BSF; + break; + case MTFSR: + myOp = VIOTAPOP_FSR; + break; + case MTBSR: + myOp = VIOTAPOP_BSR; + break; + case MTWEOF: + myOp = VIOTAPOP_WEOF; + break; + case MTREW: + myOp = VIOTAPOP_REW; + break; + case MTNOP: + myOp = VIOTAPOP_NOP; + break; + case MTEOM: + myOp = VIOTAPOP_EOM; + break; + case MTERASE: + myOp = VIOTAPOP_ERASE; + break; + case MTSETBLK: + myOp = VIOTAPOP_SETBLK; + break; + case MTSETDENSITY: + myOp = VIOTAPOP_SETDENSITY; + break; + case MTTELL: + myOp = VIOTAPOP_GETPOS; + break; + case MTSEEK: + myOp = VIOTAPOP_SETPOS; + break; + case MTSETPART: + myOp = VIOTAPOP_SETPART; + break; + case MTOFFL: + myOp = VIOTAPOP_UNLOAD; + break; + default: + printk(VIOTAPE_KERN_WARN "MTIOCTOP called " + "with invalid op 0x%x\n", mtc.mt_op); + goto free_op; + } + + /* + * if we moved the head, we are no longer + * reading or writing + */ + switch (mtc.mt_op) { + case MTFSF: + case MTBSF: + case MTFSR: + case MTBSR: + case MTTELL: + case MTSEEK: + case MTREW: + chg_state(devi.devno, VIOT_IDLE, file); + } + + init_completion(&op->com); + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapeop, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)op, + VIOVERSION << 16, + ((u64)devi.devno << 48), 0, + (((u64)myOp) << 32) | mtc.mt_count, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(VIOTAPE_KERN_WARN "hv error on op %d\n", + (int)hvrc); + goto free_op; + } + wait_for_completion(&op->com); + ret = tape_rc_to_errno(op->rc, "tape operation", devi.devno); + goto free_op; + + case MTIOCGET: + ret = -EIO; + init_completion(&op->com); + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapegetstatus, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)op, VIOVERSION << 16, + ((u64)devi.devno << 48), 0, 0, 0); + if (hvrc != HvLpEvent_Rc_Good) { + printk(VIOTAPE_KERN_WARN "hv error on op %d\n", + (int)hvrc); + goto free_op; + } + wait_for_completion(&op->com); + + /* Operation is complete - grab the error code */ + ret = tape_rc_to_errno(op->rc, "get status", devi.devno); + free_op_struct(op); + up(&reqSem); + + if ((ret == 0) && copy_to_user((void *)arg, + &viomtget[devi.devno], + sizeof(viomtget[0]))) + ret = -EFAULT; + return ret; + case MTIOCPOS: + printk(VIOTAPE_KERN_WARN "Got an (unsupported) MTIOCPOS\n"); + break; + default: + printk(VIOTAPE_KERN_WARN "got an unsupported ioctl 0x%0x\n", + cmd); + break; + } + +free_op: + free_op_struct(op); + up(&reqSem); + return ret; +} + +static long viotap_unlocked_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + long rc; + + mutex_lock(&proc_viotape_mutex); + rc = viotap_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); + mutex_unlock(&proc_viotape_mutex); + return rc; +} + +static int viotap_open(struct inode *inode, struct file *file) +{ + HvLpEvent_Rc hvrc; + struct viot_devinfo_struct devi; + int ret; + struct op_struct *op = get_op_struct(); + + if (op == NULL) + return -ENOMEM; + + mutex_lock(&proc_viotape_mutex); + get_dev_info(file->f_path.dentry->d_inode, &devi); + + /* Note: We currently only support one mode! */ + if ((devi.devno >= viotape_numdev) || (devi.mode)) { + ret = -ENODEV; + goto free_op; + } + + init_completion(&op->com); + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapeopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)op, VIOVERSION << 16, + ((u64)devi.devno << 48), 0, 0, 0); + if (hvrc != 0) { + printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n", + (int) hvrc); + ret = -EIO; + goto free_op; + } + + wait_for_completion(&op->com); + ret = tape_rc_to_errno(op->rc, "open", devi.devno); + +free_op: + free_op_struct(op); + mutex_unlock(&proc_viotape_mutex); + return ret; +} + + +static int viotap_release(struct inode *inode, struct file *file) +{ + HvLpEvent_Rc hvrc; + struct viot_devinfo_struct devi; + int ret = 0; + struct op_struct *op = get_op_struct(); + + if (op == NULL) + return -ENOMEM; + init_completion(&op->com); + + get_dev_info(file->f_path.dentry->d_inode, &devi); + + if (devi.devno >= viotape_numdev) { + ret = -ENODEV; + goto free_op; + } + + chg_state(devi.devno, VIOT_IDLE, file); + + if (devi.rewind) { + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapeop, + HvLpEvent_AckInd_DoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)op, VIOVERSION << 16, + ((u64)devi.devno << 48), 0, + ((u64)VIOTAPOP_REW) << 32, 0); + wait_for_completion(&op->com); + + tape_rc_to_errno(op->rc, "rewind", devi.devno); + } + + hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_tape | viotapeclose, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + (u64)(unsigned long)op, VIOVERSION << 16, + ((u64)devi.devno << 48), 0, 0, 0); + if (hvrc != 0) { + printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n", + (int) hvrc); + ret = -EIO; + goto free_op; + } + + wait_for_completion(&op->com); + + if (op->rc) + printk(VIOTAPE_KERN_WARN "close failed\n"); + +free_op: + free_op_struct(op); + return ret; +} + +const struct file_operations viotap_fops = { + .owner = THIS_MODULE, + .read = viotap_read, + .write = viotap_write, + .unlocked_ioctl = viotap_unlocked_ioctl, + .open = viotap_open, + .release = viotap_release, + .llseek = noop_llseek, +}; + +/* Handle interrupt events for tape */ +static void vioHandleTapeEvent(struct HvLpEvent *event) +{ + int tapeminor; + struct op_struct *op; + struct viotapelpevent *tevent = (struct viotapelpevent *)event; + + if (event == NULL) { + /* Notification that a partition went away! */ + if (!viopath_isactive(viopath_hostLp)) { + /* TODO! Clean up */ + } + return; + } + + tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; + op = (struct op_struct *)event->xCorrelationToken; + switch (tapeminor) { + case viotapeopen: + case viotapeclose: + op->rc = tevent->sub_type_result; + complete(&op->com); + break; + case viotaperead: + op->rc = tevent->sub_type_result; + op->count = tevent->len; + complete(&op->com); + break; + case viotapewrite: + if (op->non_blocking) { + dma_free_coherent(op->dev, op->count, + op->buffer, op->dmaaddr); + free_op_struct(op); + up(&reqSem); + } else { + op->rc = tevent->sub_type_result; + op->count = tevent->len; + complete(&op->com); + } + break; + case viotapeop: + case viotapegetpos: + case viotapesetpos: + case viotapegetstatus: + if (op) { + op->count = tevent->u.op.count; + op->rc = tevent->sub_type_result; + if (!op->non_blocking) + complete(&op->com); + } + break; + default: + printk(VIOTAPE_KERN_WARN "weird ack\n"); + } +} + +static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) +{ + int i = vdev->unit_address; + int j; + struct device_node *node = vdev->dev.of_node; + + if (i >= VIOTAPE_MAX_TAPE) + return -ENODEV; + if (!node) + return -ENODEV; + + if (i >= viotape_numdev) + viotape_numdev = i + 1; + + tape_device[i] = &vdev->dev; + viotape_unitinfo[i].rsrcname = of_get_property(node, + "linux,vio_rsrcname", NULL); + viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type", + NULL); + viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model", + NULL); + + state[i].cur_part = 0; + for (j = 0; j < MAX_PARTITIONS; ++j) + state[i].part_stat_rwi[j] = VIOT_IDLE; + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, + "iseries!vt%d", i); + device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL, + "iseries!nvt%d", i); + printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries " + "resource %10.10s type %4.4s, model %3.3s\n", + i, viotape_unitinfo[i].rsrcname, + viotape_unitinfo[i].type, viotape_unitinfo[i].model); + return 0; +} + +static int viotape_remove(struct vio_dev *vdev) +{ + int i = vdev->unit_address; + + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); + device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); + return 0; +} + +/** + * viotape_device_table: Used by vio.c to match devices that we + * support. + */ +static struct vio_device_id viotape_device_table[] __devinitdata = { + { "byte", "IBM,iSeries-viotape" }, + { "", "" } +}; +MODULE_DEVICE_TABLE(vio, viotape_device_table); + +static struct vio_driver viotape_driver = { + .id_table = viotape_device_table, + .probe = viotape_probe, + .remove = viotape_remove, + .driver = { + .name = "viotape", + .owner = THIS_MODULE, + } +}; + + +int __init viotap_init(void) +{ + int ret; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -ENODEV; + + op_struct_list = NULL; + if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) { + printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n"); + return ret; + } + spin_lock_init(&op_struct_list_lock); + + sema_init(&reqSem, VIOTAPE_MAXREQ); + + if (viopath_hostLp == HvLpIndexInvalid) { + vio_set_hostlp(); + if (viopath_hostLp == HvLpIndexInvalid) { + ret = -ENODEV; + goto clear_op; + } + } + + ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, + VIOTAPE_MAXREQ + 2); + if (ret) { + printk(VIOTAPE_KERN_WARN + "error on viopath_open to hostlp %d\n", ret); + ret = -EIO; + goto clear_op; + } + + printk(VIOTAPE_KERN_INFO "vers " VIOTAPE_VERSION + ", hosting partition %d\n", viopath_hostLp); + + vio_setHandler(viomajorsubtype_tape, vioHandleTapeEvent); + + ret = register_chrdev(VIOTAPE_MAJOR, "viotape", &viotap_fops); + if (ret < 0) { + printk(VIOTAPE_KERN_WARN "Error registering viotape device\n"); + goto clear_handler; + } + + tape_class = class_create(THIS_MODULE, "tape"); + if (IS_ERR(tape_class)) { + printk(VIOTAPE_KERN_WARN "Unable to allocate class\n"); + ret = PTR_ERR(tape_class); + goto unreg_chrdev; + } + + ret = vio_register_driver(&viotape_driver); + if (ret) + goto unreg_class; + + proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL, + &proc_viotape_operations); + + return 0; + +unreg_class: + class_destroy(tape_class); +unreg_chrdev: + unregister_chrdev(VIOTAPE_MAJOR, "viotape"); +clear_handler: + vio_clearHandler(viomajorsubtype_tape); + viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); +clear_op: + clear_op_struct_pool(); + return ret; +} + +/* Give a new state to the tape object */ +static int chg_state(int index, unsigned char new_state, struct file *file) +{ + unsigned char *cur_state = + &state[index].part_stat_rwi[state[index].cur_part]; + int rc = 0; + + /* if the same state, don't bother */ + if (*cur_state == new_state) + return 0; + + /* write an EOF if changing from writing to some other state */ + if (*cur_state == VIOT_WRITING) { + struct mtop write_eof = { MTWEOF, 1 }; + + rc = viotap_ioctl(NULL, file, MTIOCTOP, + (unsigned long)&write_eof); + } + *cur_state = new_state; + return rc; +} + +/* Cleanup */ +static void __exit viotap_exit(void) +{ + remove_proc_entry("iSeries/viotape", NULL); + vio_unregister_driver(&viotape_driver); + class_destroy(tape_class); + unregister_chrdev(VIOTAPE_MAJOR, "viotape"); + viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); + vio_clearHandler(viomajorsubtype_tape); + clear_op_struct_pool(); +} + +MODULE_LICENSE("GPL"); +module_init(viotap_init); +module_exit(viotap_exit); diff --git a/trunk/drivers/crypto/Kconfig b/trunk/drivers/crypto/Kconfig index e707979767fb..6d16b4b0d7a0 100644 --- a/trunk/drivers/crypto/Kconfig +++ b/trunk/drivers/crypto/Kconfig @@ -293,15 +293,4 @@ config CRYPTO_DEV_S5P Select this to offload Samsung S5PV210 or S5PC110 from AES algorithms execution. -config CRYPTO_DEV_TEGRA_AES - tristate "Support for TEGRA AES hw engine" - depends on ARCH_TEGRA - select CRYPTO_AES - help - TEGRA processors have AES module accelerator. Select this if you - want to use the TEGRA module for AES algorithms. - - To compile this driver as a module, choose M here: the module - will be called tegra-aes. - endif # CRYPTO_HW diff --git a/trunk/drivers/crypto/Makefile b/trunk/drivers/crypto/Makefile index f3e64eadd7af..53ea50155319 100644 --- a/trunk/drivers/crypto/Makefile +++ b/trunk/drivers/crypto/Makefile @@ -13,4 +13,3 @@ obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o -obj-$(CONFIG_CRYPTO_DEV_TEGRA_AES) += tegra-aes.o diff --git a/trunk/drivers/crypto/caam/caamalg.c b/trunk/drivers/crypto/caam/caamalg.c index 534a36469d57..e73cf2e8110a 100644 --- a/trunk/drivers/crypto/caam/caamalg.c +++ b/trunk/drivers/crypto/caam/caamalg.c @@ -1843,25 +1843,6 @@ static struct caam_alg_template driver_algs[] = { .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, - { - .name = "authenc(hmac(sha224),cbc(aes))", - .driver_name = "authenc-hmac-sha224-cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA224_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, - }, { .name = "authenc(hmac(sha256),cbc(aes))", .driver_name = "authenc-hmac-sha256-cbc-aes-caam", @@ -1882,26 +1863,6 @@ static struct caam_alg_template driver_algs[] = { OP_ALG_AAI_HMAC_PRECOMP, .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, - { - .name = "authenc(hmac(sha384),cbc(aes))", - .driver_name = "authenc-hmac-sha384-cbc-aes-caam", - .blocksize = AES_BLOCK_SIZE, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = AES_BLOCK_SIZE, - .maxauthsize = SHA384_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, - }, - { .name = "authenc(hmac(sha512),cbc(aes))", .driver_name = "authenc-hmac-sha512-cbc-aes-caam", @@ -1960,25 +1921,6 @@ static struct caam_alg_template driver_algs[] = { .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, - { - .name = "authenc(hmac(sha224),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha224-cbc-des3_ede-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA224_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, - }, { .name = "authenc(hmac(sha256),cbc(des3_ede))", .driver_name = "authenc-hmac-sha256-cbc-des3_ede-caam", @@ -1999,25 +1941,6 @@ static struct caam_alg_template driver_algs[] = { OP_ALG_AAI_HMAC_PRECOMP, .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, - { - .name = "authenc(hmac(sha384),cbc(des3_ede))", - .driver_name = "authenc-hmac-sha384-cbc-des3_ede-caam", - .blocksize = DES3_EDE_BLOCK_SIZE, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = DES3_EDE_BLOCK_SIZE, - .maxauthsize = SHA384_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, - }, { .name = "authenc(hmac(sha512),cbc(des3_ede))", .driver_name = "authenc-hmac-sha512-cbc-des3_ede-caam", @@ -2076,25 +1999,6 @@ static struct caam_alg_template driver_algs[] = { .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, - { - .name = "authenc(hmac(sha224),cbc(des))", - .driver_name = "authenc-hmac-sha224-cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = DES_BLOCK_SIZE, - .maxauthsize = SHA224_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA224 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, - }, { .name = "authenc(hmac(sha256),cbc(des))", .driver_name = "authenc-hmac-sha256-cbc-des-caam", @@ -2115,25 +2019,6 @@ static struct caam_alg_template driver_algs[] = { OP_ALG_AAI_HMAC_PRECOMP, .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, - { - .name = "authenc(hmac(sha384),cbc(des))", - .driver_name = "authenc-hmac-sha384-cbc-des-caam", - .blocksize = DES_BLOCK_SIZE, - .template_aead = { - .setkey = aead_setkey, - .setauthsize = aead_setauthsize, - .encrypt = aead_encrypt, - .decrypt = aead_decrypt, - .givencrypt = aead_givencrypt, - .geniv = "", - .ivsize = DES_BLOCK_SIZE, - .maxauthsize = SHA384_DIGEST_SIZE, - }, - .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, - .class2_alg_type = OP_ALG_ALGSEL_SHA384 | - OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, - }, { .name = "authenc(hmac(sha512),cbc(des))", .driver_name = "authenc-hmac-sha512-cbc-des-caam", @@ -2320,8 +2205,7 @@ static struct caam_crypto_alg *caam_alg_alloc(struct device *ctrldev, alg->cra_blocksize = template->blocksize; alg->cra_alignmask = 0; alg->cra_ctxsize = sizeof(struct caam_ctx); - alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | - template->type; + alg->cra_flags = CRYPTO_ALG_ASYNC | template->type; switch (template->type) { case CRYPTO_ALG_TYPE_ABLKCIPHER: alg->cra_type = &crypto_ablkcipher_type; @@ -2401,12 +2285,12 @@ static int __init caam_algapi_init(void) dev_warn(ctrldev, "%s alg registration failed\n", t_alg->crypto_alg.cra_driver_name); kfree(t_alg); - } else + } else { list_add_tail(&t_alg->entry, &priv->alg_list); + dev_info(ctrldev, "%s\n", + t_alg->crypto_alg.cra_driver_name); + } } - if (!list_empty(&priv->alg_list)) - dev_info(ctrldev, "%s algorithms registered in /proc/crypto\n", - (char *)of_get_property(dev_node, "compatible", NULL)); return err; } diff --git a/trunk/drivers/crypto/caam/ctrl.c b/trunk/drivers/crypto/caam/ctrl.c index c5f61c55d923..8ae3ba2a160d 100644 --- a/trunk/drivers/crypto/caam/ctrl.c +++ b/trunk/drivers/crypto/caam/ctrl.c @@ -46,7 +46,7 @@ static int caam_remove(struct platform_device *pdev) /* Probe routine for CAAM top (controller) level */ static int caam_probe(struct platform_device *pdev) { - int ring, rspec; + int d, ring, rspec; struct device *dev; struct device_node *nprop, *np; struct caam_ctrl __iomem *ctrl; diff --git a/trunk/drivers/crypto/geode-aes.c b/trunk/drivers/crypto/geode-aes.c index f3e36c86b6c3..219d09cbb0d1 100644 --- a/trunk/drivers/crypto/geode-aes.c +++ b/trunk/drivers/crypto/geode-aes.c @@ -393,8 +393,7 @@ static struct crypto_alg geode_cbc_alg = { .cra_driver_name = "cbc-aes-geode", .cra_priority = 400, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_NEED_FALLBACK, .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, @@ -480,8 +479,7 @@ static struct crypto_alg geode_ecb_alg = { .cra_driver_name = "ecb-aes-geode", .cra_priority = 400, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_NEED_FALLBACK, .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, diff --git a/trunk/drivers/crypto/hifn_795x.c b/trunk/drivers/crypto/hifn_795x.c index c9c4befb5a8d..76368f984023 100644 --- a/trunk/drivers/crypto/hifn_795x.c +++ b/trunk/drivers/crypto/hifn_795x.c @@ -2494,8 +2494,7 @@ static int hifn_alg_alloc(struct hifn_device *dev, struct hifn_alg_template *t) t->drv_name, dev->name); alg->alg.cra_priority = 300; - alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; + alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; alg->alg.cra_blocksize = t->bsize; alg->alg.cra_ctxsize = sizeof(struct hifn_context); alg->alg.cra_alignmask = 0; diff --git a/trunk/drivers/crypto/ixp4xx_crypto.c b/trunk/drivers/crypto/ixp4xx_crypto.c index 0053d7ebb5ca..4c20c5bf6058 100644 --- a/trunk/drivers/crypto/ixp4xx_crypto.c +++ b/trunk/drivers/crypto/ixp4xx_crypto.c @@ -265,7 +265,7 @@ static int setup_crypt_desc(void) BUILD_BUG_ON(sizeof(struct crypt_ctl) != 64); crypt_virt = dma_alloc_coherent(dev, NPE_QLEN * sizeof(struct crypt_ctl), - &crypt_phys, GFP_ATOMIC); + &crypt_phys, GFP_KERNEL); if (!crypt_virt) return -ENOMEM; memset(crypt_virt, 0, NPE_QLEN * sizeof(struct crypt_ctl)); @@ -1449,7 +1449,6 @@ static int __init ixp_module_init(void) /* block ciphers */ cra->cra_type = &crypto_ablkcipher_type; cra->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; if (!cra->cra_ablkcipher.setkey) cra->cra_ablkcipher.setkey = ablk_setkey; @@ -1462,7 +1461,6 @@ static int __init ixp_module_init(void) /* authenc */ cra->cra_type = &crypto_aead_type; cra->cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; cra->cra_aead.setkey = aead_setkey; cra->cra_aead.setauthsize = aead_setauthsize; diff --git a/trunk/drivers/crypto/mv_cesa.c b/trunk/drivers/crypto/mv_cesa.c index e6ecc5f23943..0d40cf66b3cc 100644 --- a/trunk/drivers/crypto/mv_cesa.c +++ b/trunk/drivers/crypto/mv_cesa.c @@ -899,8 +899,7 @@ struct crypto_alg mv_aes_alg_ecb = { .cra_name = "ecb(aes)", .cra_driver_name = "mv-ecb-aes", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = 16, .cra_ctxsize = sizeof(struct mv_ctx), .cra_alignmask = 0, @@ -922,8 +921,7 @@ struct crypto_alg mv_aes_alg_cbc = { .cra_name = "cbc(aes)", .cra_driver_name = "mv-cbc-aes", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct mv_ctx), .cra_alignmask = 0, @@ -955,8 +953,7 @@ struct ahash_alg mv_sha1_alg = { .cra_driver_name = "mv-sha1", .cra_priority = 300, .cra_flags = - CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct mv_tfm_hash_ctx), .cra_init = mv_cra_hash_sha1_init, @@ -980,8 +977,7 @@ struct ahash_alg mv_hmac_sha1_alg = { .cra_driver_name = "mv-hmac-sha1", .cra_priority = 300, .cra_flags = - CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct mv_tfm_hash_ctx), .cra_init = mv_cra_hash_hmac_sha1_init, diff --git a/trunk/drivers/crypto/n2_core.c b/trunk/drivers/crypto/n2_core.c index 67b97c5fd859..8944dabc0e3c 100644 --- a/trunk/drivers/crypto/n2_core.c +++ b/trunk/drivers/crypto/n2_core.c @@ -1402,8 +1402,7 @@ static int __devinit __n2_register_one_cipher(const struct n2_cipher_tmpl *tmpl) snprintf(alg->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); snprintf(alg->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->drv_name); alg->cra_priority = N2_CRA_PRIORITY; - alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; + alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC; alg->cra_blocksize = tmpl->block_size; p->enc_type = tmpl->enc_type; alg->cra_ctxsize = sizeof(struct n2_cipher_context); @@ -1494,9 +1493,7 @@ static int __devinit __n2_register_one_ahash(const struct n2_hash_tmpl *tmpl) snprintf(base->cra_name, CRYPTO_MAX_ALG_NAME, "%s", tmpl->name); snprintf(base->cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s-n2", tmpl->name); base->cra_priority = N2_CRA_PRIORITY; - base->cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_NEED_FALLBACK; + base->cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK; base->cra_blocksize = tmpl->block_size; base->cra_ctxsize = sizeof(struct n2_hash_ctx); base->cra_module = THIS_MODULE; diff --git a/trunk/drivers/crypto/omap-aes.c b/trunk/drivers/crypto/omap-aes.c index 63e57b57a12c..5b970d9e9956 100644 --- a/trunk/drivers/crypto/omap-aes.c +++ b/trunk/drivers/crypto/omap-aes.c @@ -756,9 +756,7 @@ static struct crypto_alg algs[] = { .cra_name = "ecb(aes)", .cra_driver_name = "ecb-aes-omap", .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), .cra_alignmask = 0, @@ -778,9 +776,7 @@ static struct crypto_alg algs[] = { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-omap", .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | - CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), .cra_alignmask = 0, diff --git a/trunk/drivers/crypto/omap-sham.c b/trunk/drivers/crypto/omap-sham.c index a3fd6fc504b1..6399a8f1938a 100644 --- a/trunk/drivers/crypto/omap-sham.c +++ b/trunk/drivers/crypto/omap-sham.c @@ -953,7 +953,6 @@ static struct ahash_alg algs[] = { .cra_driver_name = "omap-sha1", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, @@ -976,7 +975,6 @@ static struct ahash_alg algs[] = { .cra_driver_name = "omap-md5", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, @@ -1000,7 +998,6 @@ static struct ahash_alg algs[] = { .cra_driver_name = "omap-hmac-sha1", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, @@ -1025,7 +1022,6 @@ static struct ahash_alg algs[] = { .cra_driver_name = "omap-hmac-md5", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_AHASH | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, diff --git a/trunk/drivers/crypto/picoxcell_crypto.c b/trunk/drivers/crypto/picoxcell_crypto.c index 410a03c01ca4..58480d009324 100644 --- a/trunk/drivers/crypto/picoxcell_crypto.c +++ b/trunk/drivers/crypto/picoxcell_crypto.c @@ -1322,7 +1322,6 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_driver_name = "cbc-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, @@ -1350,7 +1349,6 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_driver_name = "ecb-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), @@ -1375,9 +1373,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "cbc(des)", .cra_driver_name = "cbc-des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1402,9 +1398,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "ecb(des)", .cra_driver_name = "ecb-des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1428,9 +1422,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "cbc(des3_ede)", .cra_driver_name = "cbc-des3-ede-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1455,9 +1447,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "ecb(des3_ede)", .cra_driver_name = "ecb-des3-ede-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1482,9 +1472,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(sha1),cbc(aes))", .cra_driver_name = "authenc-hmac-sha1-cbc-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1512,9 +1500,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(sha256),cbc(aes))", .cra_driver_name = "authenc-hmac-sha256-cbc-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1541,9 +1527,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(md5),cbc(aes))", .cra_driver_name = "authenc-hmac-md5-cbc-aes-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1570,9 +1554,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(sha1),cbc(des3_ede))", .cra_driver_name = "authenc-hmac-sha1-cbc-3des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1600,9 +1582,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(sha256),cbc(des3_ede))", .cra_driver_name = "authenc-hmac-sha256-cbc-3des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1629,9 +1609,7 @@ static struct spacc_alg ipsec_engine_algs[] = { .cra_name = "authenc(hmac(md5),cbc(des3_ede))", .cra_driver_name = "authenc-hmac-md5-cbc-3des-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_AEAD | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1661,9 +1639,7 @@ static struct spacc_alg l2_engine_algs[] = { .cra_name = "f8(kasumi)", .cra_driver_name = "f8-kasumi-picoxcell", .cra_priority = SPACC_CRYPTO_ALG_PRIORITY, - .cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + .cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | CRYPTO_ALG_ASYNC, .cra_blocksize = 8, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, diff --git a/trunk/drivers/crypto/s5p-sss.c b/trunk/drivers/crypto/s5p-sss.c index bc986f806086..3376bca200fc 100644 --- a/trunk/drivers/crypto/s5p-sss.c +++ b/trunk/drivers/crypto/s5p-sss.c @@ -518,8 +518,7 @@ static struct crypto_alg algs[] = { .cra_driver_name = "ecb-aes-s5p", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s5p_aes_ctx), .cra_alignmask = 0x0f, @@ -539,8 +538,7 @@ static struct crypto_alg algs[] = { .cra_driver_name = "cbc-aes-s5p", .cra_priority = 100, .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | - CRYPTO_ALG_ASYNC | - CRYPTO_ALG_KERN_DRIVER_ONLY, + CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s5p_aes_ctx), .cra_alignmask = 0x0f, diff --git a/trunk/drivers/crypto/talitos.c b/trunk/drivers/crypto/talitos.c index dc641c796526..2d8c78901686 100644 --- a/trunk/drivers/crypto/talitos.c +++ b/trunk/drivers/crypto/talitos.c @@ -2648,7 +2648,6 @@ static struct talitos_crypto_alg *talitos_alg_alloc(struct device *dev, alg->cra_priority = TALITOS_CRA_PRIORITY; alg->cra_alignmask = 0; alg->cra_ctxsize = sizeof(struct talitos_ctx); - alg->cra_flags |= CRYPTO_ALG_KERN_DRIVER_ONLY; t_alg->dev = dev; diff --git a/trunk/drivers/crypto/tegra-aes.c b/trunk/drivers/crypto/tegra-aes.c deleted file mode 100644 index 422a9766c7c9..000000000000 --- a/trunk/drivers/crypto/tegra-aes.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* - * drivers/crypto/tegra-aes.c - * - * Driver for NVIDIA Tegra AES hardware engine residing inside the - * Bit Stream Engine for Video (BSEV) hardware block. - * - * The programming sequence for this engine is with the help - * of commands which travel via a command queue residing between the - * CPU and the BSEV block. The BSEV engine has an internal RAM (VRAM) - * where the final input plaintext, keys and the IV have to be copied - * before starting the encrypt/decrypt operation. - * - * Copyright (c) 2010, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "tegra-aes.h" - -#define FLAGS_MODE_MASK 0x00FF -#define FLAGS_ENCRYPT BIT(0) -#define FLAGS_CBC BIT(1) -#define FLAGS_GIV BIT(2) -#define FLAGS_RNG BIT(3) -#define FLAGS_OFB BIT(4) -#define FLAGS_NEW_KEY BIT(5) -#define FLAGS_NEW_IV BIT(6) -#define FLAGS_INIT BIT(7) -#define FLAGS_FAST BIT(8) -#define FLAGS_BUSY 9 - -/* - * Defines AES engine Max process bytes size in one go, which takes 1 msec. - * AES engine spends about 176 cycles/16-bytes or 11 cycles/byte - * The duration CPU can use the BSE to 1 msec, then the number of available - * cycles of AVP/BSE is 216K. In this duration, AES can process 216/11 ~= 19KB - * Based on this AES_HW_DMA_BUFFER_SIZE_BYTES is configured to 16KB. - */ -#define AES_HW_DMA_BUFFER_SIZE_BYTES 0x4000 - -/* - * The key table length is 64 bytes - * (This includes first upto 32 bytes key + 16 bytes original initial vector - * and 16 bytes updated initial vector) - */ -#define AES_HW_KEY_TABLE_LENGTH_BYTES 64 - -/* - * The memory being used is divides as follows: - * 1. Key - 32 bytes - * 2. Original IV - 16 bytes - * 3. Updated IV - 16 bytes - * 4. Key schedule - 256 bytes - * - * 1+2+3 constitute the hw key table. - */ -#define AES_HW_IV_SIZE 16 -#define AES_HW_KEYSCHEDULE_LEN 256 -#define AES_IVKEY_SIZE (AES_HW_KEY_TABLE_LENGTH_BYTES + AES_HW_KEYSCHEDULE_LEN) - -/* Define commands required for AES operation */ -enum { - CMD_BLKSTARTENGINE = 0x0E, - CMD_DMASETUP = 0x10, - CMD_DMACOMPLETE = 0x11, - CMD_SETTABLE = 0x15, - CMD_MEMDMAVD = 0x22, -}; - -/* Define sub-commands */ -enum { - SUBCMD_VRAM_SEL = 0x1, - SUBCMD_CRYPTO_TABLE_SEL = 0x3, - SUBCMD_KEY_TABLE_SEL = 0x8, -}; - -/* memdma_vd command */ -#define MEMDMA_DIR_DTOVRAM 0 /* sdram -> vram */ -#define MEMDMA_DIR_VTODRAM 1 /* vram -> sdram */ -#define MEMDMA_DIR_SHIFT 25 -#define MEMDMA_NUM_WORDS_SHIFT 12 - -/* command queue bit shifts */ -enum { - CMDQ_KEYTABLEADDR_SHIFT = 0, - CMDQ_KEYTABLEID_SHIFT = 17, - CMDQ_VRAMSEL_SHIFT = 23, - CMDQ_TABLESEL_SHIFT = 24, - CMDQ_OPCODE_SHIFT = 26, -}; - -/* - * The secure key slot contains a unique secure key generated - * and loaded by the bootloader. This slot is marked as non-accessible - * to the kernel. - */ -#define SSK_SLOT_NUM 4 - -#define AES_NR_KEYSLOTS 8 -#define TEGRA_AES_QUEUE_LENGTH 50 -#define DEFAULT_RNG_BLK_SZ 16 - -/* The command queue depth */ -#define AES_HW_MAX_ICQ_LENGTH 5 - -struct tegra_aes_slot { - struct list_head node; - int slot_num; -}; - -static struct tegra_aes_slot ssk = { - .slot_num = SSK_SLOT_NUM, -}; - -struct tegra_aes_reqctx { - unsigned long mode; -}; - -struct tegra_aes_dev { - struct device *dev; - void __iomem *io_base; - dma_addr_t ivkey_phys_base; - void __iomem *ivkey_base; - struct clk *aes_clk; - struct tegra_aes_ctx *ctx; - int irq; - unsigned long flags; - struct completion op_complete; - u32 *buf_in; - dma_addr_t dma_buf_in; - u32 *buf_out; - dma_addr_t dma_buf_out; - u8 *iv; - u8 dt[DEFAULT_RNG_BLK_SZ]; - int ivlen; - u64 ctr; - spinlock_t lock; - struct crypto_queue queue; - struct tegra_aes_slot *slots; - struct ablkcipher_request *req; - size_t total; - struct scatterlist *in_sg; - size_t in_offset; - struct scatterlist *out_sg; - size_t out_offset; -}; - -static struct tegra_aes_dev *aes_dev; - -struct tegra_aes_ctx { - struct tegra_aes_dev *dd; - unsigned long flags; - struct tegra_aes_slot *slot; - u8 key[AES_MAX_KEY_SIZE]; - size_t keylen; -}; - -static struct tegra_aes_ctx rng_ctx = { - .flags = FLAGS_NEW_KEY, - .keylen = AES_KEYSIZE_128, -}; - -/* keep registered devices data here */ -static struct list_head dev_list; -static DEFINE_SPINLOCK(list_lock); -static DEFINE_MUTEX(aes_lock); - -static void aes_workqueue_handler(struct work_struct *work); -static DECLARE_WORK(aes_work, aes_workqueue_handler); -static struct workqueue_struct *aes_wq; - -extern unsigned long long tegra_chip_uid(void); - -static inline u32 aes_readl(struct tegra_aes_dev *dd, u32 offset) -{ - return readl(dd->io_base + offset); -} - -static inline void aes_writel(struct tegra_aes_dev *dd, u32 val, u32 offset) -{ - writel(val, dd->io_base + offset); -} - -static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr, - int nblocks, int mode, bool upd_iv) -{ - u32 cmdq[AES_HW_MAX_ICQ_LENGTH]; - int i, eng_busy, icq_empty, ret; - u32 value; - - /* reset all the interrupt bits */ - aes_writel(dd, 0xFFFFFFFF, TEGRA_AES_INTR_STATUS); - - /* enable error, dma xfer complete interrupts */ - aes_writel(dd, 0x33, TEGRA_AES_INT_ENB); - - cmdq[0] = CMD_DMASETUP << CMDQ_OPCODE_SHIFT; - cmdq[1] = in_addr; - cmdq[2] = CMD_BLKSTARTENGINE << CMDQ_OPCODE_SHIFT | (nblocks-1); - cmdq[3] = CMD_DMACOMPLETE << CMDQ_OPCODE_SHIFT; - - value = aes_readl(dd, TEGRA_AES_CMDQUE_CONTROL); - /* access SDRAM through AHB */ - value &= ~TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD; - value &= ~TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD; - value |= TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD | - TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD | - TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD; - aes_writel(dd, value, TEGRA_AES_CMDQUE_CONTROL); - dev_dbg(dd->dev, "cmd_q_ctrl=0x%x", value); - - value = (0x1 << TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT) | - ((dd->ctx->keylen * 8) << - TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT) | - ((u32)upd_iv << TEGRA_AES_SECURE_IV_SELECT_SHIFT); - - if (mode & FLAGS_CBC) { - value |= ((((mode & FLAGS_ENCRYPT) ? 2 : 3) - << TEGRA_AES_SECURE_XOR_POS_SHIFT) | - (((mode & FLAGS_ENCRYPT) ? 2 : 3) - << TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT) | - ((mode & FLAGS_ENCRYPT) ? 1 : 0) - << TEGRA_AES_SECURE_CORE_SEL_SHIFT); - } else if (mode & FLAGS_OFB) { - value |= ((TEGRA_AES_SECURE_XOR_POS_FIELD) | - (2 << TEGRA_AES_SECURE_INPUT_SEL_SHIFT) | - (TEGRA_AES_SECURE_CORE_SEL_FIELD)); - } else if (mode & FLAGS_RNG) { - value |= (((mode & FLAGS_ENCRYPT) ? 1 : 0) - << TEGRA_AES_SECURE_CORE_SEL_SHIFT | - TEGRA_AES_SECURE_RNG_ENB_FIELD); - } else { - value |= (((mode & FLAGS_ENCRYPT) ? 1 : 0) - << TEGRA_AES_SECURE_CORE_SEL_SHIFT); - } - - dev_dbg(dd->dev, "secure_in_sel=0x%x", value); - aes_writel(dd, value, TEGRA_AES_SECURE_INPUT_SELECT); - - aes_writel(dd, out_addr, TEGRA_AES_SECURE_DEST_ADDR); - INIT_COMPLETION(dd->op_complete); - - for (i = 0; i < AES_HW_MAX_ICQ_LENGTH - 1; i++) { - do { - value = aes_readl(dd, TEGRA_AES_INTR_STATUS); - eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD; - icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD; - } while (eng_busy & (!icq_empty)); - aes_writel(dd, cmdq[i], TEGRA_AES_ICMDQUE_WR); - } - - ret = wait_for_completion_timeout(&dd->op_complete, - msecs_to_jiffies(150)); - if (ret == 0) { - dev_err(dd->dev, "timed out (0x%x)\n", - aes_readl(dd, TEGRA_AES_INTR_STATUS)); - return -ETIMEDOUT; - } - - aes_writel(dd, cmdq[AES_HW_MAX_ICQ_LENGTH - 1], TEGRA_AES_ICMDQUE_WR); - return 0; -} - -static void aes_release_key_slot(struct tegra_aes_slot *slot) -{ - if (slot->slot_num == SSK_SLOT_NUM) - return; - - spin_lock(&list_lock); - list_add_tail(&slot->node, &dev_list); - slot = NULL; - spin_unlock(&list_lock); -} - -static struct tegra_aes_slot *aes_find_key_slot(void) -{ - struct tegra_aes_slot *slot = NULL; - struct list_head *new_head; - int empty; - - spin_lock(&list_lock); - empty = list_empty(&dev_list); - if (!empty) { - slot = list_entry(&dev_list, struct tegra_aes_slot, node); - new_head = dev_list.next; - list_del(&dev_list); - dev_list.next = new_head->next; - dev_list.prev = NULL; - } - spin_unlock(&list_lock); - - return slot; -} - -static int aes_set_key(struct tegra_aes_dev *dd) -{ - u32 value, cmdq[2]; - struct tegra_aes_ctx *ctx = dd->ctx; - int eng_busy, icq_empty, dma_busy; - bool use_ssk = false; - - /* use ssk? */ - if (!dd->ctx->slot) { - dev_dbg(dd->dev, "using ssk"); - dd->ctx->slot = &ssk; - use_ssk = true; - } - - /* enable key schedule generation in hardware */ - value = aes_readl(dd, TEGRA_AES_SECURE_CONFIG_EXT); - value &= ~TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD; - aes_writel(dd, value, TEGRA_AES_SECURE_CONFIG_EXT); - - /* select the key slot */ - value = aes_readl(dd, TEGRA_AES_SECURE_CONFIG); - value &= ~TEGRA_AES_SECURE_KEY_INDEX_FIELD; - value |= (ctx->slot->slot_num << TEGRA_AES_SECURE_KEY_INDEX_SHIFT); - aes_writel(dd, value, TEGRA_AES_SECURE_CONFIG); - - if (use_ssk) - return 0; - - /* copy the key table from sdram to vram */ - cmdq[0] = CMD_MEMDMAVD << CMDQ_OPCODE_SHIFT | - MEMDMA_DIR_DTOVRAM << MEMDMA_DIR_SHIFT | - AES_HW_KEY_TABLE_LENGTH_BYTES / sizeof(u32) << - MEMDMA_NUM_WORDS_SHIFT; - cmdq[1] = (u32)dd->ivkey_phys_base; - - aes_writel(dd, cmdq[0], TEGRA_AES_ICMDQUE_WR); - aes_writel(dd, cmdq[1], TEGRA_AES_ICMDQUE_WR); - - do { - value = aes_readl(dd, TEGRA_AES_INTR_STATUS); - eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD; - icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD; - dma_busy = value & TEGRA_AES_DMA_BUSY_FIELD; - } while (eng_busy & (!icq_empty) & dma_busy); - - /* settable command to get key into internal registers */ - value = CMD_SETTABLE << CMDQ_OPCODE_SHIFT | - SUBCMD_CRYPTO_TABLE_SEL << CMDQ_TABLESEL_SHIFT | - SUBCMD_VRAM_SEL << CMDQ_VRAMSEL_SHIFT | - (SUBCMD_KEY_TABLE_SEL | ctx->slot->slot_num) << - CMDQ_KEYTABLEID_SHIFT; - aes_writel(dd, value, TEGRA_AES_ICMDQUE_WR); - - do { - value = aes_readl(dd, TEGRA_AES_INTR_STATUS); - eng_busy = value & TEGRA_AES_ENGINE_BUSY_FIELD; - icq_empty = value & TEGRA_AES_ICQ_EMPTY_FIELD; - } while (eng_busy & (!icq_empty)); - - return 0; -} - -static int tegra_aes_handle_req(struct tegra_aes_dev *dd) -{ - struct crypto_async_request *async_req, *backlog; - struct crypto_ablkcipher *tfm; - struct tegra_aes_ctx *ctx; - struct tegra_aes_reqctx *rctx; - struct ablkcipher_request *req; - unsigned long flags; - int dma_max = AES_HW_DMA_BUFFER_SIZE_BYTES; - int ret = 0, nblocks, total; - int count = 0; - dma_addr_t addr_in, addr_out; - struct scatterlist *in_sg, *out_sg; - - if (!dd) - return -EINVAL; - - spin_lock_irqsave(&dd->lock, flags); - backlog = crypto_get_backlog(&dd->queue); - async_req = crypto_dequeue_request(&dd->queue); - if (!async_req) - clear_bit(FLAGS_BUSY, &dd->flags); - spin_unlock_irqrestore(&dd->lock, flags); - - if (!async_req) - return -ENODATA; - - if (backlog) - backlog->complete(backlog, -EINPROGRESS); - - req = ablkcipher_request_cast(async_req); - - dev_dbg(dd->dev, "%s: get new req\n", __func__); - - if (!req->src || !req->dst) - return -EINVAL; - - /* take mutex to access the aes hw */ - mutex_lock(&aes_lock); - - /* assign new request to device */ - dd->req = req; - dd->total = req->nbytes; - dd->in_offset = 0; - dd->in_sg = req->src; - dd->out_offset = 0; - dd->out_sg = req->dst; - - in_sg = dd->in_sg; - out_sg = dd->out_sg; - - total = dd->total; - - tfm = crypto_ablkcipher_reqtfm(req); - rctx = ablkcipher_request_ctx(req); - ctx = crypto_ablkcipher_ctx(tfm); - rctx->mode &= FLAGS_MODE_MASK; - dd->flags = (dd->flags & ~FLAGS_MODE_MASK) | rctx->mode; - - dd->iv = (u8 *)req->info; - dd->ivlen = crypto_ablkcipher_ivsize(tfm); - - /* assign new context to device */ - ctx->dd = dd; - dd->ctx = ctx; - - if (ctx->flags & FLAGS_NEW_KEY) { - /* copy the key */ - memcpy(dd->ivkey_base, ctx->key, ctx->keylen); - memset(dd->ivkey_base + ctx->keylen, 0, AES_HW_KEY_TABLE_LENGTH_BYTES - ctx->keylen); - aes_set_key(dd); - ctx->flags &= ~FLAGS_NEW_KEY; - } - - if (((dd->flags & FLAGS_CBC) || (dd->flags & FLAGS_OFB)) && dd->iv) { - /* set iv to the aes hw slot - * Hw generates updated iv only after iv is set in slot. - * So key and iv is passed asynchronously. - */ - memcpy(dd->buf_in, dd->iv, dd->ivlen); - - ret = aes_start_crypt(dd, (u32)dd->dma_buf_in, - dd->dma_buf_out, 1, FLAGS_CBC, false); - if (ret < 0) { - dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret); - goto out; - } - } - - while (total) { - dev_dbg(dd->dev, "remain: %d\n", total); - ret = dma_map_sg(dd->dev, in_sg, 1, DMA_TO_DEVICE); - if (!ret) { - dev_err(dd->dev, "dma_map_sg() error\n"); - goto out; - } - - ret = dma_map_sg(dd->dev, out_sg, 1, DMA_FROM_DEVICE); - if (!ret) { - dev_err(dd->dev, "dma_map_sg() error\n"); - dma_unmap_sg(dd->dev, dd->in_sg, - 1, DMA_TO_DEVICE); - goto out; - } - - addr_in = sg_dma_address(in_sg); - addr_out = sg_dma_address(out_sg); - dd->flags |= FLAGS_FAST; - count = min_t(int, sg_dma_len(in_sg), dma_max); - WARN_ON(sg_dma_len(in_sg) != sg_dma_len(out_sg)); - nblocks = DIV_ROUND_UP(count, AES_BLOCK_SIZE); - - ret = aes_start_crypt(dd, addr_in, addr_out, nblocks, - dd->flags, true); - - dma_unmap_sg(dd->dev, out_sg, 1, DMA_FROM_DEVICE); - dma_unmap_sg(dd->dev, in_sg, 1, DMA_TO_DEVICE); - - if (ret < 0) { - dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret); - goto out; - } - dd->flags &= ~FLAGS_FAST; - - dev_dbg(dd->dev, "out: copied %d\n", count); - total -= count; - in_sg = sg_next(in_sg); - out_sg = sg_next(out_sg); - WARN_ON(((total != 0) && (!in_sg || !out_sg))); - } - -out: - mutex_unlock(&aes_lock); - - dd->total = total; - - if (dd->req->base.complete) - dd->req->base.complete(&dd->req->base, ret); - - dev_dbg(dd->dev, "%s: exit\n", __func__); - return ret; -} - -static int tegra_aes_setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct tegra_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm); - struct tegra_aes_dev *dd = aes_dev; - struct tegra_aes_slot *key_slot; - - if ((keylen != AES_KEYSIZE_128) && (keylen != AES_KEYSIZE_192) && - (keylen != AES_KEYSIZE_256)) { - dev_err(dd->dev, "unsupported key size\n"); - crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - dev_dbg(dd->dev, "keylen: %d\n", keylen); - - ctx->dd = dd; - - if (key) { - if (!ctx->slot) { - key_slot = aes_find_key_slot(); - if (!key_slot) { - dev_err(dd->dev, "no empty slot\n"); - return -ENOMEM; - } - - ctx->slot = key_slot; - } - - memcpy(ctx->key, key, keylen); - ctx->keylen = keylen; - } - - ctx->flags |= FLAGS_NEW_KEY; - dev_dbg(dd->dev, "done\n"); - return 0; -} - -static void aes_workqueue_handler(struct work_struct *work) -{ - struct tegra_aes_dev *dd = aes_dev; - int ret; - - ret = clk_enable(dd->aes_clk); - if (ret) - BUG_ON("clock enable failed"); - - /* empty the crypto queue and then return */ - do { - ret = tegra_aes_handle_req(dd); - } while (!ret); - - clk_disable(dd->aes_clk); -} - -static irqreturn_t aes_irq(int irq, void *dev_id) -{ - struct tegra_aes_dev *dd = (struct tegra_aes_dev *)dev_id; - u32 value = aes_readl(dd, TEGRA_AES_INTR_STATUS); - int busy = test_bit(FLAGS_BUSY, &dd->flags); - - if (!busy) { - dev_dbg(dd->dev, "spurious interrupt\n"); - return IRQ_NONE; - } - - dev_dbg(dd->dev, "irq_stat: 0x%x\n", value); - if (value & TEGRA_AES_INT_ERROR_MASK) - aes_writel(dd, TEGRA_AES_INT_ERROR_MASK, TEGRA_AES_INTR_STATUS); - - if (!(value & TEGRA_AES_ENGINE_BUSY_FIELD)) - complete(&dd->op_complete); - else - return IRQ_NONE; - - return IRQ_HANDLED; -} - -static int tegra_aes_crypt(struct ablkcipher_request *req, unsigned long mode) -{ - struct tegra_aes_reqctx *rctx = ablkcipher_request_ctx(req); - struct tegra_aes_dev *dd = aes_dev; - unsigned long flags; - int err = 0; - int busy; - - dev_dbg(dd->dev, "nbytes: %d, enc: %d, cbc: %d, ofb: %d\n", - req->nbytes, !!(mode & FLAGS_ENCRYPT), - !!(mode & FLAGS_CBC), !!(mode & FLAGS_OFB)); - - rctx->mode = mode; - - spin_lock_irqsave(&dd->lock, flags); - err = ablkcipher_enqueue_request(&dd->queue, req); - busy = test_and_set_bit(FLAGS_BUSY, &dd->flags); - spin_unlock_irqrestore(&dd->lock, flags); - - if (!busy) - queue_work(aes_wq, &aes_work); - - return err; -} - -static int tegra_aes_ecb_encrypt(struct ablkcipher_request *req) -{ - return tegra_aes_crypt(req, FLAGS_ENCRYPT); -} - -static int tegra_aes_ecb_decrypt(struct ablkcipher_request *req) -{ - return tegra_aes_crypt(req, 0); -} - -static int tegra_aes_cbc_encrypt(struct ablkcipher_request *req) -{ - return tegra_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_CBC); -} - -static int tegra_aes_cbc_decrypt(struct ablkcipher_request *req) -{ - return tegra_aes_crypt(req, FLAGS_CBC); -} - -static int tegra_aes_ofb_encrypt(struct ablkcipher_request *req) -{ - return tegra_aes_crypt(req, FLAGS_ENCRYPT | FLAGS_OFB); -} - -static int tegra_aes_ofb_decrypt(struct ablkcipher_request *req) -{ - return tegra_aes_crypt(req, FLAGS_OFB); -} - -static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata, - unsigned int dlen) -{ - struct tegra_aes_dev *dd = aes_dev; - struct tegra_aes_ctx *ctx = &rng_ctx; - int ret, i; - u8 *dest = rdata, *dt = dd->dt; - - /* take mutex to access the aes hw */ - mutex_lock(&aes_lock); - - ret = clk_enable(dd->aes_clk); - if (ret) - return ret; - - ctx->dd = dd; - dd->ctx = ctx; - dd->flags = FLAGS_ENCRYPT | FLAGS_RNG; - - memcpy(dd->buf_in, dt, DEFAULT_RNG_BLK_SZ); - - ret = aes_start_crypt(dd, (u32)dd->dma_buf_in, - (u32)dd->dma_buf_out, 1, dd->flags, true); - if (ret < 0) { - dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret); - dlen = ret; - goto out; - } - memcpy(dest, dd->buf_out, dlen); - - /* update the DT */ - for (i = DEFAULT_RNG_BLK_SZ - 1; i >= 0; i--) { - dt[i] += 1; - if (dt[i] != 0) - break; - } - -out: - clk_disable(dd->aes_clk); - mutex_unlock(&aes_lock); - - dev_dbg(dd->dev, "%s: done\n", __func__); - return dlen; -} - -static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed, - unsigned int slen) -{ - struct tegra_aes_dev *dd = aes_dev; - struct tegra_aes_ctx *ctx = &rng_ctx; - struct tegra_aes_slot *key_slot; - struct timespec ts; - int ret = 0; - u64 nsec, tmp[2]; - u8 *dt; - - if (!ctx || !dd) { - dev_err(dd->dev, "ctx=0x%x, dd=0x%x\n", - (unsigned int)ctx, (unsigned int)dd); - return -EINVAL; - } - - if (slen < (DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) { - dev_err(dd->dev, "seed size invalid"); - return -ENOMEM; - } - - /* take mutex to access the aes hw */ - mutex_lock(&aes_lock); - - if (!ctx->slot) { - key_slot = aes_find_key_slot(); - if (!key_slot) { - dev_err(dd->dev, "no empty slot\n"); - mutex_unlock(&aes_lock); - return -ENOMEM; - } - ctx->slot = key_slot; - } - - ctx->dd = dd; - dd->ctx = ctx; - dd->ctr = 0; - - ctx->keylen = AES_KEYSIZE_128; - ctx->flags |= FLAGS_NEW_KEY; - - /* copy the key to the key slot */ - memcpy(dd->ivkey_base, seed + DEFAULT_RNG_BLK_SZ, AES_KEYSIZE_128); - memset(dd->ivkey_base + AES_KEYSIZE_128, 0, AES_HW_KEY_TABLE_LENGTH_BYTES - AES_KEYSIZE_128); - - dd->iv = seed; - dd->ivlen = slen; - - dd->flags = FLAGS_ENCRYPT | FLAGS_RNG; - - ret = clk_enable(dd->aes_clk); - if (ret) - return ret; - - aes_set_key(dd); - - /* set seed to the aes hw slot */ - memcpy(dd->buf_in, dd->iv, DEFAULT_RNG_BLK_SZ); - ret = aes_start_crypt(dd, (u32)dd->dma_buf_in, - dd->dma_buf_out, 1, FLAGS_CBC, false); - if (ret < 0) { - dev_err(dd->dev, "aes_start_crypt fail(%d)\n", ret); - goto out; - } - - if (dd->ivlen >= (2 * DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128)) { - dt = dd->iv + DEFAULT_RNG_BLK_SZ + AES_KEYSIZE_128; - } else { - getnstimeofday(&ts); - nsec = timespec_to_ns(&ts); - do_div(nsec, 1000); - nsec ^= dd->ctr << 56; - dd->ctr++; - tmp[0] = nsec; - tmp[1] = tegra_chip_uid(); - dt = (u8 *)tmp; - } - memcpy(dd->dt, dt, DEFAULT_RNG_BLK_SZ); - -out: - clk_disable(dd->aes_clk); - mutex_unlock(&aes_lock); - - dev_dbg(dd->dev, "%s: done\n", __func__); - return ret; -} - -static int tegra_aes_cra_init(struct crypto_tfm *tfm) -{ - tfm->crt_ablkcipher.reqsize = sizeof(struct tegra_aes_reqctx); - - return 0; -} - -void tegra_aes_cra_exit(struct crypto_tfm *tfm) -{ - struct tegra_aes_ctx *ctx = - crypto_ablkcipher_ctx((struct crypto_ablkcipher *)tfm); - - if (ctx && ctx->slot) - aes_release_key_slot(ctx->slot); -} - -static struct crypto_alg algs[] = { - { - .cra_name = "ecb(aes)", - .cra_driver_name = "ecb-aes-tegra", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_alignmask = 3, - .cra_type = &crypto_ablkcipher_type, - .cra_u.ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .setkey = tegra_aes_setkey, - .encrypt = tegra_aes_ecb_encrypt, - .decrypt = tegra_aes_ecb_decrypt, - }, - }, { - .cra_name = "cbc(aes)", - .cra_driver_name = "cbc-aes-tegra", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_alignmask = 3, - .cra_type = &crypto_ablkcipher_type, - .cra_u.ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_MIN_KEY_SIZE, - .setkey = tegra_aes_setkey, - .encrypt = tegra_aes_cbc_encrypt, - .decrypt = tegra_aes_cbc_decrypt, - } - }, { - .cra_name = "ofb(aes)", - .cra_driver_name = "ofb-aes-tegra", - .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_alignmask = 3, - .cra_type = &crypto_ablkcipher_type, - .cra_u.ablkcipher = { - .min_keysize = AES_MIN_KEY_SIZE, - .max_keysize = AES_MAX_KEY_SIZE, - .ivsize = AES_MIN_KEY_SIZE, - .setkey = tegra_aes_setkey, - .encrypt = tegra_aes_ofb_encrypt, - .decrypt = tegra_aes_ofb_decrypt, - } - }, { - .cra_name = "ansi_cprng", - .cra_driver_name = "rng-aes-tegra", - .cra_flags = CRYPTO_ALG_TYPE_RNG, - .cra_ctxsize = sizeof(struct tegra_aes_ctx), - .cra_type = &crypto_rng_type, - .cra_u.rng = { - .rng_make_random = tegra_aes_get_random, - .rng_reset = tegra_aes_rng_reset, - .seedsize = AES_KEYSIZE_128 + (2 * DEFAULT_RNG_BLK_SZ), - } - } -}; - -static int tegra_aes_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct tegra_aes_dev *dd; - struct resource *res; - int err = -ENOMEM, i = 0, j; - - dd = devm_kzalloc(dev, sizeof(struct tegra_aes_dev), GFP_KERNEL); - if (dd == NULL) { - dev_err(dev, "unable to alloc data struct.\n"); - return err; - } - - dd->dev = dev; - platform_set_drvdata(pdev, dd); - - dd->slots = devm_kzalloc(dev, sizeof(struct tegra_aes_slot) * - AES_NR_KEYSLOTS, GFP_KERNEL); - if (dd->slots == NULL) { - dev_err(dev, "unable to alloc slot struct.\n"); - goto out; - } - - spin_lock_init(&dd->lock); - crypto_init_queue(&dd->queue, TEGRA_AES_QUEUE_LENGTH); - - /* Get the module base address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "invalid resource type: base\n"); - err = -ENODEV; - goto out; - } - - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), - dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "Couldn't request MEM resource\n"); - return -ENODEV; - } - - dd->io_base = devm_ioremap(dev, res->start, resource_size(res)); - if (!dd->io_base) { - dev_err(dev, "can't ioremap register space\n"); - err = -ENOMEM; - goto out; - } - - /* Initialize the vde clock */ - dd->aes_clk = clk_get(dev, "vde"); - if (IS_ERR(dd->aes_clk)) { - dev_err(dev, "iclock intialization failed.\n"); - err = -ENODEV; - goto out; - } - - err = clk_set_rate(dd->aes_clk, ULONG_MAX); - if (err) { - dev_err(dd->dev, "iclk set_rate fail(%d)\n", err); - goto out; - } - - /* - * the foll contiguous memory is allocated as follows - - * - hardware key table - * - key schedule - */ - dd->ivkey_base = dma_alloc_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES, - &dd->ivkey_phys_base, - GFP_KERNEL); - if (!dd->ivkey_base) { - dev_err(dev, "can not allocate iv/key buffer\n"); - err = -ENOMEM; - goto out; - } - - dd->buf_in = dma_alloc_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, - &dd->dma_buf_in, GFP_KERNEL); - if (!dd->buf_in) { - dev_err(dev, "can not allocate dma-in buffer\n"); - err = -ENOMEM; - goto out; - } - - dd->buf_out = dma_alloc_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, - &dd->dma_buf_out, GFP_KERNEL); - if (!dd->buf_out) { - dev_err(dev, "can not allocate dma-out buffer\n"); - err = -ENOMEM; - goto out; - } - - init_completion(&dd->op_complete); - aes_wq = alloc_workqueue("tegra_aes_wq", WQ_HIGHPRI | WQ_UNBOUND, 1); - if (!aes_wq) { - dev_err(dev, "alloc_workqueue failed\n"); - goto out; - } - - /* get the irq */ - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res) { - dev_err(dev, "invalid resource type: base\n"); - err = -ENODEV; - goto out; - } - dd->irq = res->start; - - err = devm_request_irq(dev, dd->irq, aes_irq, IRQF_TRIGGER_HIGH | - IRQF_SHARED, "tegra-aes", dd); - if (err) { - dev_err(dev, "request_irq failed\n"); - goto out; - } - - mutex_init(&aes_lock); - INIT_LIST_HEAD(&dev_list); - - spin_lock_init(&list_lock); - spin_lock(&list_lock); - for (i = 0; i < AES_NR_KEYSLOTS; i++) { - if (i == SSK_SLOT_NUM) - continue; - dd->slots[i].slot_num = i; - INIT_LIST_HEAD(&dd->slots[i].node); - list_add_tail(&dd->slots[i].node, &dev_list); - } - spin_unlock(&list_lock); - - aes_dev = dd; - for (i = 0; i < ARRAY_SIZE(algs); i++) { - INIT_LIST_HEAD(&algs[i].cra_list); - - algs[i].cra_priority = 300; - algs[i].cra_ctxsize = sizeof(struct tegra_aes_ctx); - algs[i].cra_module = THIS_MODULE; - algs[i].cra_init = tegra_aes_cra_init; - algs[i].cra_exit = tegra_aes_cra_exit; - - err = crypto_register_alg(&algs[i]); - if (err) - goto out; - } - - dev_info(dev, "registered"); - return 0; - -out: - for (j = 0; j < i; j++) - crypto_unregister_alg(&algs[j]); - if (dd->ivkey_base) - dma_free_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES, - dd->ivkey_base, dd->ivkey_phys_base); - if (dd->buf_in) - dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, - dd->buf_in, dd->dma_buf_in); - if (dd->buf_out) - dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, - dd->buf_out, dd->dma_buf_out); - if (IS_ERR(dd->aes_clk)) - clk_put(dd->aes_clk); - if (aes_wq) - destroy_workqueue(aes_wq); - spin_lock(&list_lock); - list_del(&dev_list); - spin_unlock(&list_lock); - - aes_dev = NULL; - - dev_err(dev, "%s: initialization failed.\n", __func__); - return err; -} - -static int __devexit tegra_aes_remove(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct tegra_aes_dev *dd = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < ARRAY_SIZE(algs); i++) - crypto_unregister_alg(&algs[i]); - - cancel_work_sync(&aes_work); - destroy_workqueue(aes_wq); - spin_lock(&list_lock); - list_del(&dev_list); - spin_unlock(&list_lock); - - dma_free_coherent(dev, AES_HW_KEY_TABLE_LENGTH_BYTES, - dd->ivkey_base, dd->ivkey_phys_base); - dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, - dd->buf_in, dd->dma_buf_in); - dma_free_coherent(dev, AES_HW_DMA_BUFFER_SIZE_BYTES, - dd->buf_out, dd->dma_buf_out); - clk_put(dd->aes_clk); - aes_dev = NULL; - - return 0; -} - -static struct of_device_id tegra_aes_of_match[] __devinitdata = { - { .compatible = "nvidia,tegra20-aes", }, - { .compatible = "nvidia,tegra30-aes", }, - { }, -}; - -static struct platform_driver tegra_aes_driver = { - .probe = tegra_aes_probe, - .remove = __devexit_p(tegra_aes_remove), - .driver = { - .name = "tegra-aes", - .owner = THIS_MODULE, - .of_match_table = tegra_aes_of_match, - }, -}; - -module_platform_driver(tegra_aes_driver); - -MODULE_DESCRIPTION("Tegra AES/OFB/CPRNG hw acceleration support."); -MODULE_AUTHOR("NVIDIA Corporation"); -MODULE_LICENSE("GPL v2"); diff --git a/trunk/drivers/crypto/tegra-aes.h b/trunk/drivers/crypto/tegra-aes.h deleted file mode 100644 index 6006333a8934..000000000000 --- a/trunk/drivers/crypto/tegra-aes.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2010, NVIDIA Corporation. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __CRYPTODEV_TEGRA_AES_H -#define __CRYPTODEV_TEGRA_AES_H - -#define TEGRA_AES_ICMDQUE_WR 0x1000 -#define TEGRA_AES_CMDQUE_CONTROL 0x1008 -#define TEGRA_AES_INTR_STATUS 0x1018 -#define TEGRA_AES_INT_ENB 0x1040 -#define TEGRA_AES_CONFIG 0x1044 -#define TEGRA_AES_IRAM_ACCESS_CFG 0x10A0 -#define TEGRA_AES_SECURE_DEST_ADDR 0x1100 -#define TEGRA_AES_SECURE_INPUT_SELECT 0x1104 -#define TEGRA_AES_SECURE_CONFIG 0x1108 -#define TEGRA_AES_SECURE_CONFIG_EXT 0x110C -#define TEGRA_AES_SECURE_SECURITY 0x1110 -#define TEGRA_AES_SECURE_HASH_RESULT0 0x1120 -#define TEGRA_AES_SECURE_HASH_RESULT1 0x1124 -#define TEGRA_AES_SECURE_HASH_RESULT2 0x1128 -#define TEGRA_AES_SECURE_HASH_RESULT3 0x112C -#define TEGRA_AES_SECURE_SEC_SEL0 0x1140 -#define TEGRA_AES_SECURE_SEC_SEL1 0x1144 -#define TEGRA_AES_SECURE_SEC_SEL2 0x1148 -#define TEGRA_AES_SECURE_SEC_SEL3 0x114C -#define TEGRA_AES_SECURE_SEC_SEL4 0x1150 -#define TEGRA_AES_SECURE_SEC_SEL5 0x1154 -#define TEGRA_AES_SECURE_SEC_SEL6 0x1158 -#define TEGRA_AES_SECURE_SEC_SEL7 0x115C - -/* interrupt status reg masks and shifts */ -#define TEGRA_AES_ENGINE_BUSY_FIELD BIT(0) -#define TEGRA_AES_ICQ_EMPTY_FIELD BIT(3) -#define TEGRA_AES_DMA_BUSY_FIELD BIT(23) - -/* secure select reg masks and shifts */ -#define TEGRA_AES_SECURE_SEL0_KEYREAD_ENB0_FIELD BIT(0) - -/* secure config ext masks and shifts */ -#define TEGRA_AES_SECURE_KEY_SCH_DIS_FIELD BIT(15) - -/* secure config masks and shifts */ -#define TEGRA_AES_SECURE_KEY_INDEX_SHIFT 20 -#define TEGRA_AES_SECURE_KEY_INDEX_FIELD (0x1F << TEGRA_AES_SECURE_KEY_INDEX_SHIFT) -#define TEGRA_AES_SECURE_BLOCK_CNT_SHIFT 0 -#define TEGRA_AES_SECURE_BLOCK_CNT_FIELD (0xFFFFF << TEGRA_AES_SECURE_BLOCK_CNT_SHIFT) - -/* stream interface select masks and shifts */ -#define TEGRA_AES_CMDQ_CTRL_UCMDQEN_FIELD BIT(0) -#define TEGRA_AES_CMDQ_CTRL_ICMDQEN_FIELD BIT(1) -#define TEGRA_AES_CMDQ_CTRL_SRC_STM_SEL_FIELD BIT(4) -#define TEGRA_AES_CMDQ_CTRL_DST_STM_SEL_FIELD BIT(5) - -/* config register masks and shifts */ -#define TEGRA_AES_CONFIG_ENDIAN_ENB_FIELD BIT(10) -#define TEGRA_AES_CONFIG_MODE_SEL_SHIFT 0 -#define TEGRA_AES_CONFIG_MODE_SEL_FIELD (0x1F << TEGRA_AES_CONFIG_MODE_SEL_SHIFT) - -/* extended config */ -#define TEGRA_AES_SECURE_OFFSET_CNT_SHIFT 24 -#define TEGRA_AES_SECURE_OFFSET_CNT_FIELD (0xFF << TEGRA_AES_SECURE_OFFSET_CNT_SHIFT) -#define TEGRA_AES_SECURE_KEYSCHED_GEN_FIELD BIT(15) - -/* init vector select */ -#define TEGRA_AES_SECURE_IV_SELECT_SHIFT 10 -#define TEGRA_AES_SECURE_IV_SELECT_FIELD BIT(10) - -/* secure engine input */ -#define TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT 28 -#define TEGRA_AES_SECURE_INPUT_ALG_SEL_FIELD (0xF << TEGRA_AES_SECURE_INPUT_ALG_SEL_SHIFT) -#define TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT 16 -#define TEGRA_AES_SECURE_INPUT_KEY_LEN_FIELD (0xFFF << TEGRA_AES_SECURE_INPUT_KEY_LEN_SHIFT) -#define TEGRA_AES_SECURE_RNG_ENB_FIELD BIT(11) -#define TEGRA_AES_SECURE_CORE_SEL_SHIFT 9 -#define TEGRA_AES_SECURE_CORE_SEL_FIELD BIT(9) -#define TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT 7 -#define TEGRA_AES_SECURE_VCTRAM_SEL_FIELD (0x3 << TEGRA_AES_SECURE_VCTRAM_SEL_SHIFT) -#define TEGRA_AES_SECURE_INPUT_SEL_SHIFT 5 -#define TEGRA_AES_SECURE_INPUT_SEL_FIELD (0x3 << TEGRA_AES_SECURE_INPUT_SEL_SHIFT) -#define TEGRA_AES_SECURE_XOR_POS_SHIFT 3 -#define TEGRA_AES_SECURE_XOR_POS_FIELD (0x3 << TEGRA_AES_SECURE_XOR_POS_SHIFT) -#define TEGRA_AES_SECURE_HASH_ENB_FIELD BIT(2) -#define TEGRA_AES_SECURE_ON_THE_FLY_FIELD BIT(0) - -/* interrupt error mask */ -#define TEGRA_AES_INT_ERROR_MASK 0xFFF000 - -#endif diff --git a/trunk/drivers/gpio/Kconfig b/trunk/drivers/gpio/Kconfig index 0409cf35adda..d0c41188d4e5 100644 --- a/trunk/drivers/gpio/Kconfig +++ b/trunk/drivers/gpio/Kconfig @@ -190,17 +190,6 @@ config GPIO_VX855 additional drivers must be enabled in order to use the functionality of the device. -config GPIO_GE_FPGA - bool "GE FPGA based GPIO" - depends on GE_FPGA - help - Support for common GPIO functionality provided on some GE Single Board - Computers. - - This driver provides basic support (configure as input or output, read - and write pin state) for GPIO implemented in a number of GE single - board computers. - comment "I2C GPIO expanders:" config GPIO_MAX7300 diff --git a/trunk/drivers/gpio/Makefile b/trunk/drivers/gpio/Makefile index 9a8fb54ae462..fa10df604c01 100644 --- a/trunk/drivers/gpio/Makefile +++ b/trunk/drivers/gpio/Makefile @@ -16,7 +16,6 @@ obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o -obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o diff --git a/trunk/drivers/misc/carma/carma-fpga.c b/trunk/drivers/misc/carma/carma-fpga.c index 8c279da07410..366bc156e34d 100644 --- a/trunk/drivers/misc/carma/carma-fpga.c +++ b/trunk/drivers/misc/carma/carma-fpga.c @@ -560,9 +560,6 @@ static void data_enable_interrupts(struct fpga_device *priv) /* flush the writes */ fpga_read_reg(priv, 0, MMAP_REG_STATUS); - fpga_read_reg(priv, 1, MMAP_REG_STATUS); - fpga_read_reg(priv, 2, MMAP_REG_STATUS); - fpga_read_reg(priv, 3, MMAP_REG_STATUS); /* switch back to the external interrupt source */ iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); @@ -594,12 +591,8 @@ static void data_dma_cb(void *data) list_move_tail(&priv->inflight->entry, &priv->used); priv->inflight = NULL; - /* - * If data dumping is still enabled, then clear the FPGA - * status registers and re-enable FPGA interrupts - */ - if (priv->enabled) - data_enable_interrupts(priv); + /* clear the FPGA status and re-enable interrupts */ + data_enable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -715,15 +708,6 @@ static irqreturn_t data_irq(int irq, void *dev_id) spin_lock(&priv->lock); - /* - * This is an error case that should never happen. - * - * If this driver has a bug and manages to re-enable interrupts while - * a DMA is in progress, then we will hit this statement and should - * start paying attention immediately. - */ - BUG_ON(priv->inflight != NULL); - /* hide the interrupt by switching the IRQ driver to GPIO */ data_disable_interrupts(priv); @@ -778,15 +762,11 @@ static irqreturn_t data_irq(int irq, void *dev_id) */ static int data_device_enable(struct fpga_device *priv) { - bool enabled; u32 val; int ret; /* multiple enables are safe: they do nothing */ - spin_lock_irq(&priv->lock); - enabled = priv->enabled; - spin_unlock_irq(&priv->lock); - if (enabled) + if (priv->enabled) return 0; /* check that the FPGAs are programmed */ @@ -817,9 +797,6 @@ static int data_device_enable(struct fpga_device *priv) goto out_error; } - /* prevent the FPGAs from generating interrupts */ - data_disable_interrupts(priv); - /* hookup the irq handler */ ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); if (ret) { @@ -827,13 +804,11 @@ static int data_device_enable(struct fpga_device *priv) goto out_error; } - /* allow the DMA callback to re-enable FPGA interrupts */ - spin_lock_irq(&priv->lock); - priv->enabled = true; - spin_unlock_irq(&priv->lock); - - /* allow the FPGAs to generate interrupts */ + /* switch to the external FPGA IRQ line */ data_enable_interrupts(priv); + + /* success, we're enabled */ + priv->enabled = true; return 0; out_error: @@ -859,40 +834,41 @@ static int data_device_enable(struct fpga_device *priv) */ static int data_device_disable(struct fpga_device *priv) { - spin_lock_irq(&priv->lock); + int ret; /* allow multiple disable */ - if (!priv->enabled) { - spin_unlock_irq(&priv->lock); + if (!priv->enabled) return 0; - } - - /* - * Mark the device disabled - * - * This stops DMA callbacks from re-enabling interrupts - */ - priv->enabled = false; - /* prevent the FPGAs from generating interrupts */ + /* switch to the internal GPIO IRQ line */ data_disable_interrupts(priv); - /* wait until all ongoing DMA has finished */ - while (priv->inflight != NULL) { - spin_unlock_irq(&priv->lock); - wait_event(priv->wait, priv->inflight == NULL); - spin_lock_irq(&priv->lock); - } - - spin_unlock_irq(&priv->lock); - /* unhook the irq handler */ free_irq(priv->irq, priv); + /* + * wait for all outstanding DMA to complete + * + * Device interrupts are disabled, therefore another buffer cannot + * be marked inflight. + */ + ret = wait_event_interruptible(priv->wait, priv->inflight == NULL); + if (ret) + return ret; + /* free the correlation table */ sg_free_table(&priv->corl_table); priv->corl_nents = 0; + /* + * We are taking the spinlock not to protect priv->enabled, but instead + * to make sure that there are no readers in the process of altering + * the free or used lists while we are setting this flag. + */ + spin_lock_irq(&priv->lock); + priv->enabled = false; + spin_unlock_irq(&priv->lock); + /* free all buffers: the free and used lists are not being changed */ data_free_buffers(priv); return 0; @@ -920,6 +896,15 @@ static unsigned int list_num_entries(struct list_head *list) static int data_debug_show(struct seq_file *f, void *offset) { struct fpga_device *priv = f->private; + int ret; + + /* + * Lock the mutex first, so that we get an accurate value for enable + * Lock the spinlock next, to get accurate list counts + */ + ret = mutex_lock_interruptible(&priv->mutex); + if (ret) + return ret; spin_lock_irq(&priv->lock); @@ -932,6 +917,7 @@ static int data_debug_show(struct seq_file *f, void *offset) seq_printf(f, "num_dropped: %d\n", priv->num_dropped); spin_unlock_irq(&priv->lock); + mutex_unlock(&priv->mutex); return 0; } @@ -984,13 +970,7 @@ static ssize_t data_en_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fpga_device *priv = dev_get_drvdata(dev); - int ret; - - spin_lock_irq(&priv->lock); - ret = snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); - spin_unlock_irq(&priv->lock); - - return ret; + return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); } static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, @@ -1006,7 +986,6 @@ static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, return -EINVAL; } - /* protect against concurrent enable/disable */ ret = mutex_lock_interruptible(&priv->mutex); if (ret) return ret; @@ -1100,7 +1079,6 @@ static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count, struct fpga_reader *reader = filp->private_data; struct fpga_device *priv = reader->priv; struct list_head *used = &priv->used; - bool drop_buffer = false; struct data_buf *dbuf; size_t avail; void *data; @@ -1188,12 +1166,10 @@ static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count, * One of two things has happened, the device is disabled, or the * device has been reconfigured underneath us. In either case, we * should just throw away the buffer. - * - * Lockdep complains if this is done under the spinlock, so we - * handle it during the unlock path. */ if (!priv->enabled || dbuf->size != priv->bufsize) { - drop_buffer = true; + videobuf_dma_unmap(priv->dev, &dbuf->vb); + data_free_buffer(dbuf); goto out_unlock; } @@ -1202,12 +1178,6 @@ static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count, out_unlock: spin_unlock_irq(&priv->lock); - - if (drop_buffer) { - videobuf_dma_unmap(priv->dev, &dbuf->vb); - data_free_buffer(dbuf); - } - return count; } diff --git a/trunk/drivers/misc/ibmasm/ibmasmfs.c b/trunk/drivers/misc/ibmasm/ibmasmfs.c index 1c034b80d408..35361753b487 100644 --- a/trunk/drivers/misc/ibmasm/ibmasmfs.c +++ b/trunk/drivers/misc/ibmasm/ibmasmfs.c @@ -87,7 +87,7 @@ static LIST_HEAD(service_processors); static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode); -static void ibmasmfs_create_files (struct super_block *sb); +static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root); static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent); @@ -114,6 +114,7 @@ static struct file_system_type ibmasmfs_type = { static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent) { struct inode *root; + struct dentry *root_dentry; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -128,11 +129,14 @@ static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent) root->i_op = &simple_dir_inode_operations; root->i_fop = ibmasmfs_dir_ops; - sb->s_root = d_make_root(root); - if (!sb->s_root) + root_dentry = d_alloc_root(root); + if (!root_dentry) { + iput(root); return -ENOMEM; + } + sb->s_root = root_dentry; - ibmasmfs_create_files(sb); + ibmasmfs_create_files(sb, root_dentry); return 0; } @@ -608,7 +612,7 @@ static const struct file_operations remote_settings_fops = { }; -static void ibmasmfs_create_files (struct super_block *sb) +static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root) { struct list_head *entry; struct service_processor *sp; @@ -617,7 +621,7 @@ static void ibmasmfs_create_files (struct super_block *sb) struct dentry *dir; struct dentry *remote_dir; sp = list_entry(entry, struct service_processor, node); - dir = ibmasmfs_create_dir(sb, sb->s_root, sp->dirname); + dir = ibmasmfs_create_dir(sb, root, sp->dirname); if (!dir) continue; diff --git a/trunk/drivers/misc/ibmasm/module.c b/trunk/drivers/misc/ibmasm/module.c index 168d8008f460..1ccedb71e728 100644 --- a/trunk/drivers/misc/ibmasm/module.c +++ b/trunk/drivers/misc/ibmasm/module.c @@ -211,17 +211,18 @@ static void __exit ibmasm_exit (void) static int __init ibmasm_init(void) { - int result = pci_register_driver(&ibmasm_driver); - if (result) - return result; + int result; result = ibmasmfs_register(); if (result) { - pci_unregister_driver(&ibmasm_driver); err("Failed to register ibmasmfs file system"); return result; } - + result = pci_register_driver(&ibmasm_driver); + if (result) { + ibmasmfs_unregister(); + return result; + } ibmasm_register_panic_notifier(); info(DRIVER_DESC " version " DRIVER_VERSION " loaded"); return 0; diff --git a/trunk/drivers/mmc/card/block.c b/trunk/drivers/mmc/card/block.c index e5a3c7b6dedb..c6a383d0244d 100644 --- a/trunk/drivers/mmc/card/block.c +++ b/trunk/drivers/mmc/card/block.c @@ -1685,7 +1685,7 @@ static int mmc_add_disk(struct mmc_blk_data *md) if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) && card->ext_csd.boot_ro_lockable) { - umode_t mode; + mode_t mode; if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS) mode = S_IRUGO; diff --git a/trunk/drivers/mtd/nand/Kconfig b/trunk/drivers/mtd/nand/Kconfig index 3b1d6da874e0..31b034b7eba3 100644 --- a/trunk/drivers/mtd/nand/Kconfig +++ b/trunk/drivers/mtd/nand/Kconfig @@ -462,16 +462,6 @@ config MTD_NAND_FSL_ELBC Enabling this option will enable you to use this to control external NAND devices. -config MTD_NAND_FSL_IFC - tristate "NAND support for Freescale IFC controller" - depends on MTD_NAND && FSL_SOC - select FSL_IFC - help - Various Freescale chips e.g P1010, include a NAND Flash machine - with built-in hardware ECC capabilities. - Enabling this option will enable you to use this to control - external NAND devices. - config MTD_NAND_FSL_UPM tristate "Support for NAND on Freescale UPM" depends on PPC_83xx || PPC_85xx diff --git a/trunk/drivers/mtd/nand/Makefile b/trunk/drivers/mtd/nand/Makefile index 19bc8cb1d187..618f4ba23699 100644 --- a/trunk/drivers/mtd/nand/Makefile +++ b/trunk/drivers/mtd/nand/Makefile @@ -37,7 +37,6 @@ obj-$(CONFIG_MTD_ALAUDA) += alauda.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o -obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o diff --git a/trunk/drivers/mtd/nand/fsl_ifc_nand.c b/trunk/drivers/mtd/nand/fsl_ifc_nand.c deleted file mode 100644 index c30ac7b83d28..000000000000 --- a/trunk/drivers/mtd/nand/fsl_ifc_nand.c +++ /dev/null @@ -1,1072 +0,0 @@ -/* - * Freescale Integrated Flash Controller NAND driver - * - * Copyright 2011-2012 Freescale Semiconductor, Inc - * - * Author: Dipen Dudhat - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ERR_BYTE 0xFF /* Value returned for read - bytes when read failed */ -#define IFC_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait - for IFC NAND Machine */ - -struct fsl_ifc_ctrl; - -/* mtd information per set */ -struct fsl_ifc_mtd { - struct mtd_info mtd; - struct nand_chip chip; - struct fsl_ifc_ctrl *ctrl; - - struct device *dev; - int bank; /* Chip select bank number */ - unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */ - u8 __iomem *vbase; /* Chip select base virtual address */ -}; - -/* overview of the fsl ifc controller */ -struct fsl_ifc_nand_ctrl { - struct nand_hw_control controller; - struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT]; - - u8 __iomem *addr; /* Address of assigned IFC buffer */ - unsigned int page; /* Last page written to / read from */ - unsigned int read_bytes;/* Number of bytes read during command */ - unsigned int column; /* Saved column from SEQIN */ - unsigned int index; /* Pointer to next byte to 'read' */ - unsigned int oob; /* Non zero if operating on OOB data */ - unsigned int eccread; /* Non zero for a full-page ECC read */ - unsigned int counter; /* counter for the initializations */ -}; - -static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl; - -/* 512-byte page with 4-bit ECC, 8-bit */ -static struct nand_ecclayout oob_512_8bit_ecc4 = { - .eccbytes = 8, - .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, - .oobfree = { {0, 5}, {6, 2} }, -}; - -/* 512-byte page with 4-bit ECC, 16-bit */ -static struct nand_ecclayout oob_512_16bit_ecc4 = { - .eccbytes = 8, - .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, - .oobfree = { {2, 6}, }, -}; - -/* 2048-byte page size with 4-bit ECC */ -static struct nand_ecclayout oob_2048_ecc4 = { - .eccbytes = 32, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - }, - .oobfree = { {2, 6}, {40, 24} }, -}; - -/* 4096-byte page size with 4-bit ECC */ -static struct nand_ecclayout oob_4096_ecc4 = { - .eccbytes = 64, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - }, - .oobfree = { {2, 6}, {72, 56} }, -}; - -/* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */ -static struct nand_ecclayout oob_4096_ecc8 = { - .eccbytes = 128, - .eccpos = { - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, - }, - .oobfree = { {2, 6}, {136, 82} }, -}; - - -/* - * Generic flash bbt descriptors - */ -static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; -static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 2, /* 0 on 8-bit small page */ - .len = 4, - .veroffs = 6, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | - NAND_BBT_2BIT | NAND_BBT_VERSION, - .offs = 2, /* 0 on 8-bit small page */ - .len = 4, - .veroffs = 6, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - -/* - * Set up the IFC hardware block and page address fields, and the ifc nand - * structure addr field to point to the correct IFC buffer in memory - */ -static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_regs __iomem *ifc = ctrl->regs; - int buf_num; - - ifc_nand_ctrl->page = page_addr; - /* Program ROW0/COL0 */ - out_be32(&ifc->ifc_nand.row0, page_addr); - out_be32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column); - - buf_num = page_addr & priv->bufnum_mask; - - ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2); - ifc_nand_ctrl->index = column; - - /* for OOB data point to the second half of the buffer */ - if (oob) - ifc_nand_ctrl->index += mtd->writesize; -} - -static int is_blank(struct mtd_info *mtd, unsigned int bufnum) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2); - u32 __iomem *mainarea = (u32 *)addr; - u8 __iomem *oob = addr + mtd->writesize; - int i; - - for (i = 0; i < mtd->writesize / 4; i++) { - if (__raw_readl(&mainarea[i]) != 0xffffffff) - return 0; - } - - for (i = 0; i < chip->ecc.layout->eccbytes; i++) { - int pos = chip->ecc.layout->eccpos[i]; - - if (__raw_readb(&oob[pos]) != 0xff) - return 0; - } - - return 1; -} - -/* returns nonzero if entire page is blank */ -static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl, - u32 *eccstat, unsigned int bufnum) -{ - u32 reg = eccstat[bufnum / 4]; - int errors; - - errors = (reg >> ((3 - bufnum % 4) * 8)) & 15; - - return errors; -} - -/* - * execute IFC NAND command and wait for it to complete - */ -static void fsl_ifc_run_command(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl; - struct fsl_ifc_regs __iomem *ifc = ctrl->regs; - u32 eccstat[4]; - int i; - - /* set the chip select for NAND Transaction */ - out_be32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT); - - dev_vdbg(priv->dev, - "%s: fir0=%08x fcr0=%08x\n", - __func__, - in_be32(&ifc->ifc_nand.nand_fir0), - in_be32(&ifc->ifc_nand.nand_fcr0)); - - ctrl->nand_stat = 0; - - /* start read/write seq */ - out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT); - - /* wait for command complete flag or timeout */ - wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, - IFC_TIMEOUT_MSECS * HZ/1000); - - /* ctrl->nand_stat will be updated from IRQ context */ - if (!ctrl->nand_stat) - dev_err(priv->dev, "Controller is not responding\n"); - if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER) - dev_err(priv->dev, "NAND Flash Timeout Error\n"); - if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER) - dev_err(priv->dev, "NAND Flash Write Protect Error\n"); - - if (nctrl->eccread) { - int errors; - int bufnum = nctrl->page & priv->bufnum_mask; - int sector = bufnum * chip->ecc.steps; - int sector_end = sector + chip->ecc.steps - 1; - - for (i = sector / 4; i <= sector_end / 4; i++) - eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]); - - for (i = sector; i <= sector_end; i++) { - errors = check_read_ecc(mtd, ctrl, eccstat, i); - - if (errors == 15) { - /* - * Uncorrectable error. - * OK only if the whole page is blank. - * - * We disable ECCER reporting due to... - * erratum IFC-A002770 -- so report it now if we - * see an uncorrectable error in ECCSTAT. - */ - if (!is_blank(mtd, bufnum)) - ctrl->nand_stat |= - IFC_NAND_EVTER_STAT_ECCER; - break; - } - - mtd->ecc_stats.corrected += errors; - } - - nctrl->eccread = 0; - } -} - -static void fsl_ifc_do_read(struct nand_chip *chip, - int oob, - struct mtd_info *mtd) -{ - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_regs __iomem *ifc = ctrl->regs; - - /* Program FIR/IFC_NAND_FCR0 for Small/Large page */ - if (mtd->writesize > 512) { - out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT)); - out_be32(&ifc->ifc_nand.nand_fir1, 0x0); - - out_be32(&ifc->ifc_nand.nand_fcr0, - (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); - } else { - out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT)); - out_be32(&ifc->ifc_nand.nand_fir1, 0x0); - - if (oob) - out_be32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT); - else - out_be32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); - } -} - -/* cmdfunc send commands to the IFC NAND Machine */ -static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) { - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_regs __iomem *ifc = ctrl->regs; - - /* clear the read buffer */ - ifc_nand_ctrl->read_bytes = 0; - if (command != NAND_CMD_PAGEPROG) - ifc_nand_ctrl->index = 0; - - switch (command) { - /* READ0 read the entire buffer to use hardware ECC. */ - case NAND_CMD_READ0: - out_be32(&ifc->ifc_nand.nand_fbcr, 0); - set_addr(mtd, 0, page_addr, 0); - - ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize; - ifc_nand_ctrl->index += column; - - if (chip->ecc.mode == NAND_ECC_HW) - ifc_nand_ctrl->eccread = 1; - - fsl_ifc_do_read(chip, 0, mtd); - fsl_ifc_run_command(mtd); - return; - - /* READOOB reads only the OOB because no ECC is performed. */ - case NAND_CMD_READOOB: - out_be32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column); - set_addr(mtd, column, page_addr, 1); - - ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize; - - fsl_ifc_do_read(chip, 1, mtd); - fsl_ifc_run_command(mtd); - - return; - - /* READID must read all 8 possible bytes */ - case NAND_CMD_READID: - out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); - out_be32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); - /* 8 bytes for manuf, device and exts */ - out_be32(&ifc->ifc_nand.nand_fbcr, 8); - ifc_nand_ctrl->read_bytes = 8; - - set_addr(mtd, 0, 0, 0); - fsl_ifc_run_command(mtd); - return; - - /* ERASE1 stores the block and page address */ - case NAND_CMD_ERASE1: - set_addr(mtd, 0, page_addr, 0); - return; - - /* ERASE2 uses the block and page address from ERASE1 */ - case NAND_CMD_ERASE2: - out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT)); - - out_be32(&ifc->ifc_nand.nand_fcr0, - (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT)); - - out_be32(&ifc->ifc_nand.nand_fbcr, 0); - ifc_nand_ctrl->read_bytes = 0; - fsl_ifc_run_command(mtd); - return; - - /* SEQIN sets up the addr buffer and all registers except the length */ - case NAND_CMD_SEQIN: { - u32 nand_fcr0; - ifc_nand_ctrl->column = column; - ifc_nand_ctrl->oob = 0; - - if (mtd->writesize > 512) { - nand_fcr0 = - (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT); - - out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT)); - } else { - nand_fcr0 = ((NAND_CMD_PAGEPROG << - IFC_NAND_FCR0_CMD1_SHIFT) | - (NAND_CMD_SEQIN << - IFC_NAND_FCR0_CMD2_SHIFT)); - - out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) | - (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) | - (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) | - (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT)); - out_be32(&ifc->ifc_nand.nand_fir1, - (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT)); - - if (column >= mtd->writesize) - nand_fcr0 |= - NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT; - else - nand_fcr0 |= - NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT; - } - - if (column >= mtd->writesize) { - /* OOB area --> READOOB */ - column -= mtd->writesize; - ifc_nand_ctrl->oob = 1; - } - out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0); - set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob); - return; - } - - /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ - case NAND_CMD_PAGEPROG: { - if (ifc_nand_ctrl->oob) { - out_be32(&ifc->ifc_nand.nand_fbcr, - ifc_nand_ctrl->index - ifc_nand_ctrl->column); - } else { - out_be32(&ifc->ifc_nand.nand_fbcr, 0); - } - - fsl_ifc_run_command(mtd); - return; - } - - case NAND_CMD_STATUS: - out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT)); - out_be32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT); - out_be32(&ifc->ifc_nand.nand_fbcr, 1); - set_addr(mtd, 0, 0, 0); - ifc_nand_ctrl->read_bytes = 1; - - fsl_ifc_run_command(mtd); - - /* - * The chip always seems to report that it is - * write-protected, even when it is not. - */ - setbits8(ifc_nand_ctrl->addr, NAND_STATUS_WP); - return; - - case NAND_CMD_RESET: - out_be32(&ifc->ifc_nand.nand_fir0, - IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT); - out_be32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT); - fsl_ifc_run_command(mtd); - return; - - default: - dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n", - __func__, command); - } -} - -static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) -{ - /* The hardware does not seem to support multiple - * chips per bank. - */ -} - -/* - * Write buf to the IFC NAND Controller Data Buffer - */ -static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - unsigned int bufsize = mtd->writesize + mtd->oobsize; - - if (len <= 0) { - dev_err(priv->dev, "%s: len %d bytes", __func__, len); - return; - } - - if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) { - dev_err(priv->dev, - "%s: beyond end of buffer (%d requested, %u available)\n", - __func__, len, bufsize - ifc_nand_ctrl->index); - len = bufsize - ifc_nand_ctrl->index; - } - - memcpy_toio(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index], buf, len); - ifc_nand_ctrl->index += len; -} - -/* - * Read a byte from either the IFC hardware buffer - * read function for 8-bit buswidth - */ -static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - - /* - * If there are still bytes in the IFC buffer, then use the - * next byte. - */ - if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) - return in_8(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index++]); - - dev_err(priv->dev, "%s: beyond end of buffer\n", __func__); - return ERR_BYTE; -} - -/* - * Read two bytes from the IFC hardware buffer - * read function for 16-bit buswith - */ -static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - uint16_t data; - - /* - * If there are still bytes in the IFC buffer, then use the - * next byte. - */ - if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) { - data = in_be16((uint16_t *)&ifc_nand_ctrl-> - addr[ifc_nand_ctrl->index]); - ifc_nand_ctrl->index += 2; - return (uint8_t) data; - } - - dev_err(priv->dev, "%s: beyond end of buffer\n", __func__); - return ERR_BYTE; -} - -/* - * Read from the IFC Controller Data Buffer - */ -static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - int avail; - - if (len < 0) { - dev_err(priv->dev, "%s: len %d bytes", __func__, len); - return; - } - - avail = min((unsigned int)len, - ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index); - memcpy_fromio(buf, &ifc_nand_ctrl->addr[ifc_nand_ctrl->index], avail); - ifc_nand_ctrl->index += avail; - - if (len > avail) - dev_err(priv->dev, - "%s: beyond end of buffer (%d requested, %d available)\n", - __func__, len, avail); -} - -/* - * Verify buffer against the IFC Controller Data Buffer - */ -static int fsl_ifc_verify_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl; - int i; - - if (len < 0) { - dev_err(priv->dev, "%s: write_buf of %d bytes", __func__, len); - return -EINVAL; - } - - if ((unsigned int)len > nctrl->read_bytes - nctrl->index) { - dev_err(priv->dev, - "%s: beyond end of buffer (%d requested, %u available)\n", - __func__, len, nctrl->read_bytes - nctrl->index); - - nctrl->index = nctrl->read_bytes; - return -EINVAL; - } - - for (i = 0; i < len; i++) - if (in_8(&nctrl->addr[nctrl->index + i]) != buf[i]) - break; - - nctrl->index += len; - - if (i != len) - return -EIO; - if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) - return -EIO; - - return 0; -} - -/* - * This function is called after Program and Erase Operations to - * check for success or failure. - */ -static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) -{ - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_regs __iomem *ifc = ctrl->regs; - u32 nand_fsr; - - /* Use READ_STATUS command, but wait for the device to be ready */ - out_be32(&ifc->ifc_nand.nand_fir0, - (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | - (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT)); - out_be32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS << - IFC_NAND_FCR0_CMD0_SHIFT); - out_be32(&ifc->ifc_nand.nand_fbcr, 1); - set_addr(mtd, 0, 0, 0); - ifc_nand_ctrl->read_bytes = 1; - - fsl_ifc_run_command(mtd); - - nand_fsr = in_be32(&ifc->ifc_nand.nand_fsr); - - /* - * The chip always seems to report that it is - * write-protected, even when it is not. - */ - return nand_fsr | NAND_STATUS_WP; -} - -static int fsl_ifc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, int page) -{ - struct fsl_ifc_mtd *priv = chip->priv; - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - - fsl_ifc_read_buf(mtd, buf, mtd->writesize); - fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); - - if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) - dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n"); - - if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) - mtd->ecc_stats.failed++; - - return 0; -} - -/* ECC will be calculated automatically, and errors will be detected in - * waitfunc. - */ -static void fsl_ifc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf) -{ - fsl_ifc_write_buf(mtd, buf, mtd->writesize); - fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); -} - -static int fsl_ifc_chip_init_tail(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - struct fsl_ifc_mtd *priv = chip->priv; - - dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__, - chip->numchips); - dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__, - chip->chipsize); - dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__, - chip->pagemask); - dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__, - chip->chip_delay); - dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__, - chip->badblockpos); - dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__, - chip->chip_shift); - dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__, - chip->page_shift); - dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__, - chip->phys_erase_shift); - dev_dbg(priv->dev, "%s: nand->ecclayout = %p\n", __func__, - chip->ecclayout); - dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__, - chip->ecc.mode); - dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__, - chip->ecc.steps); - dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__, - chip->ecc.bytes); - dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__, - chip->ecc.total); - dev_dbg(priv->dev, "%s: nand->ecc.layout = %p\n", __func__, - chip->ecc.layout); - dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags); - dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size); - dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__, - mtd->erasesize); - dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__, - mtd->writesize); - dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__, - mtd->oobsize); - - return 0; -} - -static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) -{ - struct fsl_ifc_ctrl *ctrl = priv->ctrl; - struct fsl_ifc_regs __iomem *ifc = ctrl->regs; - struct nand_chip *chip = &priv->chip; - struct nand_ecclayout *layout; - u32 csor; - - /* Fill in fsl_ifc_mtd structure */ - priv->mtd.priv = chip; - priv->mtd.owner = THIS_MODULE; - - /* fill in nand_chip structure */ - /* set up function call table */ - if ((in_be32(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16) - chip->read_byte = fsl_ifc_read_byte16; - else - chip->read_byte = fsl_ifc_read_byte; - - chip->write_buf = fsl_ifc_write_buf; - chip->read_buf = fsl_ifc_read_buf; - chip->verify_buf = fsl_ifc_verify_buf; - chip->select_chip = fsl_ifc_select_chip; - chip->cmdfunc = fsl_ifc_cmdfunc; - chip->waitfunc = fsl_ifc_wait; - - chip->bbt_td = &bbt_main_descr; - chip->bbt_md = &bbt_mirror_descr; - - out_be32(&ifc->ifc_nand.ncfgr, 0x0); - - /* set up nand options */ - chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; - chip->bbt_options = NAND_BBT_USE_FLASH; - - - if (in_be32(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) { - chip->read_byte = fsl_ifc_read_byte16; - chip->options |= NAND_BUSWIDTH_16; - } else { - chip->read_byte = fsl_ifc_read_byte; - } - - chip->controller = &ifc_nand_ctrl->controller; - chip->priv = priv; - - chip->ecc.read_page = fsl_ifc_read_page; - chip->ecc.write_page = fsl_ifc_write_page; - - csor = in_be32(&ifc->csor_cs[priv->bank].csor); - - /* Hardware generates ECC per 512 Bytes */ - chip->ecc.size = 512; - chip->ecc.bytes = 8; - - switch (csor & CSOR_NAND_PGS_MASK) { - case CSOR_NAND_PGS_512: - if (chip->options & NAND_BUSWIDTH_16) { - layout = &oob_512_16bit_ecc4; - } else { - layout = &oob_512_8bit_ecc4; - - /* Avoid conflict with bad block marker */ - bbt_main_descr.offs = 0; - bbt_mirror_descr.offs = 0; - } - - priv->bufnum_mask = 15; - break; - - case CSOR_NAND_PGS_2K: - layout = &oob_2048_ecc4; - priv->bufnum_mask = 3; - break; - - case CSOR_NAND_PGS_4K: - if ((csor & CSOR_NAND_ECC_MODE_MASK) == - CSOR_NAND_ECC_MODE_4) { - layout = &oob_4096_ecc4; - } else { - layout = &oob_4096_ecc8; - chip->ecc.bytes = 16; - } - - priv->bufnum_mask = 1; - break; - - default: - dev_err(priv->dev, "bad csor %#x: bad page size\n", csor); - return -ENODEV; - } - - /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */ - if (csor & CSOR_NAND_ECC_DEC_EN) { - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.layout = layout; - } else { - chip->ecc.mode = NAND_ECC_SOFT; - } - - return 0; -} - -static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv) -{ - nand_release(&priv->mtd); - - kfree(priv->mtd.name); - - if (priv->vbase) - iounmap(priv->vbase); - - ifc_nand_ctrl->chips[priv->bank] = NULL; - dev_set_drvdata(priv->dev, NULL); - kfree(priv); - - return 0; -} - -static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank, - phys_addr_t addr) -{ - u32 cspr = in_be32(&ifc->cspr_cs[bank].cspr); - - if (!(cspr & CSPR_V)) - return 0; - if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND) - return 0; - - return (cspr & CSPR_BA) == convert_ifc_address(addr); -} - -static DEFINE_MUTEX(fsl_ifc_nand_mutex); - -static int __devinit fsl_ifc_nand_probe(struct platform_device *dev) -{ - struct fsl_ifc_regs __iomem *ifc; - struct fsl_ifc_mtd *priv; - struct resource res; - static const char *part_probe_types[] - = { "cmdlinepart", "RedBoot", "ofpart", NULL }; - int ret; - int bank; - struct device_node *node = dev->dev.of_node; - struct mtd_part_parser_data ppdata; - - ppdata.of_node = dev->dev.of_node; - if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs) - return -ENODEV; - ifc = fsl_ifc_ctrl_dev->regs; - - /* get, allocate and map the memory resource */ - ret = of_address_to_resource(node, 0, &res); - if (ret) { - dev_err(&dev->dev, "%s: failed to get resource\n", __func__); - return ret; - } - - /* find which chip select it is connected to */ - for (bank = 0; bank < FSL_IFC_BANK_COUNT; bank++) { - if (match_bank(ifc, bank, res.start)) - break; - } - - if (bank >= FSL_IFC_BANK_COUNT) { - dev_err(&dev->dev, "%s: address did not match any chip selects\n", - __func__); - return -ENODEV; - } - - priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - mutex_lock(&fsl_ifc_nand_mutex); - if (!fsl_ifc_ctrl_dev->nand) { - ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL); - if (!ifc_nand_ctrl) { - dev_err(&dev->dev, "failed to allocate memory\n"); - mutex_unlock(&fsl_ifc_nand_mutex); - return -ENOMEM; - } - - ifc_nand_ctrl->read_bytes = 0; - ifc_nand_ctrl->index = 0; - ifc_nand_ctrl->addr = NULL; - fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl; - - spin_lock_init(&ifc_nand_ctrl->controller.lock); - init_waitqueue_head(&ifc_nand_ctrl->controller.wq); - } else { - ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand; - } - mutex_unlock(&fsl_ifc_nand_mutex); - - ifc_nand_ctrl->chips[bank] = priv; - priv->bank = bank; - priv->ctrl = fsl_ifc_ctrl_dev; - priv->dev = &dev->dev; - - priv->vbase = ioremap(res.start, resource_size(&res)); - if (!priv->vbase) { - dev_err(priv->dev, "%s: failed to map chip region\n", __func__); - ret = -ENOMEM; - goto err; - } - - dev_set_drvdata(priv->dev, priv); - - out_be32(&ifc->ifc_nand.nand_evter_en, - IFC_NAND_EVTER_EN_OPC_EN | - IFC_NAND_EVTER_EN_FTOER_EN | - IFC_NAND_EVTER_EN_WPER_EN); - - /* enable NAND Machine Interrupts */ - out_be32(&ifc->ifc_nand.nand_evter_intr_en, - IFC_NAND_EVTER_INTR_OPCIR_EN | - IFC_NAND_EVTER_INTR_FTOERIR_EN | - IFC_NAND_EVTER_INTR_WPERIR_EN); - - priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start); - if (!priv->mtd.name) { - ret = -ENOMEM; - goto err; - } - - ret = fsl_ifc_chip_init(priv); - if (ret) - goto err; - - ret = nand_scan_ident(&priv->mtd, 1, NULL); - if (ret) - goto err; - - ret = fsl_ifc_chip_init_tail(&priv->mtd); - if (ret) - goto err; - - ret = nand_scan_tail(&priv->mtd); - if (ret) - goto err; - - /* First look for RedBoot table or partitions on the command - * line, these take precedence over device tree information */ - mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata, - NULL, 0); - - dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n", - (unsigned long long)res.start, priv->bank); - return 0; - -err: - fsl_ifc_chip_remove(priv); - return ret; -} - -static int fsl_ifc_nand_remove(struct platform_device *dev) -{ - struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev); - - fsl_ifc_chip_remove(priv); - - mutex_lock(&fsl_ifc_nand_mutex); - ifc_nand_ctrl->counter--; - if (!ifc_nand_ctrl->counter) { - fsl_ifc_ctrl_dev->nand = NULL; - kfree(ifc_nand_ctrl); - } - mutex_unlock(&fsl_ifc_nand_mutex); - - return 0; -} - -static const struct of_device_id fsl_ifc_nand_match[] = { - { - .compatible = "fsl,ifc-nand", - }, - {} -}; - -static struct platform_driver fsl_ifc_nand_driver = { - .driver = { - .name = "fsl,ifc-nand", - .owner = THIS_MODULE, - .of_match_table = fsl_ifc_nand_match, - }, - .probe = fsl_ifc_nand_probe, - .remove = fsl_ifc_nand_remove, -}; - -static int __init fsl_ifc_nand_init(void) -{ - int ret; - - ret = platform_driver_register(&fsl_ifc_nand_driver); - if (ret) - printk(KERN_ERR "fsl-ifc: Failed to register platform" - "driver\n"); - - return ret; -} - -static void __exit fsl_ifc_nand_exit(void) -{ - platform_driver_unregister(&fsl_ifc_nand_driver); -} - -module_init(fsl_ifc_nand_init); -module_exit(fsl_ifc_nand_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Freescale"); -MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver"); diff --git a/trunk/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/trunk/drivers/net/ethernet/brocade/bna/bnad_debugfs.c index 6e8bc9d88c41..c9fdceb135f3 100644 --- a/trunk/drivers/net/ethernet/brocade/bna/bnad_debugfs.c +++ b/trunk/drivers/net/ethernet/brocade/bna/bnad_debugfs.c @@ -516,7 +516,7 @@ static const struct file_operations bnad_debugfs_op_drvinfo = { struct bnad_debugfs_entry { const char *name; - umode_t mode; + mode_t mode; const struct file_operations *fops; }; diff --git a/trunk/drivers/net/macvtap.c b/trunk/drivers/net/macvtap.c index 0427c6561c84..58dc117a8d78 100644 --- a/trunk/drivers/net/macvtap.c +++ b/trunk/drivers/net/macvtap.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include diff --git a/trunk/drivers/oprofile/oprofilefs.c b/trunk/drivers/oprofile/oprofilefs.c index ee8fd037bb53..2f0aa0f700e6 100644 --- a/trunk/drivers/oprofile/oprofilefs.c +++ b/trunk/drivers/oprofile/oprofilefs.c @@ -238,6 +238,7 @@ struct dentry *oprofilefs_mkdir(struct super_block *sb, static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *root_inode; + struct dentry *root_dentry; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -250,11 +251,15 @@ static int oprofilefs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; root_inode->i_op = &simple_dir_inode_operations; root_inode->i_fop = &simple_dir_operations; - sb->s_root = d_make_root(root_inode); - if (!sb->s_root) + root_dentry = d_alloc_root(root_inode); + if (!root_dentry) { + iput(root_inode); return -ENOMEM; + } + + sb->s_root = root_dentry; - oprofile_create_files(sb, sb->s_root); + oprofile_create_files(sb, root_dentry); // FIXME: verify kill_litter_super removes our dentries return 0; diff --git a/trunk/drivers/scsi/Kconfig b/trunk/drivers/scsi/Kconfig index 4e89103204dc..d3d18e89cb57 100644 --- a/trunk/drivers/scsi/Kconfig +++ b/trunk/drivers/scsi/Kconfig @@ -974,8 +974,9 @@ config SCSI_IPS config SCSI_IBMVSCSI tristate "IBM Virtual SCSI support" - depends on PPC_PSERIES + depends on PPC_PSERIES || PPC_ISERIES select SCSI_SRP_ATTRS + select VIOPATH if PPC_ISERIES help This is the IBM POWER Virtual SCSI Client diff --git a/trunk/drivers/scsi/ibmvscsi/Makefile b/trunk/drivers/scsi/ibmvscsi/Makefile index ff5b5c5538ee..a423d9633625 100644 --- a/trunk/drivers/scsi/ibmvscsi/Makefile +++ b/trunk/drivers/scsi/ibmvscsi/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o ibmvscsic-y += ibmvscsi.o +ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o diff --git a/trunk/drivers/scsi/ibmvscsi/ibmvscsi.c b/trunk/drivers/scsi/ibmvscsi/ibmvscsi.c index e984951baeb6..3d391dc3f11f 100644 --- a/trunk/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/trunk/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -55,7 +55,13 @@ * and sends a CRQ message back to inform the client that the request has * completed. * - * TODO: This is currently pretty tied to the IBM pSeries hypervisor + * Note that some of the underlying infrastructure is different between + * machines conforming to the "RS/6000 Platform Architecture" (RPA) and + * the older iSeries hypervisor models. To support both, some low level + * routines have been broken out into rpa_vscsi.c and iseries_vscsi.c. + * The Makefile should pick one, not two, not zero, of these. + * + * TODO: This is currently pretty tied to the IBM i/pSeries hypervisor * interfaces. It would be really nice to abstract this above an RDMA * layer. */ @@ -2079,7 +2085,9 @@ int __init ibmvscsi_module_init(void) driver_template.can_queue = max_requests; max_events = max_requests + 2; - if (firmware_has_feature(FW_FEATURE_VIO)) + if (firmware_has_feature(FW_FEATURE_ISERIES)) + ibmvscsi_ops = &iseriesvscsi_ops; + else if (firmware_has_feature(FW_FEATURE_VIO)) ibmvscsi_ops = &rpavscsi_ops; else return -ENODEV; diff --git a/trunk/drivers/scsi/ibmvscsi/ibmvscsi.h b/trunk/drivers/scsi/ibmvscsi/ibmvscsi.h index c503e1776014..02197a2b22b9 100644 --- a/trunk/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/trunk/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -127,6 +127,7 @@ struct ibmvscsi_ops { int (*resume) (struct ibmvscsi_host_data *hostdata); }; +extern struct ibmvscsi_ops iseriesvscsi_ops; extern struct ibmvscsi_ops rpavscsi_ops; #endif /* IBMVSCSI_H */ diff --git a/trunk/drivers/scsi/ibmvscsi/iseries_vscsi.c b/trunk/drivers/scsi/ibmvscsi/iseries_vscsi.c new file mode 100644 index 000000000000..f4776451a754 --- /dev/null +++ b/trunk/drivers/scsi/ibmvscsi/iseries_vscsi.c @@ -0,0 +1,173 @@ +/* ------------------------------------------------------------ + * iSeries_vscsi.c + * (C) Copyright IBM Corporation 1994, 2003 + * Authors: Colin DeVilbiss (devilbis@us.ibm.com) + * Santiago Leon (santil@us.ibm.com) + * Dave Boutcher (sleddog@us.ibm.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA + * + * ------------------------------------------------------------ + * iSeries-specific functions of the SCSI host adapter for Virtual I/O devices + * + * This driver allows the Linux SCSI peripheral drivers to directly + * access devices in the hosting partition, either on an iSeries + * hypervisor system or a converged hypervisor system. + */ + +#include +#include +#include +#include +#include +#include +#include "ibmvscsi.h" + +/* global variables */ +static struct ibmvscsi_host_data *single_host_data; + +/* ------------------------------------------------------------ + * Routines for direct interpartition interaction + */ +struct srp_lp_event { + struct HvLpEvent lpevt; /* 0x00-0x17 */ + u32 reserved1; /* 0x18-0x1B; unused */ + u16 version; /* 0x1C-0x1D; unused */ + u16 subtype_rc; /* 0x1E-0x1F; unused */ + struct viosrp_crq crq; /* 0x20-0x3F */ +}; + +/** + * standard interface for handling logical partition events. + */ +static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt) +{ + struct srp_lp_event *evt = (struct srp_lp_event *)lpevt; + + if (!evt) { + printk(KERN_ERR "ibmvscsi: received null event\n"); + return; + } + + if (single_host_data == NULL) { + printk(KERN_ERR + "ibmvscsi: received event, no adapter present\n"); + return; + } + + ibmvscsi_handle_crq(&evt->crq, single_host_data); +} + +/* ------------------------------------------------------------ + * Routines for driver initialization + */ +static int iseriesvscsi_init_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + int rc; + + single_host_data = hostdata; + rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, max_requests); + if (rc < 0) { + printk("viopath_open failed with rc %d in open_event_path\n", + rc); + goto viopath_open_failed; + } + + rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event); + if (rc < 0) { + printk("vio_setHandler failed with rc %d in open_event_path\n", + rc); + goto vio_setHandler_failed; + } + return 0; + + vio_setHandler_failed: + viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests); + viopath_open_failed: + return -1; +} + +static void iseriesvscsi_release_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata, + int max_requests) +{ + vio_clearHandler(viomajorsubtype_scsi); + viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests); +} + +/** + * reset_crq_queue: - resets a crq after a failure + * @queue: crq_queue to initialize and register + * @hostdata: ibmvscsi_host_data of host + * + * no-op for iSeries + */ +static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) +{ + return 0; +} + +/** + * reenable_crq_queue: - reenables a crq after a failure + * @queue: crq_queue to initialize and register + * @hostdata: ibmvscsi_host_data of host + * + * no-op for iSeries + */ +static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue, + struct ibmvscsi_host_data *hostdata) +{ + return 0; +} + +/** + * iseriesvscsi_send_crq: - Send a CRQ + * @hostdata: the adapter + * @word1: the first 64 bits of the data + * @word2: the second 64 bits of the data + */ +static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata, + u64 word1, u64 word2) +{ + single_host_data = hostdata; + return HvCallEvent_signalLpEventFast(viopath_hostLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_scsi, + HvLpEvent_AckInd_NoAck, + HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(viopath_hostLp), + viopath_targetinst(viopath_hostLp), + 0, + VIOVERSION << 16, word1, word2, 0, + 0); +} + +static int iseriesvscsi_resume(struct ibmvscsi_host_data *hostdata) +{ + return 0; +} + +struct ibmvscsi_ops iseriesvscsi_ops = { + .init_crq_queue = iseriesvscsi_init_crq_queue, + .release_crq_queue = iseriesvscsi_release_crq_queue, + .reset_crq_queue = iseriesvscsi_reset_crq_queue, + .reenable_crq_queue = iseriesvscsi_reenable_crq_queue, + .send_crq = iseriesvscsi_send_crq, + .resume = iseriesvscsi_resume, +}; diff --git a/trunk/drivers/target/iscsi/iscsi_target.c b/trunk/drivers/target/iscsi/iscsi_target.c index 1c6f700f5faa..501b27c18145 100644 --- a/trunk/drivers/target/iscsi/iscsi_target.c +++ b/trunk/drivers/target/iscsi/iscsi_target.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/target/iscsi/iscsi_target_login.c b/trunk/drivers/target/iscsi/iscsi_target_login.c index 1ee33a8c3fab..38cb7ce8469e 100644 --- a/trunk/drivers/target/iscsi/iscsi_target_login.c +++ b/trunk/drivers/target/iscsi/iscsi_target_login.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/drivers/tty/hvc/Kconfig b/trunk/drivers/tty/hvc/Kconfig index 48cb8d3d1758..4222035acfb7 100644 --- a/trunk/drivers/tty/hvc/Kconfig +++ b/trunk/drivers/tty/hvc/Kconfig @@ -24,6 +24,16 @@ config HVC_OLD_HVSI depends on HVC_CONSOLE default n +config HVC_ISERIES + bool "iSeries Hypervisor Virtual Console support" + depends on PPC_ISERIES + default y + select HVC_DRIVER + select HVC_IRQ + select VIOPATH + help + iSeries machines support a hypervisor virtual console. + config HVC_OPAL bool "OPAL Console support" depends on PPC_POWERNV @@ -71,10 +81,6 @@ config HVC_UDBG depends on PPC && EXPERIMENTAL select HVC_DRIVER default n - help - This is meant to be used during HW bring up or debugging when - no other console mechanism exist but udbg, to get you a quick - console for userspace. Do NOT enable in production kernels. config HVC_DCC bool "ARM JTAG DCC console" diff --git a/trunk/drivers/tty/hvc/Makefile b/trunk/drivers/tty/hvc/Makefile index 4ca3723b0a3a..89abf40bc73d 100644 --- a/trunk/drivers/tty/hvc/Makefile +++ b/trunk/drivers/tty/hvc/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o obj-$(CONFIG_HVC_OPAL) += hvc_opal.o hvsi_lib.o obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o +obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_TILE) += hvc_tile.o obj-$(CONFIG_HVC_DCC) += hvc_dcc.o diff --git a/trunk/drivers/tty/hvc/hvc_iseries.c b/trunk/drivers/tty/hvc/hvc_iseries.c new file mode 100644 index 000000000000..3f4a897bf4d7 --- /dev/null +++ b/trunk/drivers/tty/hvc/hvc_iseries.c @@ -0,0 +1,599 @@ +/* + * iSeries vio driver interface to hvc_console.c + * + * This code is based heavily on hvc_vio.c and viocons.c + * + * Copyright (C) 2006 Stephen Rothwell, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hvc_console.h" + +#define VTTY_PORTS 10 + +static DEFINE_SPINLOCK(consolelock); +static DEFINE_SPINLOCK(consoleloglock); + +static const char hvc_driver_name[] = "hvc_console"; + +#define IN_BUF_SIZE 200 + +/* + * Our port information. + */ +static struct port_info { + HvLpIndex lp; + u64 seq; /* sequence number of last HV send */ + u64 ack; /* last ack from HV */ + struct hvc_struct *hp; + int in_start; + int in_end; + unsigned char in_buf[IN_BUF_SIZE]; +} port_info[VTTY_PORTS] = { + [ 0 ... VTTY_PORTS - 1 ] = { + .lp = HvLpIndexInvalid + } +}; + +#define viochar_is_console(pi) ((pi) == &port_info[0]) + +static struct vio_device_id hvc_driver_table[] __devinitdata = { + {"serial", "IBM,iSeries-vty"}, + { "", "" } +}; +MODULE_DEVICE_TABLE(vio, hvc_driver_table); + +static void hvlog(char *fmt, ...) +{ + int i; + unsigned long flags; + va_list args; + static char buf[256]; + + spin_lock_irqsave(&consoleloglock, flags); + va_start(args, fmt); + i = vscnprintf(buf, sizeof(buf) - 1, fmt, args); + va_end(args); + buf[i++] = '\r'; + HvCall_writeLogBuffer(buf, i); + spin_unlock_irqrestore(&consoleloglock, flags); +} + +/* + * Initialize the common fields in a charLpEvent + */ +static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp) +{ + struct HvLpEvent *hev = &viochar->event; + + memset(viochar, 0, sizeof(struct viocharlpevent)); + + hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK | + HV_LP_EVENT_INT; + hev->xType = HvLpEvent_Type_VirtualIo; + hev->xSubtype = viomajorsubtype_chario | viochardata; + hev->xSourceLp = HvLpConfig_getLpIndex(); + hev->xTargetLp = lp; + hev->xSizeMinus1 = sizeof(struct viocharlpevent); + hev->xSourceInstanceId = viopath_sourceinst(lp); + hev->xTargetInstanceId = viopath_targetinst(lp); +} + +static int get_chars(uint32_t vtermno, char *buf, int count) +{ + struct port_info *pi; + int n = 0; + unsigned long flags; + + if (vtermno >= VTTY_PORTS) + return -EINVAL; + if (count == 0) + return 0; + + pi = &port_info[vtermno]; + spin_lock_irqsave(&consolelock, flags); + + if (pi->in_end == 0) + goto done; + + n = pi->in_end - pi->in_start; + if (n > count) + n = count; + memcpy(buf, &pi->in_buf[pi->in_start], n); + pi->in_start += n; + if (pi->in_start == pi->in_end) { + pi->in_start = 0; + pi->in_end = 0; + } +done: + spin_unlock_irqrestore(&consolelock, flags); + return n; +} + +static int put_chars(uint32_t vtermno, const char *buf, int count) +{ + struct viocharlpevent *viochar; + struct port_info *pi; + HvLpEvent_Rc hvrc; + unsigned long flags; + int sent = 0; + + if (vtermno >= VTTY_PORTS) + return -EINVAL; + + pi = &port_info[vtermno]; + + spin_lock_irqsave(&consolelock, flags); + + if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) { + HvCall_writeLogBuffer(buf, count); + sent = count; + goto done; + } + + viochar = vio_get_event_buffer(viomajorsubtype_chario); + if (viochar == NULL) { + hvlog("\n\rviocons: Can't get viochar buffer."); + goto done; + } + + while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { + int len; + + len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count; + + if (viochar_is_console(pi)) + HvCall_writeLogBuffer(buf, len); + + init_data_event(viochar, pi->lp); + + viochar->len = len; + viochar->event.xCorrelationToken = pi->seq++; + viochar->event.xSizeMinus1 = + offsetof(struct viocharlpevent, data) + len; + + memcpy(viochar->data, buf, len); + + hvrc = HvCallEvent_signalLpEvent(&viochar->event); + if (hvrc) + hvlog("\n\rerror sending event! return code %d\n\r", + (int)hvrc); + sent += len; + count -= len; + buf += len; + } + + vio_free_event_buffer(viomajorsubtype_chario, viochar); +done: + spin_unlock_irqrestore(&consolelock, flags); + return sent; +} + +static const struct hv_ops hvc_get_put_ops = { + .get_chars = get_chars, + .put_chars = put_chars, + .notifier_add = notifier_add_irq, + .notifier_del = notifier_del_irq, + .notifier_hangup = notifier_hangup_irq, +}; + +static int __devinit hvc_vio_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + struct hvc_struct *hp; + struct port_info *pi; + + /* probed with invalid parameters. */ + if (!vdev || !id) + return -EPERM; + + if (vdev->unit_address >= VTTY_PORTS) + return -ENODEV; + + pi = &port_info[vdev->unit_address]; + + hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops, + VIOCHAR_MAX_DATA); + if (IS_ERR(hp)) + return PTR_ERR(hp); + pi->hp = hp; + dev_set_drvdata(&vdev->dev, pi); + + return 0; +} + +static int __devexit hvc_vio_remove(struct vio_dev *vdev) +{ + struct port_info *pi = dev_get_drvdata(&vdev->dev); + struct hvc_struct *hp = pi->hp; + + return hvc_remove(hp); +} + +static struct vio_driver hvc_vio_driver = { + .id_table = hvc_driver_table, + .probe = hvc_vio_probe, + .remove = __devexit_p(hvc_vio_remove), + .driver = { + .name = hvc_driver_name, + .owner = THIS_MODULE, + } +}; + +static void hvc_open_event(struct HvLpEvent *event) +{ + unsigned long flags; + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + u8 port = cevent->virtual_device; + struct port_info *pi; + int reject = 0; + + if (hvlpevent_is_ack(event)) { + if (port >= VTTY_PORTS) + return; + + spin_lock_irqsave(&consolelock, flags); + + pi = &port_info[port]; + if (event->xRc == HvLpEvent_Rc_Good) { + pi->seq = pi->ack = 0; + /* + * This line allows connections from the primary + * partition but once one is connected from the + * primary partition nothing short of a reboot + * of linux will allow access from the hosting + * partition again without a required iSeries fix. + */ + pi->lp = event->xTargetLp; + } + + spin_unlock_irqrestore(&consolelock, flags); + if (event->xRc != HvLpEvent_Rc_Good) + printk(KERN_WARNING + "hvc: handle_open_event: event->xRc == (%d).\n", + event->xRc); + + if (event->xCorrelationToken != 0) { + atomic_t *aptr= (atomic_t *)event->xCorrelationToken; + atomic_set(aptr, 1); + } else + printk(KERN_WARNING + "hvc: weird...got open ack without atomic\n"); + return; + } + + /* This had better require an ack, otherwise complain */ + if (!hvlpevent_need_ack(event)) { + printk(KERN_WARNING "hvc: viocharopen without ack bit!\n"); + return; + } + + spin_lock_irqsave(&consolelock, flags); + + /* Make sure this is a good virtual tty */ + if (port >= VTTY_PORTS) { + event->xRc = HvLpEvent_Rc_SubtypeError; + cevent->subtype_result_code = viorc_openRejected; + /* + * Flag state here since we can't printk while holding + * the consolelock spinlock. + */ + reject = 1; + } else { + pi = &port_info[port]; + if ((pi->lp != HvLpIndexInvalid) && + (pi->lp != event->xSourceLp)) { + /* + * If this is tty is already connected to a different + * partition, fail. + */ + event->xRc = HvLpEvent_Rc_SubtypeError; + cevent->subtype_result_code = viorc_openRejected; + reject = 2; + } else { + pi->lp = event->xSourceLp; + event->xRc = HvLpEvent_Rc_Good; + cevent->subtype_result_code = viorc_good; + pi->seq = pi->ack = 0; + } + } + + spin_unlock_irqrestore(&consolelock, flags); + + if (reject == 1) + printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n"); + else if (reject == 2) + printk(KERN_WARNING "hvc: open rejected: console in exclusive " + "use by another partition.\n"); + + /* Return the acknowledgement */ + HvCallEvent_ackLpEvent(event); +} + +/* + * Handle a close charLpEvent. This should ONLY be an Interrupt because the + * virtual console should never actually issue a close event to the hypervisor + * because the virtual console never goes away. A close event coming from the + * hypervisor simply means that there are no client consoles connected to the + * virtual console. + */ +static void hvc_close_event(struct HvLpEvent *event) +{ + unsigned long flags; + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + u8 port = cevent->virtual_device; + + if (!hvlpevent_is_int(event)) { + printk(KERN_WARNING + "hvc: got unexpected close acknowledgement\n"); + return; + } + + if (port >= VTTY_PORTS) { + printk(KERN_WARNING + "hvc: close message from invalid virtual device.\n"); + return; + } + + /* For closes, just mark the console partition invalid */ + spin_lock_irqsave(&consolelock, flags); + + if (port_info[port].lp == event->xSourceLp) + port_info[port].lp = HvLpIndexInvalid; + + spin_unlock_irqrestore(&consolelock, flags); +} + +static void hvc_data_event(struct HvLpEvent *event) +{ + unsigned long flags; + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + struct port_info *pi; + int n; + u8 port = cevent->virtual_device; + + if (port >= VTTY_PORTS) { + printk(KERN_WARNING "hvc: data on invalid virtual device %d\n", + port); + return; + } + if (cevent->len == 0) + return; + + /* + * Change 05/01/2003 - Ryan Arnold: If a partition other than + * the current exclusive partition tries to send us data + * events then just drop them on the floor because we don't + * want his stinking data. He isn't authorized to receive + * data because he wasn't the first one to get the console, + * therefore he shouldn't be allowed to send data either. + * This will work without an iSeries fix. + */ + pi = &port_info[port]; + if (pi->lp != event->xSourceLp) + return; + + spin_lock_irqsave(&consolelock, flags); + + n = IN_BUF_SIZE - pi->in_end; + if (n > cevent->len) + n = cevent->len; + if (n > 0) { + memcpy(&pi->in_buf[pi->in_end], cevent->data, n); + pi->in_end += n; + } + spin_unlock_irqrestore(&consolelock, flags); + if (n == 0) + printk(KERN_WARNING "hvc: input buffer overflow\n"); +} + +static void hvc_ack_event(struct HvLpEvent *event) +{ + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + unsigned long flags; + u8 port = cevent->virtual_device; + + if (port >= VTTY_PORTS) { + printk(KERN_WARNING "hvc: data on invalid virtual device\n"); + return; + } + + spin_lock_irqsave(&consolelock, flags); + port_info[port].ack = event->xCorrelationToken; + spin_unlock_irqrestore(&consolelock, flags); +} + +static void hvc_config_event(struct HvLpEvent *event) +{ + struct viocharlpevent *cevent = (struct viocharlpevent *)event; + + if (cevent->data[0] == 0x01) + printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n", + cevent->data[1], cevent->data[2], + cevent->data[3], cevent->data[4]); + else + printk(KERN_WARNING "hvc: unknown config event\n"); +} + +static void hvc_handle_event(struct HvLpEvent *event) +{ + int charminor; + + if (event == NULL) + return; + + charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; + switch (charminor) { + case viocharopen: + hvc_open_event(event); + break; + case viocharclose: + hvc_close_event(event); + break; + case viochardata: + hvc_data_event(event); + break; + case viocharack: + hvc_ack_event(event); + break; + case viocharconfig: + hvc_config_event(event); + break; + default: + if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { + event->xRc = HvLpEvent_Rc_InvalidSubtype; + HvCallEvent_ackLpEvent(event); + } + } +} + +static int __init send_open(HvLpIndex remoteLp, void *sem) +{ + return HvCallEvent_signalLpEventFast(remoteLp, + HvLpEvent_Type_VirtualIo, + viomajorsubtype_chario | viocharopen, + HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, + viopath_sourceinst(remoteLp), + viopath_targetinst(remoteLp), + (u64)(unsigned long)sem, VIOVERSION << 16, + 0, 0, 0, 0); +} + +static int __init hvc_vio_init(void) +{ + atomic_t wait_flag; + int rc; + + if (!firmware_has_feature(FW_FEATURE_ISERIES)) + return -EIO; + + /* +2 for fudge */ + rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), + viomajorsubtype_chario, VIOCHAR_WINDOW + 2); + if (rc) + printk(KERN_WARNING "hvc: error opening to primary %d\n", rc); + + if (viopath_hostLp == HvLpIndexInvalid) + vio_set_hostlp(); + + /* + * And if the primary is not the same as the hosting LP, open to the + * hosting lp + */ + if ((viopath_hostLp != HvLpIndexInvalid) && + (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) { + printk(KERN_INFO "hvc: open path to hosting (%d)\n", + viopath_hostLp); + rc = viopath_open(viopath_hostLp, viomajorsubtype_chario, + VIOCHAR_WINDOW + 2); /* +2 for fudge */ + if (rc) + printk(KERN_WARNING + "error opening to partition %d: %d\n", + viopath_hostLp, rc); + } + + if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0) + printk(KERN_WARNING + "hvc: error seting handler for console events!\n"); + + /* + * First, try to open the console to the hosting lp. + * Wait on a semaphore for the response. + */ + atomic_set(&wait_flag, 0); + if ((viopath_isactive(viopath_hostLp)) && + (send_open(viopath_hostLp, &wait_flag) == 0)) { + printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp); + while (atomic_read(&wait_flag) == 0) + mb(); + atomic_set(&wait_flag, 0); + } + + /* + * If we don't have an active console, try the primary + */ + if ((!viopath_isactive(port_info[0].lp)) && + (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) && + (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) { + printk(KERN_INFO "hvc: opening console to primary partition\n"); + while (atomic_read(&wait_flag) == 0) + mb(); + } + + /* Register as a vio device to receive callbacks */ + rc = vio_register_driver(&hvc_vio_driver); + + return rc; +} +module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ + +static void __exit hvc_vio_exit(void) +{ + vio_unregister_driver(&hvc_vio_driver); +} +module_exit(hvc_vio_exit); + +/* the device tree order defines our numbering */ +static int __init hvc_find_vtys(void) +{ + struct device_node *vty; + int num_found = 0; + + for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; + vty = of_find_node_by_name(vty, "vty")) { + const uint32_t *vtermno; + + /* We have statically defined space for only a certain number + * of console adapters. + */ + if ((num_found >= MAX_NR_HVC_CONSOLES) || + (num_found >= VTTY_PORTS)) { + of_node_put(vty); + break; + } + + vtermno = of_get_property(vty, "reg", NULL); + if (!vtermno) + continue; + + if (!of_device_is_compatible(vty, "IBM,iSeries-vty")) + continue; + + if (num_found == 0) + add_preferred_console("hvc", 0, NULL); + hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); + ++num_found; + } + + return num_found; +} +console_initcall(hvc_find_vtys); diff --git a/trunk/drivers/tty/hvc/hvc_udbg.c b/trunk/drivers/tty/hvc/hvc_udbg.c index 72228276fe31..4c9b13e7748c 100644 --- a/trunk/drivers/tty/hvc/hvc_udbg.c +++ b/trunk/drivers/tty/hvc/hvc_udbg.c @@ -36,7 +36,7 @@ static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) { int i; - for (i = 0; i < count && udbg_putc; i++) + for (i = 0; i < count; i++) udbg_putc(buf[i]); return i; @@ -67,9 +67,6 @@ static int __init hvc_udbg_init(void) { struct hvc_struct *hp; - if (!udbg_putc) - return -ENODEV; - BUG_ON(hvc_udbg_dev); hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16); @@ -91,9 +88,6 @@ module_exit(hvc_udbg_exit); static int __init hvc_udbg_console_init(void) { - if (!udbg_putc) - return -ENODEV; - hvc_instantiate(0, 0, &hvc_udbg_ops); add_preferred_console("hvc", 0, NULL); diff --git a/trunk/drivers/tty/hvc/hvc_vio.c b/trunk/drivers/tty/hvc/hvc_vio.c index 3a0d53d6368f..fc3c3ad6c072 100644 --- a/trunk/drivers/tty/hvc/hvc_vio.c +++ b/trunk/drivers/tty/hvc/hvc_vio.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -321,6 +322,9 @@ static int __init hvc_vio_init(void) { int rc; + if (firmware_has_feature(FW_FEATURE_ISERIES)) + return -EIO; + /* Register as a vio device to receive callbacks */ rc = vio_register_driver(&hvc_vio_driver); diff --git a/trunk/drivers/tty/serial/Kconfig b/trunk/drivers/tty/serial/Kconfig index 665beb68f670..76e7764488e6 100644 --- a/trunk/drivers/tty/serial/Kconfig +++ b/trunk/drivers/tty/serial/Kconfig @@ -853,7 +853,7 @@ config SERIAL_MPC52xx_CONSOLE_BAUD config SERIAL_ICOM tristate "IBM Multiport Serial Adapter" - depends on PCI && PPC_PSERIES + depends on PCI && (PPC_ISERIES || PPC_PSERIES) select SERIAL_CORE select FW_LOADER help diff --git a/trunk/drivers/usb/core/inode.c b/trunk/drivers/usb/core/inode.c index cefa0c8b5b6a..9e186f3da839 100644 --- a/trunk/drivers/usb/core/inode.c +++ b/trunk/drivers/usb/core/inode.c @@ -50,6 +50,7 @@ static const struct file_operations default_file_operations; static struct vfsmount *usbfs_mount; static int usbfs_mount_count; /* = 0 */ +static int ignore_mount = 0; static struct dentry *devices_usbfs_dentry; static int num_buses; /* = 0 */ @@ -255,7 +256,7 @@ static int remount(struct super_block *sb, int *flags, char *data) * i.e. it's a simple_pin_fs from create_special_files, * then ignore it. */ - if (*flags & MS_KERNMOUNT) + if (ignore_mount) return 0; if (parse_options(sb, data)) { @@ -453,6 +454,7 @@ static const struct super_operations usbfs_ops = { static int usbfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; + struct dentry *root; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; @@ -460,11 +462,19 @@ static int usbfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_op = &usbfs_ops; sb->s_time_gran = 1; inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); - sb->s_root = d_make_root(inode); - if (!sb->s_root) { + + if (!inode) { + dbg("%s: could not get inode!",__func__); + return -ENOMEM; + } + + root = d_alloc_root(inode); + if (!root) { dbg("%s: could not get root dentry!",__func__); + iput(inode); return -ENOMEM; } + sb->s_root = root; return 0; } @@ -581,6 +591,11 @@ static int create_special_files (void) struct dentry *parent; int retval; + /* the simple_pin_fs calls will call remount with no options + * without this flag that would overwrite the real mount options (if any) + */ + ignore_mount = 1; + /* create the devices special file */ retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count); if (retval) { @@ -588,6 +603,8 @@ static int create_special_files (void) goto exit; } + ignore_mount = 0; + parent = usbfs_mount->mnt_root; devices_usbfs_dentry = fs_create_file ("devices", listmode | S_IFREG, parent, diff --git a/trunk/drivers/usb/gadget/f_fs.c b/trunk/drivers/usb/gadget/f_fs.c index 1cbba70836bc..7f445ec723bc 100644 --- a/trunk/drivers/usb/gadget/f_fs.c +++ b/trunk/drivers/usb/gadget/f_fs.c @@ -1063,9 +1063,13 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) &simple_dir_operations, &simple_dir_inode_operations, &data->perms); - sb->s_root = d_make_root(inode); - if (unlikely(!sb->s_root)) + if (unlikely(!inode)) goto Enomem; + sb->s_root = d_alloc_root(inode); + if (unlikely(!sb->s_root)) { + iput(inode); + goto Enomem; + } /* EP0 file */ if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs, diff --git a/trunk/drivers/usb/gadget/inode.c b/trunk/drivers/usb/gadget/inode.c index 8793f32bab11..4f18a0e46070 100644 --- a/trunk/drivers/usb/gadget/inode.c +++ b/trunk/drivers/usb/gadget/inode.c @@ -1571,18 +1571,20 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) static void destroy_ep_files (struct dev_data *dev) { + struct list_head *entry, *tmp; + DBG (dev, "%s %d\n", __func__, dev->state); /* dev->state must prevent interference */ restart: spin_lock_irq (&dev->lock); - while (!list_empty(&dev->epfiles)) { + list_for_each_safe (entry, tmp, &dev->epfiles) { struct ep_data *ep; struct inode *parent; struct dentry *dentry; /* break link to FS */ - ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles); + ep = list_entry (entry, struct ep_data, epfiles); list_del_init (&ep->epfiles); dentry = ep->dentry; ep->dentry = NULL; @@ -1605,7 +1607,8 @@ static void destroy_ep_files (struct dev_data *dev) dput (dentry); mutex_unlock (&parent->i_mutex); - spin_lock_irq (&dev->lock); + /* fds may still be open */ + goto restart; } spin_unlock_irq (&dev->lock); } @@ -2058,8 +2061,10 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent) if (!inode) goto Enomem; inode->i_op = &simple_dir_inode_operations; - if (!(sb->s_root = d_make_root (inode))) + if (!(sb->s_root = d_alloc_root (inode))) { + iput(inode); goto Enomem; + } /* the ep0 file is named after the controller we expect; * user mode code can use it for sanity checks, like we do. diff --git a/trunk/drivers/watchdog/Kconfig b/trunk/drivers/watchdog/Kconfig index 7e9e8f4d8f0c..df9e8f0e327d 100644 --- a/trunk/drivers/watchdog/Kconfig +++ b/trunk/drivers/watchdog/Kconfig @@ -1039,7 +1039,7 @@ config LANTIQ_WDT config GEF_WDT tristate "GE Watchdog Timer" - depends on GE_FPGA + depends on GEF_SBC610 || GEF_SBC310 || GEF_PPC9A ---help--- Watchdog timer found in a number of GE single board computers. diff --git a/trunk/fs/9p/v9fs.c b/trunk/fs/9p/v9fs.c index b85efa773949..1964f98e74be 100644 --- a/trunk/fs/9p/v9fs.c +++ b/trunk/fs/9p/v9fs.c @@ -594,21 +594,21 @@ static int __init init_v9fs(void) int err; pr_info("Installing v9fs 9p2000 file system support\n"); /* TODO: Setup list of registered trasnport modules */ + err = register_filesystem(&v9fs_fs_type); + if (err < 0) { + pr_err("Failed to register filesystem\n"); + return err; + } err = v9fs_cache_register(); if (err < 0) { pr_err("Failed to register v9fs for caching\n"); - return err; + goto out_fs_unreg; } err = v9fs_sysfs_init(); if (err < 0) { pr_err("Failed to register with sysfs\n"); - goto out_cache; - } - err = register_filesystem(&v9fs_fs_type); - if (err < 0) { - pr_err("Failed to register filesystem\n"); goto out_sysfs_cleanup; } @@ -617,8 +617,8 @@ static int __init init_v9fs(void) out_sysfs_cleanup: v9fs_sysfs_cleanup(); -out_cache: - v9fs_cache_unregister(); +out_fs_unreg: + unregister_filesystem(&v9fs_fs_type); return err; } diff --git a/trunk/fs/9p/vfs_super.c b/trunk/fs/9p/vfs_super.c index 10b7d3c9dba8..7b0cd87b07c2 100644 --- a/trunk/fs/9p/vfs_super.c +++ b/trunk/fs/9p/vfs_super.c @@ -155,8 +155,9 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, goto release_sb; } - root = d_make_root(inode); + root = d_alloc_root(inode); if (!root) { + iput(inode); retval = -ENOMEM; goto release_sb; } diff --git a/trunk/fs/Kconfig b/trunk/fs/Kconfig index f95ae3a027f3..aa195265362f 100644 --- a/trunk/fs/Kconfig +++ b/trunk/fs/Kconfig @@ -214,7 +214,6 @@ source "fs/minix/Kconfig" source "fs/omfs/Kconfig" source "fs/hpfs/Kconfig" source "fs/qnx4/Kconfig" -source "fs/qnx6/Kconfig" source "fs/romfs/Kconfig" source "fs/pstore/Kconfig" source "fs/sysv/Kconfig" diff --git a/trunk/fs/Makefile b/trunk/fs/Makefile index 2fb977934673..93804d4d66e1 100644 --- a/trunk/fs/Makefile +++ b/trunk/fs/Makefile @@ -102,7 +102,6 @@ obj-$(CONFIG_UBIFS_FS) += ubifs/ obj-$(CONFIG_AFFS_FS) += affs/ obj-$(CONFIG_ROMFS_FS) += romfs/ obj-$(CONFIG_QNX4FS_FS) += qnx4/ -obj-$(CONFIG_QNX6FS_FS) += qnx6/ obj-$(CONFIG_AUTOFS4_FS) += autofs4/ obj-$(CONFIG_ADFS_FS) += adfs/ obj-$(CONFIG_FUSE_FS) += fuse/ diff --git a/trunk/fs/adfs/super.c b/trunk/fs/adfs/super.c index 06fdcc9382c4..8e3b36ace305 100644 --- a/trunk/fs/adfs/super.c +++ b/trunk/fs/adfs/super.c @@ -483,9 +483,10 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_d_op = &adfs_dentry_operations; root = adfs_iget(sb, &root_obj); - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { int i; + iput(root); for (i = 0; i < asb->s_map_size; i++) brelse(asb->s_map[i].dm_bh); kfree(asb->s_map); diff --git a/trunk/fs/affs/super.c b/trunk/fs/affs/super.c index 0782653a05a2..8ba73fed7964 100644 --- a/trunk/fs/affs/super.c +++ b/trunk/fs/affs/super.c @@ -473,7 +473,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) root_inode = affs_iget(sb, root_block); if (IS_ERR(root_inode)) { ret = PTR_ERR(root_inode); - goto out_error; + goto out_error_noinode; } if (AFFS_SB(sb)->s_flags & SF_INTL) @@ -481,7 +481,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) else sb->s_d_op = &affs_dentry_operations; - sb->s_root = d_make_root(root_inode); + sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) { printk(KERN_ERR "AFFS: Get root inode failed\n"); goto out_error; @@ -494,6 +494,9 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) * Begin the cascaded cleanup ... */ out_error: + if (root_inode) + iput(root_inode); +out_error_noinode: kfree(sbi->s_bitmap); affs_brelse(root_bh); kfree(sbi->s_prefix); diff --git a/trunk/fs/afs/super.c b/trunk/fs/afs/super.c index f02b31e7e648..983ec59fc80d 100644 --- a/trunk/fs/afs/super.c +++ b/trunk/fs/afs/super.c @@ -301,6 +301,7 @@ static int afs_fill_super(struct super_block *sb, { struct afs_super_info *as = sb->s_fs_info; struct afs_fid fid; + struct dentry *root = NULL; struct inode *inode = NULL; int ret; @@ -326,16 +327,18 @@ static int afs_fill_super(struct super_block *sb, set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); ret = -ENOMEM; - sb->s_root = d_make_root(inode); - if (!sb->s_root) + root = d_alloc_root(inode); + if (!root) goto error; sb->s_d_op = &afs_fs_dentry_operations; + sb->s_root = root; _leave(" = 0"); return 0; error: + iput(inode); _leave(" = %d", ret); return ret; } diff --git a/trunk/fs/aio.c b/trunk/fs/aio.c index c7acaf3167aa..5b600cb8779e 100644 --- a/trunk/fs/aio.c +++ b/trunk/fs/aio.c @@ -199,7 +199,16 @@ static int aio_setup_ring(struct kioctx *ctx) static void ctx_rcu_free(struct rcu_head *head) { struct kioctx *ctx = container_of(head, struct kioctx, rcu_head); + unsigned nr_events = ctx->max_reqs; + kmem_cache_free(kioctx_cachep, ctx); + + if (nr_events) { + spin_lock(&aio_nr_lock); + BUG_ON(aio_nr - nr_events > aio_nr); + aio_nr -= nr_events; + spin_unlock(&aio_nr_lock); + } } /* __put_ioctx @@ -208,19 +217,13 @@ static void ctx_rcu_free(struct rcu_head *head) */ static void __put_ioctx(struct kioctx *ctx) { - unsigned nr_events = ctx->max_reqs; BUG_ON(ctx->reqs_active); - cancel_delayed_work_sync(&ctx->wq); + cancel_delayed_work(&ctx->wq); + cancel_work_sync(&ctx->wq.work); aio_free_ring(ctx); mmdrop(ctx->mm); ctx->mm = NULL; - if (nr_events) { - spin_lock(&aio_nr_lock); - BUG_ON(aio_nr - nr_events > aio_nr); - aio_nr -= nr_events; - spin_unlock(&aio_nr_lock); - } pr_debug("__put_ioctx: freeing %p\n", ctx); call_rcu(&ctx->rcu_head, ctx_rcu_free); } @@ -244,7 +247,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) { struct mm_struct *mm; struct kioctx *ctx; - int err = -ENOMEM; + int did_sync = 0; /* Prevent overflows */ if ((nr_events > (0x10000000U / sizeof(struct io_event))) || @@ -253,7 +256,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) return ERR_PTR(-EINVAL); } - if (!nr_events || (unsigned long)nr_events > aio_max_nr) + if ((unsigned long)nr_events > aio_max_nr) return ERR_PTR(-EAGAIN); ctx = kmem_cache_zalloc(kioctx_cachep, GFP_KERNEL); @@ -277,14 +280,25 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) goto out_freectx; /* limit the number of system wide aios */ - spin_lock(&aio_nr_lock); - if (aio_nr + nr_events > aio_max_nr || - aio_nr + nr_events < aio_nr) { - spin_unlock(&aio_nr_lock); + do { + spin_lock_bh(&aio_nr_lock); + if (aio_nr + nr_events > aio_max_nr || + aio_nr + nr_events < aio_nr) + ctx->max_reqs = 0; + else + aio_nr += ctx->max_reqs; + spin_unlock_bh(&aio_nr_lock); + if (ctx->max_reqs || did_sync) + break; + + /* wait for rcu callbacks to have completed before giving up */ + synchronize_rcu(); + did_sync = 1; + ctx->max_reqs = nr_events; + } while (1); + + if (ctx->max_reqs == 0) goto out_cleanup; - } - aio_nr += ctx->max_reqs; - spin_unlock(&aio_nr_lock); /* now link into global list. */ spin_lock(&mm->ioctx_lock); @@ -296,13 +310,16 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) return ctx; out_cleanup: - err = -EAGAIN; - aio_free_ring(ctx); + __put_ioctx(ctx); + return ERR_PTR(-EAGAIN); + out_freectx: mmdrop(mm); kmem_cache_free(kioctx_cachep, ctx); - dprintk("aio: error allocating ioctx %d\n", err); - return ERR_PTR(err); + ctx = ERR_PTR(-ENOMEM); + + dprintk("aio: error allocating ioctx %p\n", ctx); + return ctx; } /* aio_cancel_all @@ -390,6 +407,10 @@ void exit_aio(struct mm_struct *mm) aio_cancel_all(ctx); wait_for_all_aios(ctx); + /* + * Ensure we don't leave the ctx on the aio_wq + */ + cancel_work_sync(&ctx->wq.work); if (1 != atomic_read(&ctx->users)) printk(KERN_DEBUG @@ -899,7 +920,7 @@ static void aio_kick_handler(struct work_struct *work) unuse_mm(mm); set_fs(oldfs); /* - * we're in a worker thread already; no point using non-zero delay + * we're in a worker thread already, don't use queue_delayed_work, */ if (requeue) queue_delayed_work(aio_wq, &ctx->wq, 0); diff --git a/trunk/fs/anon_inodes.c b/trunk/fs/anon_inodes.c index 28d39fb84ae3..f11e43ed907d 100644 --- a/trunk/fs/anon_inodes.c +++ b/trunk/fs/anon_inodes.c @@ -39,6 +39,19 @@ static const struct dentry_operations anon_inodefs_dentry_operations = { .d_dname = anon_inodefs_dname, }; +static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "anon_inode:", NULL, + &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC); +} + +static struct file_system_type anon_inode_fs_type = { + .name = "anon_inodefs", + .mount = anon_inodefs_mount, + .kill_sb = kill_anon_super, +}; + /* * nop .set_page_dirty method so that people can use .page_mkwrite on * anon inodes. @@ -52,62 +65,6 @@ static const struct address_space_operations anon_aops = { .set_page_dirty = anon_set_page_dirty, }; -/* - * A single inode exists for all anon_inode files. Contrary to pipes, - * anon_inode inodes have no associated per-instance data, so we need - * only allocate one of them. - */ -static struct inode *anon_inode_mkinode(struct super_block *s) -{ - struct inode *inode = new_inode_pseudo(s); - - if (!inode) - return ERR_PTR(-ENOMEM); - - inode->i_ino = get_next_ino(); - inode->i_fop = &anon_inode_fops; - - inode->i_mapping->a_ops = &anon_aops; - - /* - * Mark the inode dirty from the very beginning, - * that way it will never be moved to the dirty - * list because mark_inode_dirty() will think - * that it already _is_ on the dirty list. - */ - inode->i_state = I_DIRTY; - inode->i_mode = S_IRUSR | S_IWUSR; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); - inode->i_flags |= S_PRIVATE; - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - return inode; -} - -static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - struct dentry *root; - root = mount_pseudo(fs_type, "anon_inode:", NULL, - &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC); - if (!IS_ERR(root)) { - struct super_block *s = root->d_sb; - anon_inode_inode = anon_inode_mkinode(s); - if (IS_ERR(anon_inode_inode)) { - dput(root); - deactivate_locked_super(s); - root = ERR_CAST(anon_inode_inode); - } - } - return root; -} - -static struct file_system_type anon_inode_fs_type = { - .name = "anon_inodefs", - .mount = anon_inodefs_mount, - .kill_sb = kill_anon_super, -}; - /** * anon_inode_getfile - creates a new file instance by hooking it up to an * anonymous inode, and a dentry that describe the "class" @@ -223,6 +180,38 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops, } EXPORT_SYMBOL_GPL(anon_inode_getfd); +/* + * A single inode exists for all anon_inode files. Contrary to pipes, + * anon_inode inodes have no associated per-instance data, so we need + * only allocate one of them. + */ +static struct inode *anon_inode_mkinode(void) +{ + struct inode *inode = new_inode_pseudo(anon_inode_mnt->mnt_sb); + + if (!inode) + return ERR_PTR(-ENOMEM); + + inode->i_ino = get_next_ino(); + inode->i_fop = &anon_inode_fops; + + inode->i_mapping->a_ops = &anon_aops; + + /* + * Mark the inode dirty from the very beginning, + * that way it will never be moved to the dirty + * list because mark_inode_dirty() will think + * that it already _is_ on the dirty list. + */ + inode->i_state = I_DIRTY; + inode->i_mode = S_IRUSR | S_IWUSR; + inode->i_uid = current_fsuid(); + inode->i_gid = current_fsgid(); + inode->i_flags |= S_PRIVATE; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + return inode; +} + static int __init anon_inode_init(void) { int error; @@ -235,8 +224,16 @@ static int __init anon_inode_init(void) error = PTR_ERR(anon_inode_mnt); goto err_unregister_filesystem; } + anon_inode_inode = anon_inode_mkinode(); + if (IS_ERR(anon_inode_inode)) { + error = PTR_ERR(anon_inode_inode); + goto err_mntput; + } + return 0; +err_mntput: + kern_unmount(anon_inode_mnt); err_unregister_filesystem: unregister_filesystem(&anon_inode_fs_type); err_exit: diff --git a/trunk/fs/autofs4/init.c b/trunk/fs/autofs4/init.c index cddc74b9cdb2..c038727b4050 100644 --- a/trunk/fs/autofs4/init.c +++ b/trunk/fs/autofs4/init.c @@ -31,11 +31,11 @@ static int __init init_autofs4_fs(void) { int err; - autofs_dev_ioctl_init(); - err = register_filesystem(&autofs_fs_type); if (err) - autofs_dev_ioctl_exit(); + return err; + + autofs_dev_ioctl_init(); return err; } diff --git a/trunk/fs/autofs4/inode.c b/trunk/fs/autofs4/inode.c index d8dc002e9cc3..06858d955120 100644 --- a/trunk/fs/autofs4/inode.c +++ b/trunk/fs/autofs4/inode.c @@ -247,9 +247,12 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) if (!ino) goto fail_free; root_inode = autofs4_get_inode(s, S_IFDIR | 0755); - root = d_make_root(root_inode); - if (!root) + if (!root_inode) goto fail_ino; + + root = d_alloc_root(root_inode); + if (!root) + goto fail_iput; pipe = NULL; root->d_fsdata = ino; @@ -314,6 +317,9 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) fail_dput: dput(root); goto fail_free; +fail_iput: + printk("autofs: get root dentry failed\n"); + iput(root_inode); fail_ino: kfree(ino); fail_free: diff --git a/trunk/fs/befs/linuxvfs.c b/trunk/fs/befs/linuxvfs.c index e18da23d42b5..6e6d536767fe 100644 --- a/trunk/fs/befs/linuxvfs.c +++ b/trunk/fs/befs/linuxvfs.c @@ -852,8 +852,9 @@ befs_fill_super(struct super_block *sb, void *data, int silent) ret = PTR_ERR(root); goto unacquire_priv_sbp; } - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { + iput(root); befs_error(sb, "get root inode failed"); goto unacquire_priv_sbp; } diff --git a/trunk/fs/bfs/inode.c b/trunk/fs/bfs/inode.c index e23dc7c8b884..b0391bc402b1 100644 --- a/trunk/fs/bfs/inode.c +++ b/trunk/fs/bfs/inode.c @@ -367,8 +367,9 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) ret = PTR_ERR(inode); goto out2; } - s->s_root = d_make_root(inode); + s->s_root = d_alloc_root(inode); if (!s->s_root) { + iput(inode); ret = -ENOMEM; goto out2; } diff --git a/trunk/fs/binfmt_aout.c b/trunk/fs/binfmt_aout.c index 4d5e6d26578c..1ff94054d35a 100644 --- a/trunk/fs/binfmt_aout.c +++ b/trunk/fs/binfmt_aout.c @@ -267,6 +267,7 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs) } install_exec_creds(bprm); + current->flags &= ~PF_FORKNOEXEC; if (N_MAGIC(ex) == OMAGIC) { unsigned long text_addr, map_size; @@ -453,8 +454,7 @@ static int load_aout_library(struct file *file) static int __init init_aout_binfmt(void) { - register_binfmt(&aout_format); - return 0; + return register_binfmt(&aout_format); } static void __exit exit_aout_binfmt(void) diff --git a/trunk/fs/binfmt_elf.c b/trunk/fs/binfmt_elf.c index 81878b78c9d4..07d096c49920 100644 --- a/trunk/fs/binfmt_elf.c +++ b/trunk/fs/binfmt_elf.c @@ -712,6 +712,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) goto out_free_dentry; /* OK, This is the point of no return */ + current->flags &= ~PF_FORKNOEXEC; current->mm->def_flags = def_flags; /* Do this immediately, since STACK_TOP as used in setup_arg_pages @@ -933,6 +934,7 @@ static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs) #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ install_exec_creds(bprm); + current->flags &= ~PF_FORKNOEXEC; retval = create_elf_tables(bprm, &loc->elf_ex, load_addr, interp_load_addr); if (retval < 0) { @@ -2075,8 +2077,7 @@ static int elf_core_dump(struct coredump_params *cprm) static int __init init_elf_binfmt(void) { - register_binfmt(&elf_format); - return 0; + return register_binfmt(&elf_format); } static void __exit exit_elf_binfmt(void) diff --git a/trunk/fs/binfmt_elf_fdpic.c b/trunk/fs/binfmt_elf_fdpic.c index c64bf5ee2df4..30745f459faf 100644 --- a/trunk/fs/binfmt_elf_fdpic.c +++ b/trunk/fs/binfmt_elf_fdpic.c @@ -91,8 +91,7 @@ static struct linux_binfmt elf_fdpic_format = { static int __init init_elf_fdpic_binfmt(void) { - register_binfmt(&elf_fdpic_format); - return 0; + return register_binfmt(&elf_fdpic_format); } static void __exit exit_elf_fdpic_binfmt(void) @@ -335,6 +334,8 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, current->mm->context.exec_fdpic_loadmap = 0; current->mm->context.interp_fdpic_loadmap = 0; + current->flags &= ~PF_FORKNOEXEC; + #ifdef CONFIG_MMU elf_fdpic_arch_lay_out_mm(&exec_params, &interp_params, @@ -412,6 +413,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, #endif install_exec_creds(bprm); + current->flags &= ~PF_FORKNOEXEC; if (create_elf_fdpic_tables(bprm, current->mm, &exec_params, &interp_params) < 0) goto error_kill; diff --git a/trunk/fs/binfmt_em86.c b/trunk/fs/binfmt_em86.c index 2790c7e1912e..b8e8b0acf9bd 100644 --- a/trunk/fs/binfmt_em86.c +++ b/trunk/fs/binfmt_em86.c @@ -100,8 +100,7 @@ static struct linux_binfmt em86_format = { static int __init init_em86_binfmt(void) { - register_binfmt(&em86_format); - return 0; + return register_binfmt(&em86_format); } static void __exit exit_em86_binfmt(void) diff --git a/trunk/fs/binfmt_flat.c b/trunk/fs/binfmt_flat.c index 04f61f0bdfde..1bffbe0ed778 100644 --- a/trunk/fs/binfmt_flat.c +++ b/trunk/fs/binfmt_flat.c @@ -902,6 +902,7 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) libinfo.lib_list[j].start_data:UNLOADED_LIB; install_exec_creds(bprm); + current->flags &= ~PF_FORKNOEXEC; set_binfmt(&flat_format); @@ -949,8 +950,7 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) static int __init init_flat_binfmt(void) { - register_binfmt(&flat_format); - return 0; + return register_binfmt(&flat_format); } /****************************************************************************/ diff --git a/trunk/fs/binfmt_misc.c b/trunk/fs/binfmt_misc.c index 1ffb60355cae..a9198dfd5f85 100644 --- a/trunk/fs/binfmt_misc.c +++ b/trunk/fs/binfmt_misc.c @@ -726,8 +726,11 @@ static struct file_system_type bm_fs_type = { static int __init init_misc_binfmt(void) { int err = register_filesystem(&bm_fs_type); - if (!err) - insert_binfmt(&misc_format); + if (!err) { + err = insert_binfmt(&misc_format); + if (err) + unregister_filesystem(&bm_fs_type); + } return err; } diff --git a/trunk/fs/binfmt_script.c b/trunk/fs/binfmt_script.c index d3b8c1f63155..396a9884591f 100644 --- a/trunk/fs/binfmt_script.c +++ b/trunk/fs/binfmt_script.c @@ -105,8 +105,7 @@ static struct linux_binfmt script_format = { static int __init init_script_binfmt(void) { - register_binfmt(&script_format); - return 0; + return register_binfmt(&script_format); } static void __exit exit_script_binfmt(void) diff --git a/trunk/fs/binfmt_som.c b/trunk/fs/binfmt_som.c index e4fc746629a7..cc8560f6c9b0 100644 --- a/trunk/fs/binfmt_som.c +++ b/trunk/fs/binfmt_som.c @@ -225,6 +225,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) goto out_free; /* OK, This is the point of no return */ + current->flags &= ~PF_FORKNOEXEC; current->personality = PER_HPUX; setup_new_exec(bprm); @@ -288,8 +289,7 @@ static int load_som_library(struct file *f) static int __init init_som_binfmt(void) { - register_binfmt(&som_format); - return 0; + return register_binfmt(&som_format); } static void __exit exit_som_binfmt(void) diff --git a/trunk/fs/btrfs/super.c b/trunk/fs/btrfs/super.c index 81df3fec6a6d..3ce97b217cbe 100644 --- a/trunk/fs/btrfs/super.c +++ b/trunk/fs/btrfs/super.c @@ -629,6 +629,7 @@ static int btrfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; + struct dentry *root_dentry; struct btrfs_fs_info *fs_info = btrfs_sb(sb); struct btrfs_key key; int err; @@ -659,12 +660,15 @@ static int btrfs_fill_super(struct super_block *sb, goto fail_close; } - sb->s_root = d_make_root(inode); - if (!sb->s_root) { + root_dentry = d_alloc_root(inode); + if (!root_dentry) { + iput(inode); err = -ENOMEM; goto fail_close; } + sb->s_root = root_dentry; + save_mount_options(sb, data); cleancache_init_fs(sb); sb->s_flags |= MS_ACTIVE; diff --git a/trunk/fs/cachefiles/namei.c b/trunk/fs/cachefiles/namei.c index 7f0771d3894e..a0358c2189cb 100644 --- a/trunk/fs/cachefiles/namei.c +++ b/trunk/fs/cachefiles/namei.c @@ -646,8 +646,7 @@ int cachefiles_walk_to_object(struct cachefiles_object *parent, * (this is used to keep track of culling, and atimes are only * updated by read, write and readdir but not lookup or * open) */ - path.dentry = next; - touch_atime(&path); + touch_atime(cache->mnt, next); } /* open a file interface onto a data file */ diff --git a/trunk/fs/ceph/super.c b/trunk/fs/ceph/super.c index 256f85221926..00de2c9568cd 100644 --- a/trunk/fs/ceph/super.c +++ b/trunk/fs/ceph/super.c @@ -655,8 +655,9 @@ static struct dentry *open_root_dentry(struct ceph_fs_client *fsc, dout("open_root_inode success\n"); if (ceph_ino(inode) == CEPH_INO_ROOT && fsc->sb->s_root == NULL) { - root = d_make_root(inode); + root = d_alloc_root(inode); if (!root) { + iput(inode); root = ERR_PTR(-ENOMEM); goto out; } diff --git a/trunk/fs/cifs/cifsacl.c b/trunk/fs/cifs/cifsacl.c index 3cc1b251ca08..c1b254487388 100644 --- a/trunk/fs/cifs/cifsacl.c +++ b/trunk/fs/cifs/cifsacl.c @@ -556,7 +556,6 @@ init_cifs_idmap(void) /* instruct request_key() to use this special keyring as a cache for * the results it looks up */ - set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); cred->thread_keyring = keyring; cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; root_cred = cred; diff --git a/trunk/fs/cifs/cifsfs.c b/trunk/fs/cifs/cifsfs.c index 418fc42fb8b2..b1fd382d1952 100644 --- a/trunk/fs/cifs/cifsfs.c +++ b/trunk/fs/cifs/cifsfs.c @@ -119,10 +119,12 @@ cifs_read_super(struct super_block *sb) if (IS_ERR(inode)) { rc = PTR_ERR(inode); + inode = NULL; goto out_no_root; } - sb->s_root = d_make_root(inode); + sb->s_root = d_alloc_root(inode); + if (!sb->s_root) { rc = -ENOMEM; goto out_no_root; @@ -145,6 +147,9 @@ cifs_read_super(struct super_block *sb) out_no_root: cERROR(1, "cifs_read_super: get root inode failed"); + if (inode) + iput(inode); + return rc; } diff --git a/trunk/fs/coda/inode.c b/trunk/fs/coda/inode.c index 05156c17b551..5e2e1b3f068d 100644 --- a/trunk/fs/coda/inode.c +++ b/trunk/fs/coda/inode.c @@ -208,12 +208,13 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent) if (IS_ERR(root)) { error = PTR_ERR(root); printk("Failure of coda_cnode_make for root: error %d\n", error); + root = NULL; goto error; } printk("coda_read_super: rootinode is %ld dev %s\n", root->i_ino, root->i_sb->s_id); - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { error = -EINVAL; goto error; @@ -221,6 +222,9 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent) return 0; error: + if (root) + iput(root); + mutex_lock(&vc->vc_mutex); bdi_destroy(&vc->bdi); vc->vc_sb = NULL; diff --git a/trunk/fs/configfs/configfs_internal.h b/trunk/fs/configfs/configfs_internal.h index b5f0a3b91f18..ede857d20a04 100644 --- a/trunk/fs/configfs/configfs_internal.h +++ b/trunk/fs/configfs/configfs_internal.h @@ -58,11 +58,12 @@ struct configfs_dirent { extern struct mutex configfs_symlink_mutex; extern spinlock_t configfs_dirent_lock; +extern struct vfsmount * configfs_mount; extern struct kmem_cache *configfs_dir_cachep; extern int configfs_is_root(struct config_item *item); -extern struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *, struct super_block *); +extern struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *); extern int configfs_create(struct dentry *, umode_t mode, int (*init)(struct inode *)); extern int configfs_inode_init(void); extern void configfs_inode_exit(void); @@ -79,15 +80,15 @@ extern const unsigned char * configfs_get_name(struct configfs_dirent *sd); extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent); extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr); -extern struct dentry *configfs_pin_fs(void); +extern int configfs_pin_fs(void); extern void configfs_release_fs(void); extern struct rw_semaphore configfs_rename_sem; +extern struct super_block * configfs_sb; extern const struct file_operations configfs_dir_operations; extern const struct file_operations configfs_file_operations; extern const struct file_operations bin_fops; extern const struct inode_operations configfs_dir_inode_operations; -extern const struct inode_operations configfs_root_inode_operations; extern const struct inode_operations configfs_symlink_inode_operations; extern const struct dentry_operations configfs_dentry_ops; diff --git a/trunk/fs/configfs/dir.c b/trunk/fs/configfs/dir.c index 7e6c52d8a207..5ddd7ebd9dcd 100644 --- a/trunk/fs/configfs/dir.c +++ b/trunk/fs/configfs/dir.c @@ -264,13 +264,11 @@ static int init_symlink(struct inode * inode) return 0; } -static int create_dir(struct config_item *k, struct dentry *d) +static int create_dir(struct config_item * k, struct dentry * p, + struct dentry * d) { int error; umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; - struct dentry *p = d->d_parent; - - BUG_ON(!k); error = configfs_dirent_exists(p->d_fsdata, d->d_name.name); if (!error) @@ -306,7 +304,19 @@ static int create_dir(struct config_item *k, struct dentry *d) static int configfs_create_dir(struct config_item * item, struct dentry *dentry) { - int error = create_dir(item, dentry); + struct dentry * parent; + int error = 0; + + BUG_ON(!item); + + if (item->ci_parent) + parent = item->ci_parent->ci_dentry; + else if (configfs_mount) + parent = configfs_mount->mnt_root; + else + return -EFAULT; + + error = create_dir(item,parent,dentry); if (!error) item->ci_dentry = dentry; return error; @@ -1069,24 +1079,23 @@ int configfs_depend_item(struct configfs_subsystem *subsys, int ret; struct configfs_dirent *p, *root_sd, *subsys_sd = NULL; struct config_item *s_item = &subsys->su_group.cg_item; - struct dentry *root; /* * Pin the configfs filesystem. This means we can safely access * the root of the configfs filesystem. */ - root = configfs_pin_fs(); - if (IS_ERR(root)) - return PTR_ERR(root); + ret = configfs_pin_fs(); + if (ret) + return ret; /* * Next, lock the root directory. We're going to check that the * subsystem is really registered, and so we need to lock out * configfs_[un]register_subsystem(). */ - mutex_lock(&root->d_inode->i_mutex); + mutex_lock(&configfs_sb->s_root->d_inode->i_mutex); - root_sd = root->d_fsdata; + root_sd = configfs_sb->s_root->d_fsdata; list_for_each_entry(p, &root_sd->s_children, s_sibling) { if (p->s_type & CONFIGFS_DIR) { @@ -1120,7 +1129,7 @@ int configfs_depend_item(struct configfs_subsystem *subsys, out_unlock_dirent_lock: spin_unlock(&configfs_dirent_lock); out_unlock_fs: - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex); /* * If we succeeded, the fs is pinned via other methods. If not, @@ -1174,6 +1183,11 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode struct module *subsys_owner = NULL, *new_item_owner = NULL; char *name; + if (dentry->d_parent == configfs_sb->s_root) { + ret = -EPERM; + goto out; + } + sd = dentry->d_parent->d_fsdata; /* @@ -1345,6 +1359,9 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) struct module *subsys_owner = NULL, *dead_item_owner = NULL; int ret; + if (dentry->d_parent == configfs_sb->s_root) + return -EPERM; + sd = dentry->d_fsdata; if (sd->s_type & CONFIGFS_USET_DEFAULT) return -EPERM; @@ -1442,11 +1459,6 @@ const struct inode_operations configfs_dir_inode_operations = { .setattr = configfs_setattr, }; -const struct inode_operations configfs_root_inode_operations = { - .lookup = configfs_lookup, - .setattr = configfs_setattr, -}; - #if 0 int configfs_rename_dir(struct config_item * item, const char *new_name) { @@ -1534,7 +1546,6 @@ static inline unsigned char dt_type(struct configfs_dirent *sd) static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct dentry *dentry = filp->f_path.dentry; - struct super_block *sb = dentry->d_sb; struct configfs_dirent * parent_sd = dentry->d_fsdata; struct configfs_dirent *cursor = filp->private_data; struct list_head *p, *q = &cursor->s_sibling; @@ -1597,7 +1608,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir ino = inode->i_ino; spin_unlock(&configfs_dirent_lock); if (!inode) - ino = iunique(sb, 2); + ino = iunique(configfs_sb, 2); if (filldir(dirent, name, len, filp->f_pos, ino, dt_type(next)) < 0) @@ -1669,27 +1680,27 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) struct config_group *group = &subsys->su_group; struct qstr name; struct dentry *dentry; - struct dentry *root; struct configfs_dirent *sd; - root = configfs_pin_fs(); - if (IS_ERR(root)) - return PTR_ERR(root); + err = configfs_pin_fs(); + if (err) + return err; if (!group->cg_item.ci_name) group->cg_item.ci_name = group->cg_item.ci_namebuf; - sd = root->d_fsdata; + sd = configfs_sb->s_root->d_fsdata; link_group(to_config_group(sd->s_element), group); - mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT); + mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, + I_MUTEX_PARENT); name.name = group->cg_item.ci_name; name.len = strlen(name.name); name.hash = full_name_hash(name.name, name.len); err = -ENOMEM; - dentry = d_alloc(root, &name); + dentry = d_alloc(configfs_sb->s_root, &name); if (dentry) { d_add(dentry, NULL); @@ -1706,7 +1717,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) } } - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex); if (err) { unlink_group(group); @@ -1720,14 +1731,13 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) { struct config_group *group = &subsys->su_group; struct dentry *dentry = group->cg_item.ci_dentry; - struct dentry *root = dentry->d_sb->s_root; - if (dentry->d_parent != root) { + if (dentry->d_parent != configfs_sb->s_root) { printk(KERN_ERR "configfs: Tried to unregister non-subsystem!\n"); return; } - mutex_lock_nested(&root->d_inode->i_mutex, + mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); mutex_lock(&configfs_symlink_mutex); @@ -1744,7 +1754,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) d_delete(dentry); - mutex_unlock(&root->d_inode->i_mutex); + mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex); dput(dentry); diff --git a/trunk/fs/configfs/inode.c b/trunk/fs/configfs/inode.c index 0074362d9f7f..3ee36d418863 100644 --- a/trunk/fs/configfs/inode.c +++ b/trunk/fs/configfs/inode.c @@ -44,6 +44,8 @@ static struct lock_class_key default_group_class[MAX_LOCK_DEPTH]; #endif +extern struct super_block * configfs_sb; + static const struct address_space_operations configfs_aops = { .readpage = simple_readpage, .write_begin = simple_write_begin, @@ -130,10 +132,9 @@ static inline void set_inode_attr(struct inode * inode, struct iattr * iattr) inode->i_ctime = iattr->ia_ctime; } -struct inode *configfs_new_inode(umode_t mode, struct configfs_dirent *sd, - struct super_block *s) +struct inode *configfs_new_inode(umode_t mode, struct configfs_dirent * sd) { - struct inode * inode = new_inode(s); + struct inode * inode = new_inode(configfs_sb); if (inode) { inode->i_ino = get_next_ino(); inode->i_mapping->a_ops = &configfs_aops; @@ -187,35 +188,36 @@ static void configfs_set_inode_lock_class(struct configfs_dirent *sd, int configfs_create(struct dentry * dentry, umode_t mode, int (*init)(struct inode *)) { int error = 0; - struct inode *inode = NULL; - struct configfs_dirent *sd; - struct inode *p_inode; - - if (!dentry) - return -ENOENT; - - if (dentry->d_inode) - return -EEXIST; - - sd = dentry->d_fsdata; - inode = configfs_new_inode(mode, sd, dentry->d_sb); - if (!inode) - return -ENOMEM; - - p_inode = dentry->d_parent->d_inode; - p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; - configfs_set_inode_lock_class(sd, inode); + struct inode * inode = NULL; + if (dentry) { + if (!dentry->d_inode) { + struct configfs_dirent *sd = dentry->d_fsdata; + if ((inode = configfs_new_inode(mode, sd))) { + if (dentry->d_parent && dentry->d_parent->d_inode) { + struct inode *p_inode = dentry->d_parent->d_inode; + p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME; + } + configfs_set_inode_lock_class(sd, inode); + goto Proceed; + } + else + error = -ENOMEM; + } else + error = -EEXIST; + } else + error = -ENOENT; + goto Done; - if (init) { + Proceed: + if (init) error = init(inode); - if (error) { - iput(inode); - return error; - } - } - d_instantiate(dentry, inode); - if (S_ISDIR(mode) || S_ISLNK(mode)) - dget(dentry); /* pin link and directory dentries in core */ + if (!error) { + d_instantiate(dentry, inode); + if (S_ISDIR(mode) || S_ISLNK(mode)) + dget(dentry); /* pin link and directory dentries in core */ + } else + iput(inode); + Done: return error; } diff --git a/trunk/fs/configfs/mount.c b/trunk/fs/configfs/mount.c index aee0a7ebbd8e..276e15cafd58 100644 --- a/trunk/fs/configfs/mount.c +++ b/trunk/fs/configfs/mount.c @@ -37,7 +37,8 @@ /* Random magic number */ #define CONFIGFS_MAGIC 0x62656570 -static struct vfsmount *configfs_mount = NULL; +struct vfsmount * configfs_mount = NULL; +struct super_block * configfs_sb = NULL; struct kmem_cache *configfs_dir_cachep; static int configfs_mnt_count = 0; @@ -76,11 +77,12 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_magic = CONFIGFS_MAGIC; sb->s_op = &configfs_ops; sb->s_time_gran = 1; + configfs_sb = sb; inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, - &configfs_root, sb); + &configfs_root); if (inode) { - inode->i_op = &configfs_root_inode_operations; + inode->i_op = &configfs_dir_inode_operations; inode->i_fop = &configfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); @@ -89,9 +91,10 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; } - root = d_make_root(inode); + root = d_alloc_root(inode); if (!root) { pr_debug("%s: could not get root dentry!\n",__func__); + iput(inode); return -ENOMEM; } config_group_init(&configfs_root_group); @@ -115,11 +118,10 @@ static struct file_system_type configfs_fs_type = { .kill_sb = kill_litter_super, }; -struct dentry *configfs_pin_fs(void) +int configfs_pin_fs(void) { - int err = simple_pin_fs(&configfs_fs_type, &configfs_mount, + return simple_pin_fs(&configfs_fs_type, &configfs_mount, &configfs_mnt_count); - return err ? ERR_PTR(err) : configfs_mount->mnt_root; } void configfs_release_fs(void) diff --git a/trunk/fs/configfs/symlink.c b/trunk/fs/configfs/symlink.c index cc9f2546ea4a..0f3eb41d9201 100644 --- a/trunk/fs/configfs/symlink.c +++ b/trunk/fs/configfs/symlink.c @@ -110,13 +110,13 @@ static int create_link(struct config_item *parent_item, static int get_target(const char *symname, struct path *path, - struct config_item **target, struct super_block *sb) + struct config_item **target) { int ret; ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path); if (!ret) { - if (path->dentry->d_sb == sb) { + if (path->dentry->d_sb == configfs_sb) { *target = configfs_get_config_item(path->dentry); if (!*target) { ret = -ENOENT; @@ -141,6 +141,10 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna struct config_item *target_item = NULL; struct config_item_type *type; + ret = -EPERM; /* What lack-of-symlink returns */ + if (dentry->d_parent == configfs_sb->s_root) + goto out; + sd = dentry->d_parent->d_fsdata; /* * Fake invisibility if dir belongs to a group/default groups hierarchy @@ -158,7 +162,7 @@ int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symna !type->ct_item_ops->allow_link) goto out_put; - ret = get_target(symname, &path, &target_item, dentry->d_sb); + ret = get_target(symname, &path, &target_item); if (ret) goto out_put; @@ -194,6 +198,8 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry) if (!(sd->s_type & CONFIGFS_ITEM_LINK)) goto out; + BUG_ON(dentry->d_parent == configfs_sb->s_root); + sl = sd->s_element; parent_item = configfs_get_config_item(dentry->d_parent); diff --git a/trunk/fs/cramfs/inode.c b/trunk/fs/cramfs/inode.c index d013c46402ed..04d51f9333d7 100644 --- a/trunk/fs/cramfs/inode.c +++ b/trunk/fs/cramfs/inode.c @@ -318,9 +318,11 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) root = get_cramfs_inode(sb, &super.root, 0); if (IS_ERR(root)) goto out; - sb->s_root = d_make_root(root); - if (!sb->s_root) + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + iput(root); goto out; + } return 0; out: kfree(sbi); diff --git a/trunk/fs/dcache.c b/trunk/fs/dcache.c index e441941c834d..11828de68dce 100644 --- a/trunk/fs/dcache.c +++ b/trunk/fs/dcache.c @@ -1466,6 +1466,30 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode) EXPORT_SYMBOL(d_instantiate_unique); +/** + * d_alloc_root - allocate root dentry + * @root_inode: inode to allocate the root for + * + * Allocate a root ("/") dentry for the inode given. The inode is + * instantiated and returned. %NULL is returned if there is insufficient + * memory or the inode passed is %NULL. + */ + +struct dentry * d_alloc_root(struct inode * root_inode) +{ + struct dentry *res = NULL; + + if (root_inode) { + static const struct qstr name = { .name = "/", .len = 1 }; + + res = __d_alloc(root_inode->i_sb, &name); + if (res) + d_instantiate(res, root_inode); + } + return res; +} +EXPORT_SYMBOL(d_alloc_root); + struct dentry *d_make_root(struct inode *root_inode) { struct dentry *res = NULL; diff --git a/trunk/fs/debugfs/file.c b/trunk/fs/debugfs/file.c index 21e93605161c..ef023eef0464 100644 --- a/trunk/fs/debugfs/file.c +++ b/trunk/fs/debugfs/file.c @@ -611,7 +611,7 @@ static const struct file_operations fops_regset32 = { * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling * code. */ -struct dentry *debugfs_create_regset32(const char *name, umode_t mode, +struct dentry *debugfs_create_regset32(const char *name, mode_t mode, struct dentry *parent, struct debugfs_regset32 *regset) { diff --git a/trunk/fs/devpts/inode.c b/trunk/fs/devpts/inode.c index 10f5e0b484db..1c6f908e38ca 100644 --- a/trunk/fs/devpts/inode.c +++ b/trunk/fs/devpts/inode.c @@ -374,11 +374,12 @@ devpts_fill_super(struct super_block *s, void *data, int silent) inode->i_fop = &simple_dir_operations; set_nlink(inode, 2); - s->s_root = d_make_root(inode); + s->s_root = d_alloc_root(inode); if (s->s_root) return 0; printk(KERN_ERR "devpts: get root dentry failed\n"); + iput(inode); fail: return -ENOMEM; diff --git a/trunk/fs/dlm/dir.c b/trunk/fs/dlm/dir.c index dc5eb598b81f..83641574b016 100644 --- a/trunk/fs/dlm/dir.c +++ b/trunk/fs/dlm/dir.c @@ -351,28 +351,11 @@ int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen, static struct dlm_rsb *find_rsb_root(struct dlm_ls *ls, char *name, int len) { struct dlm_rsb *r; - uint32_t hash, bucket; - int rv; - - hash = jhash(name, len, 0); - bucket = hash & (ls->ls_rsbtbl_size - 1); - - spin_lock(&ls->ls_rsbtbl[bucket].lock); - rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].keep, name, len, 0, &r); - if (rv) - rv = dlm_search_rsb_tree(&ls->ls_rsbtbl[bucket].toss, - name, len, 0, &r); - spin_unlock(&ls->ls_rsbtbl[bucket].lock); - - if (!rv) - return r; down_read(&ls->ls_root_sem); list_for_each_entry(r, &ls->ls_root_list, res_root_list) { if (len == r->res_length && !memcmp(name, r->res_name, len)) { up_read(&ls->ls_root_sem); - log_error(ls, "find_rsb_root revert to root_list %s", - r->res_name); return r; } } diff --git a/trunk/fs/dlm/lock.c b/trunk/fs/dlm/lock.c index fa5c07d51dcc..d47183043c59 100644 --- a/trunk/fs/dlm/lock.c +++ b/trunk/fs/dlm/lock.c @@ -411,8 +411,8 @@ static int rsb_cmp(struct dlm_rsb *r, const char *name, int nlen) return memcmp(r->res_name, maxname, DLM_RESNAME_MAXLEN); } -int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len, - unsigned int flags, struct dlm_rsb **r_ret) +static int search_rsb_tree(struct rb_root *tree, char *name, int len, + unsigned int flags, struct dlm_rsb **r_ret) { struct rb_node *node = tree->rb_node; struct dlm_rsb *r; @@ -474,12 +474,12 @@ static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b, struct dlm_rsb *r; int error; - error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r); + error = search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r); if (!error) { kref_get(&r->res_ref); goto out; } - error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r); + error = search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r); if (error) goto out; diff --git a/trunk/fs/dlm/lock.h b/trunk/fs/dlm/lock.h index 1a255307f6ff..265017a7c3e7 100644 --- a/trunk/fs/dlm/lock.h +++ b/trunk/fs/dlm/lock.h @@ -28,9 +28,6 @@ void dlm_scan_waiters(struct dlm_ls *ls); void dlm_scan_timeout(struct dlm_ls *ls); void dlm_adjust_timeouts(struct dlm_ls *ls); -int dlm_search_rsb_tree(struct rb_root *tree, char *name, int len, - unsigned int flags, struct dlm_rsb **r_ret); - int dlm_purge_locks(struct dlm_ls *ls); void dlm_purge_mstcpy_locks(struct dlm_rsb *r); void dlm_grant_after_purge(struct dlm_ls *ls); diff --git a/trunk/fs/dlm/lowcomms.c b/trunk/fs/dlm/lowcomms.c index 133ef6dc7cb7..ca0c59a4246c 100644 --- a/trunk/fs/dlm/lowcomms.c +++ b/trunk/fs/dlm/lowcomms.c @@ -1076,7 +1076,7 @@ static void init_local(void) int i; dlm_local_count = 0; - for (i = 0; i < DLM_MAX_ADDR_COUNT; i++) { + for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) { if (dlm_our_addr(&sas, i)) break; diff --git a/trunk/fs/ecryptfs/file.c b/trunk/fs/ecryptfs/file.c index 2b17f2f9b121..d3f95f941c47 100644 --- a/trunk/fs/ecryptfs/file.c +++ b/trunk/fs/ecryptfs/file.c @@ -48,7 +48,8 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, unsigned long nr_segs, loff_t pos) { ssize_t rc; - struct path lower; + struct dentry *lower_dentry; + struct vfsmount *lower_vfsmount; struct file *file = iocb->ki_filp; rc = generic_file_aio_read(iocb, iov, nr_segs, pos); @@ -59,9 +60,9 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, if (-EIOCBQUEUED == rc) rc = wait_on_sync_kiocb(iocb); if (rc >= 0) { - lower.dentry = ecryptfs_dentry_to_lower(file->f_path.dentry); - lower.mnt = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry); - touch_atime(&lower); + lower_dentry = ecryptfs_dentry_to_lower(file->f_path.dentry); + lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry); + touch_atime(lower_vfsmount, lower_dentry); } return rc; } diff --git a/trunk/fs/ecryptfs/main.c b/trunk/fs/ecryptfs/main.c index 68954937a071..b4a6befb1216 100644 --- a/trunk/fs/ecryptfs/main.c +++ b/trunk/fs/ecryptfs/main.c @@ -550,8 +550,9 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags if (IS_ERR(inode)) goto out_free; - s->s_root = d_make_root(inode); + s->s_root = d_alloc_root(inode); if (!s->s_root) { + iput(inode); rc = -ENOMEM; goto out_free; } @@ -794,10 +795,15 @@ static int __init ecryptfs_init(void) "Failed to allocate one or more kmem_cache objects\n"); goto out; } + rc = register_filesystem(&ecryptfs_fs_type); + if (rc) { + printk(KERN_ERR "Failed to register filesystem\n"); + goto out_free_kmem_caches; + } rc = do_sysfs_registration(); if (rc) { printk(KERN_ERR "sysfs registration failed\n"); - goto out_free_kmem_caches; + goto out_unregister_filesystem; } rc = ecryptfs_init_kthread(); if (rc) { @@ -818,24 +824,19 @@ static int __init ecryptfs_init(void) "rc = [%d]\n", rc); goto out_release_messaging; } - rc = register_filesystem(&ecryptfs_fs_type); - if (rc) { - printk(KERN_ERR "Failed to register filesystem\n"); - goto out_destroy_crypto; - } if (ecryptfs_verbosity > 0) printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values " "will be written to the syslog!\n", ecryptfs_verbosity); goto out; -out_destroy_crypto: - ecryptfs_destroy_crypto(); out_release_messaging: ecryptfs_release_messaging(); out_destroy_kthread: ecryptfs_destroy_kthread(); out_do_sysfs_unregistration: do_sysfs_unregistration(); +out_unregister_filesystem: + unregister_filesystem(&ecryptfs_fs_type); out_free_kmem_caches: ecryptfs_free_kmem_caches(); out: diff --git a/trunk/fs/ecryptfs/super.c b/trunk/fs/ecryptfs/super.c index 2dd946b636d2..cf152823bbf4 100644 --- a/trunk/fs/ecryptfs/super.c +++ b/trunk/fs/ecryptfs/super.c @@ -184,6 +184,7 @@ static int ecryptfs_show_options(struct seq_file *m, struct dentry *root) const struct super_operations ecryptfs_sops = { .alloc_inode = ecryptfs_alloc_inode, .destroy_inode = ecryptfs_destroy_inode, + .drop_inode = generic_drop_inode, .statfs = ecryptfs_statfs, .remount_fs = NULL, .evict_inode = ecryptfs_evict_inode, diff --git a/trunk/fs/efs/super.c b/trunk/fs/efs/super.c index e755ec746c69..981106429a9f 100644 --- a/trunk/fs/efs/super.c +++ b/trunk/fs/efs/super.c @@ -317,9 +317,10 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) goto out_no_fs; } - s->s_root = d_make_root(root); + s->s_root = d_alloc_root(root); if (!(s->s_root)) { printk(KERN_ERR "EFS: get root dentry failed\n"); + iput(root); ret = -ENOMEM; goto out_no_fs; } diff --git a/trunk/fs/exec.c b/trunk/fs/exec.c index 0b931471d4f4..3908544f5d18 100644 --- a/trunk/fs/exec.c +++ b/trunk/fs/exec.c @@ -81,13 +81,15 @@ static atomic_t call_count = ATOMIC_INIT(1); static LIST_HEAD(formats); static DEFINE_RWLOCK(binfmt_lock); -void __register_binfmt(struct linux_binfmt * fmt, int insert) +int __register_binfmt(struct linux_binfmt * fmt, int insert) { - BUG_ON(!fmt); + if (!fmt) + return -EINVAL; write_lock(&binfmt_lock); insert ? list_add(&fmt->lh, &formats) : list_add_tail(&fmt->lh, &formats); write_unlock(&binfmt_lock); + return 0; } EXPORT_SYMBOL(__register_binfmt); @@ -1113,7 +1115,7 @@ int flush_old_exec(struct linux_binprm * bprm) bprm->mm = NULL; /* We're using it now */ set_fs(USER_DS); - current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD); + current->flags &= ~(PF_RANDOMIZE | PF_KTHREAD); flush_thread(); current->personality &= ~bprm->per_clear; diff --git a/trunk/fs/exofs/namei.c b/trunk/fs/exofs/namei.c index fc7161d6bf6b..9dbf0c301030 100644 --- a/trunk/fs/exofs/namei.c +++ b/trunk/fs/exofs/namei.c @@ -143,6 +143,9 @@ static int exofs_link(struct dentry *old_dentry, struct inode *dir, { struct inode *inode = old_dentry->d_inode; + if (inode->i_nlink >= EXOFS_LINK_MAX) + return -EMLINK; + inode->i_ctime = CURRENT_TIME; inode_inc_link_count(inode); ihold(inode); @@ -153,7 +156,10 @@ static int exofs_link(struct dentry *old_dentry, struct inode *dir, static int exofs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { struct inode *inode; - int err; + int err = -EMLINK; + + if (dir->i_nlink >= EXOFS_LINK_MAX) + goto out; inode_inc_link_count(dir); @@ -269,6 +275,11 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry, if (err) goto out_dir; } else { + if (dir_de) { + err = -EMLINK; + if (new_dir->i_nlink >= EXOFS_LINK_MAX) + goto out_dir; + } err = exofs_add_link(new_dentry, old_inode); if (err) goto out_dir; diff --git a/trunk/fs/exofs/super.c b/trunk/fs/exofs/super.c index 7f2b590a36b7..d22cd168c6ee 100644 --- a/trunk/fs/exofs/super.c +++ b/trunk/fs/exofs/super.c @@ -754,7 +754,6 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) sb->s_blocksize = EXOFS_BLKSIZE; sb->s_blocksize_bits = EXOFS_BLKSHIFT; sb->s_maxbytes = MAX_LFS_FILESIZE; - sb->s_max_links = EXOFS_LINK_MAX; atomic_set(&sbi->s_curr_pending, 0); sb->s_bdev = NULL; sb->s_dev = 0; @@ -819,8 +818,9 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) ret = PTR_ERR(root); goto free_sbi; } - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { + iput(root); EXOFS_ERR("ERROR: get root inode failed\n"); ret = -ENOMEM; goto free_sbi; diff --git a/trunk/fs/ext2/namei.c b/trunk/fs/ext2/namei.c index dffb86536285..080419814bae 100644 --- a/trunk/fs/ext2/namei.c +++ b/trunk/fs/ext2/namei.c @@ -195,6 +195,9 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir, struct inode *inode = old_dentry->d_inode; int err; + if (inode->i_nlink >= EXT2_LINK_MAX) + return -EMLINK; + dquot_initialize(dir); inode->i_ctime = CURRENT_TIME_SEC; @@ -214,7 +217,10 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir, static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) { struct inode * inode; - int err; + int err = -EMLINK; + + if (dir->i_nlink >= EXT2_LINK_MAX) + goto out; dquot_initialize(dir); @@ -340,6 +346,11 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { + if (dir_de) { + err = -EMLINK; + if (new_dir->i_nlink >= EXT2_LINK_MAX) + goto out_dir; + } err = ext2_add_link(new_dentry, old_inode); if (err) goto out_dir; diff --git a/trunk/fs/ext2/super.c b/trunk/fs/ext2/super.c index e1025c7a437a..0090595beb28 100644 --- a/trunk/fs/ext2/super.c +++ b/trunk/fs/ext2/super.c @@ -919,7 +919,6 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) } sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits); - sb->s_max_links = EXT2_LINK_MAX; if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) { sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE; @@ -1088,8 +1087,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount3; } - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { + iput(root); ext2_msg(sb, KERN_ERR, "error: get root inode failed"); ret = -ENOMEM; goto failed_mount3; diff --git a/trunk/fs/ext3/super.c b/trunk/fs/ext3/super.c index e0b45b93327b..726c7ef6cdf1 100644 --- a/trunk/fs/ext3/super.c +++ b/trunk/fs/ext3/super.c @@ -2046,9 +2046,10 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) ext3_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck"); goto failed_mount3; } - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { ext3_msg(sb, KERN_ERR, "error: get root dentry failed"); + iput(root); ret = -ENOMEM; goto failed_mount3; } diff --git a/trunk/fs/ext4/super.c b/trunk/fs/ext4/super.c index 933900909ed0..502c61fd7392 100644 --- a/trunk/fs/ext4/super.c +++ b/trunk/fs/ext4/super.c @@ -3735,8 +3735,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) iput(root); goto failed_mount4; } - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { + iput(root); ext4_msg(sb, KERN_ERR, "get root dentry failed"); ret = -ENOMEM; goto failed_mount4; @@ -5055,9 +5056,6 @@ static int __init ext4_init_fs(void) { int i, err; - ext4_li_info = NULL; - mutex_init(&ext4_li_mtx); - ext4_check_flag_values(); for (i = 0; i < EXT4_WQ_HASH_SZ; i++) { @@ -5096,6 +5094,8 @@ static int __init ext4_init_fs(void) if (err) goto out; + ext4_li_info = NULL; + mutex_init(&ext4_li_mtx); return 0; out: unregister_as_ext2(); diff --git a/trunk/fs/fat/inode.c b/trunk/fs/fat/inode.c index 21687e31acc0..3ab841054d53 100644 --- a/trunk/fs/fat/inode.c +++ b/trunk/fs/fat/inode.c @@ -1496,13 +1496,11 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, root_inode->i_ino = MSDOS_ROOT_INO; root_inode->i_version = 1; error = fat_read_root(root_inode); - if (error < 0) { - iput(root_inode); + if (error < 0) goto out_fail; - } error = -ENOMEM; insert_inode_hash(root_inode); - sb->s_root = d_make_root(root_inode); + sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) { fat_msg(sb, KERN_ERR, "get root inode failed"); goto out_fail; @@ -1518,6 +1516,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, out_fail: if (fat_inode) iput(fat_inode); + if (root_inode) + iput(root_inode); unload_nls(sbi->nls_io); unload_nls(sbi->nls_disk); if (sbi->options.iocharset != fat_default_iocharset) diff --git a/trunk/fs/file_table.c b/trunk/fs/file_table.c index 70f2a0fd6aec..20002e39754d 100644 --- a/trunk/fs/file_table.c +++ b/trunk/fs/file_table.c @@ -204,7 +204,7 @@ EXPORT_SYMBOL(alloc_file); * to write to @file, along with access to write through * its vfsmount. */ -static void drop_file_write_access(struct file *file) +void drop_file_write_access(struct file *file) { struct vfsmount *mnt = file->f_path.mnt; struct dentry *dentry = file->f_path.dentry; @@ -219,6 +219,7 @@ static void drop_file_write_access(struct file *file) mnt_drop_write(mnt); file_release_write(file); } +EXPORT_SYMBOL_GPL(drop_file_write_access); /* the real guts of fput() - releasing the last reference to file */ diff --git a/trunk/fs/freevxfs/vxfs_super.c b/trunk/fs/freevxfs/vxfs_super.c index d4fabd26084e..9d1c99558389 100644 --- a/trunk/fs/freevxfs/vxfs_super.c +++ b/trunk/fs/freevxfs/vxfs_super.c @@ -224,8 +224,9 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent) ret = PTR_ERR(root); goto out; } - sbp->s_root = d_make_root(root); + sbp->s_root = d_alloc_root(root); if (!sbp->s_root) { + iput(root); printk(KERN_WARNING "vxfs: unable to get root dentry.\n"); goto out_free_ilist; } diff --git a/trunk/fs/fs_struct.c b/trunk/fs/fs_struct.c index 6324c4274959..78b519c13536 100644 --- a/trunk/fs/fs_struct.c +++ b/trunk/fs/fs_struct.c @@ -26,11 +26,11 @@ void set_fs_root(struct fs_struct *fs, struct path *path) { struct path old_root; - path_get_longterm(path); spin_lock(&fs->lock); write_seqcount_begin(&fs->seq); old_root = fs->root; fs->root = *path; + path_get_longterm(path); write_seqcount_end(&fs->seq); spin_unlock(&fs->lock); if (old_root.dentry) @@ -45,11 +45,11 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) { struct path old_pwd; - path_get_longterm(path); spin_lock(&fs->lock); write_seqcount_begin(&fs->seq); old_pwd = fs->pwd; fs->pwd = *path; + path_get_longterm(path); write_seqcount_end(&fs->seq); spin_unlock(&fs->lock); @@ -57,14 +57,6 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path) path_put_longterm(&old_pwd); } -static inline int replace_path(struct path *p, const struct path *old, const struct path *new) -{ - if (likely(p->dentry != old->dentry || p->mnt != old->mnt)) - return 0; - *p = *new; - return 1; -} - void chroot_fs_refs(struct path *old_root, struct path *new_root) { struct task_struct *g, *p; @@ -76,16 +68,21 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root) task_lock(p); fs = p->fs; if (fs) { - int hits = 0; spin_lock(&fs->lock); write_seqcount_begin(&fs->seq); - hits += replace_path(&fs->root, old_root, new_root); - hits += replace_path(&fs->pwd, old_root, new_root); - write_seqcount_end(&fs->seq); - while (hits--) { + if (fs->root.dentry == old_root->dentry + && fs->root.mnt == old_root->mnt) { + path_get_longterm(new_root); + fs->root = *new_root; count++; + } + if (fs->pwd.dentry == old_root->dentry + && fs->pwd.mnt == old_root->mnt) { path_get_longterm(new_root); + fs->pwd = *new_root; + count++; } + write_seqcount_end(&fs->seq); spin_unlock(&fs->lock); } task_unlock(p); @@ -110,8 +107,10 @@ void exit_fs(struct task_struct *tsk) int kill; task_lock(tsk); spin_lock(&fs->lock); + write_seqcount_begin(&fs->seq); tsk->fs = NULL; kill = !--fs->users; + write_seqcount_end(&fs->seq); spin_unlock(&fs->lock); task_unlock(tsk); if (kill) diff --git a/trunk/fs/fuse/inode.c b/trunk/fs/fuse/inode.c index 4aec5995867e..64cf8d07393e 100644 --- a/trunk/fs/fuse/inode.c +++ b/trunk/fs/fuse/inode.c @@ -988,9 +988,14 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) err = -ENOMEM; root = fuse_get_root_inode(sb, d.rootmode); - root_dentry = d_make_root(root); - if (!root_dentry) + if (!root) goto err_put_conn; + + root_dentry = d_alloc_root(root); + if (!root_dentry) { + iput(root); + goto err_put_conn; + } /* only now - we want root dentry with NULL ->d_op */ sb->s_d_op = &fuse_dentry_operations; diff --git a/trunk/fs/gfs2/bmap.c b/trunk/fs/gfs2/bmap.c index 197c5c47e577..14a704015970 100644 --- a/trunk/fs/gfs2/bmap.c +++ b/trunk/fs/gfs2/bmap.c @@ -60,7 +60,7 @@ static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh, int release = 0; if (!page || page->index) { - page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS); + page = grab_cache_page(inode->i_mapping, 0); if (!page) return -ENOMEM; release = 1; @@ -930,7 +930,7 @@ static int gfs2_block_truncate_page(struct address_space *mapping, loff_t from) struct page *page; int err; - page = find_or_create_page(mapping, index, GFP_NOFS); + page = grab_cache_page(mapping, index); if (!page) return 0; diff --git a/trunk/fs/gfs2/file.c b/trunk/fs/gfs2/file.c index 76834587a8a4..c5fb3597f696 100644 --- a/trunk/fs/gfs2/file.c +++ b/trunk/fs/gfs2/file.c @@ -313,8 +313,6 @@ static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return gfs2_get_flags(filp, (u32 __user *)arg); case FS_IOC_SETFLAGS: return gfs2_set_flags(filp, (u32 __user *)arg); - case FITRIM: - return gfs2_fitrim(filp, (void __user *)arg); } return -ENOTTY; } @@ -676,7 +674,6 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, struct gfs2_inode *ip = GFS2_I(inode); struct buffer_head *dibh; int error; - loff_t size = len; unsigned int nr_blks; sector_t lblock = offset >> inode->i_blkbits; @@ -710,8 +707,8 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, goto out; } } - if (offset + size > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE)) - i_size_write(inode, offset + size); + if (offset + len > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE)) + i_size_write(inode, offset + len); mark_inode_dirty(inode); @@ -780,14 +777,12 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset, if (unlikely(error)) goto out_uninit; + if (!gfs2_write_alloc_required(ip, offset, len)) + goto out_unlock; + while (len > 0) { if (len < bytes) bytes = len; - if (!gfs2_write_alloc_required(ip, offset, bytes)) { - len -= bytes; - offset += bytes; - continue; - } qa = gfs2_qadata_get(ip); if (!qa) { error = -ENOMEM; diff --git a/trunk/fs/gfs2/glock.c b/trunk/fs/gfs2/glock.c index dab2526071cc..351a3e797789 100644 --- a/trunk/fs/gfs2/glock.c +++ b/trunk/fs/gfs2/glock.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "gfs2.h" #include "incore.h" @@ -544,11 +543,6 @@ __acquires(&gl->gl_spin) do_error(gl, 0); /* Fail queued try locks */ } gl->gl_req = target; - set_bit(GLF_BLOCKING, &gl->gl_flags); - if ((gl->gl_req == LM_ST_UNLOCKED) || - (gl->gl_state == LM_ST_EXCLUSIVE) || - (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB))) - clear_bit(GLF_BLOCKING, &gl->gl_flags); spin_unlock(&gl->gl_spin); if (glops->go_xmote_th) glops->go_xmote_th(gl); @@ -750,7 +744,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, return -ENOMEM; atomic_inc(&sdp->sd_glock_disposal); - gl->gl_sbd = sdp; gl->gl_flags = 0; gl->gl_name = name; atomic_set(&gl->gl_ref, 1); @@ -759,17 +752,12 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, gl->gl_demote_state = LM_ST_EXCLUSIVE; gl->gl_hash = hash; gl->gl_ops = glops; - gl->gl_dstamp = ktime_set(0, 0); - preempt_disable(); - /* We use the global stats to estimate the initial per-glock stats */ - gl->gl_stats = this_cpu_ptr(sdp->sd_lkstats)->lkstats[glops->go_type]; - preempt_enable(); - gl->gl_stats.stats[GFS2_LKS_DCOUNT] = 0; - gl->gl_stats.stats[GFS2_LKS_QCOUNT] = 0; + snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number); memset(&gl->gl_lksb, 0, sizeof(struct dlm_lksb)); gl->gl_lksb.sb_lvbptr = gl->gl_lvb; gl->gl_tchange = jiffies; gl->gl_object = NULL; + gl->gl_sbd = sdp; gl->gl_hold_time = GL_GLOCK_DFT_HOLD; INIT_DELAYED_WORK(&gl->gl_work, glock_work_func); INIT_WORK(&gl->gl_delete, delete_work_func); @@ -1011,8 +999,6 @@ __acquires(&gl->gl_spin) } set_bit(GLF_QUEUED, &gl->gl_flags); trace_gfs2_glock_queue(gh, 1); - gfs2_glstats_inc(gl, GFS2_LKS_QCOUNT); - gfs2_sbstats_inc(gl, GFS2_LKS_QCOUNT); if (likely(insert_pt == NULL)) { list_add_tail(&gh->gh_list, &gl->gl_holders); if (unlikely(gh->gh_flags & LM_FLAG_PRIORITY)) @@ -1672,8 +1658,6 @@ static const char *gflags2str(char *buf, const struct gfs2_glock *gl) *p++ = 'L'; if (gl->gl_object) *p++ = 'o'; - if (test_bit(GLF_BLOCKING, gflags)) - *p++ = 'b'; *p = 0; return buf; } @@ -1730,78 +1714,8 @@ static int __dump_glock(struct seq_file *seq, const struct gfs2_glock *gl) return error; } -static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr) -{ - struct gfs2_glock *gl = iter_ptr; - - seq_printf(seq, "G: n:%u/%llx rtt:%lld/%lld rttb:%lld/%lld irt:%lld/%lld dcnt: %lld qcnt: %lld\n", - gl->gl_name.ln_type, - (unsigned long long)gl->gl_name.ln_number, - (long long)gl->gl_stats.stats[GFS2_LKS_SRTT], - (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVAR], - (long long)gl->gl_stats.stats[GFS2_LKS_SRTTB], - (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVARB], - (long long)gl->gl_stats.stats[GFS2_LKS_SIRT], - (long long)gl->gl_stats.stats[GFS2_LKS_SIRTVAR], - (long long)gl->gl_stats.stats[GFS2_LKS_DCOUNT], - (long long)gl->gl_stats.stats[GFS2_LKS_QCOUNT]); - return 0; -} - -static const char *gfs2_gltype[] = { - "type", - "reserved", - "nondisk", - "inode", - "rgrp", - "meta", - "iopen", - "flock", - "plock", - "quota", - "journal", -}; - -static const char *gfs2_stype[] = { - [GFS2_LKS_SRTT] = "srtt", - [GFS2_LKS_SRTTVAR] = "srttvar", - [GFS2_LKS_SRTTB] = "srttb", - [GFS2_LKS_SRTTVARB] = "srttvarb", - [GFS2_LKS_SIRT] = "sirt", - [GFS2_LKS_SIRTVAR] = "sirtvar", - [GFS2_LKS_DCOUNT] = "dlm", - [GFS2_LKS_QCOUNT] = "queue", -}; - -#define GFS2_NR_SBSTATS (ARRAY_SIZE(gfs2_gltype) * ARRAY_SIZE(gfs2_stype)) - -static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr) -{ - struct gfs2_glock_iter *gi = seq->private; - struct gfs2_sbd *sdp = gi->sdp; - unsigned index = gi->hash >> 3; - unsigned subindex = gi->hash & 0x07; - s64 value; - int i; - - if (index == 0 && subindex != 0) - return 0; - seq_printf(seq, "%-10s %8s:", gfs2_gltype[index], - (index == 0) ? "cpu": gfs2_stype[subindex]); - for_each_possible_cpu(i) { - const struct gfs2_pcpu_lkstats *lkstats = per_cpu_ptr(sdp->sd_lkstats, i); - if (index == 0) { - value = i; - } else { - value = lkstats->lkstats[index - 1].stats[subindex]; - } - seq_printf(seq, " %15lld", (long long)value); - } - seq_putc(seq, '\n'); - return 0; -} int __init gfs2_glock_init(void) { @@ -1914,35 +1828,6 @@ static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr) return dump_glock(seq, iter_ptr); } -static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct gfs2_glock_iter *gi = seq->private; - - gi->hash = *pos; - if (*pos >= GFS2_NR_SBSTATS) - return NULL; - preempt_disable(); - return SEQ_START_TOKEN; -} - -static void *gfs2_sbstats_seq_next(struct seq_file *seq, void *iter_ptr, - loff_t *pos) -{ - struct gfs2_glock_iter *gi = seq->private; - (*pos)++; - gi->hash++; - if (gi->hash >= GFS2_NR_SBSTATS) { - preempt_enable(); - return NULL; - } - return SEQ_START_TOKEN; -} - -static void gfs2_sbstats_seq_stop(struct seq_file *seq, void *iter_ptr) -{ - preempt_enable(); -} - static const struct seq_operations gfs2_glock_seq_ops = { .start = gfs2_glock_seq_start, .next = gfs2_glock_seq_next, @@ -1950,21 +1835,7 @@ static const struct seq_operations gfs2_glock_seq_ops = { .show = gfs2_glock_seq_show, }; -static const struct seq_operations gfs2_glstats_seq_ops = { - .start = gfs2_glock_seq_start, - .next = gfs2_glock_seq_next, - .stop = gfs2_glock_seq_stop, - .show = gfs2_glstats_seq_show, -}; - -static const struct seq_operations gfs2_sbstats_seq_ops = { - .start = gfs2_sbstats_seq_start, - .next = gfs2_sbstats_seq_next, - .stop = gfs2_sbstats_seq_stop, - .show = gfs2_sbstats_seq_show, -}; - -static int gfs2_glocks_open(struct inode *inode, struct file *file) +static int gfs2_debugfs_open(struct inode *inode, struct file *file) { int ret = seq_open_private(file, &gfs2_glock_seq_ops, sizeof(struct gfs2_glock_iter)); @@ -1976,49 +1847,9 @@ static int gfs2_glocks_open(struct inode *inode, struct file *file) return ret; } -static int gfs2_glstats_open(struct inode *inode, struct file *file) -{ - int ret = seq_open_private(file, &gfs2_glstats_seq_ops, - sizeof(struct gfs2_glock_iter)); - if (ret == 0) { - struct seq_file *seq = file->private_data; - struct gfs2_glock_iter *gi = seq->private; - gi->sdp = inode->i_private; - } - return ret; -} - -static int gfs2_sbstats_open(struct inode *inode, struct file *file) -{ - int ret = seq_open_private(file, &gfs2_sbstats_seq_ops, - sizeof(struct gfs2_glock_iter)); - if (ret == 0) { - struct seq_file *seq = file->private_data; - struct gfs2_glock_iter *gi = seq->private; - gi->sdp = inode->i_private; - } - return ret; -} - -static const struct file_operations gfs2_glocks_fops = { - .owner = THIS_MODULE, - .open = gfs2_glocks_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - -static const struct file_operations gfs2_glstats_fops = { +static const struct file_operations gfs2_debug_fops = { .owner = THIS_MODULE, - .open = gfs2_glstats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - -static const struct file_operations gfs2_sbstats_fops = { - .owner = THIS_MODULE, - .open = gfs2_sbstats_open, + .open = gfs2_debugfs_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private, @@ -2032,45 +1863,20 @@ int gfs2_create_debugfs_file(struct gfs2_sbd *sdp) sdp->debugfs_dentry_glocks = debugfs_create_file("glocks", S_IFREG | S_IRUGO, sdp->debugfs_dir, sdp, - &gfs2_glocks_fops); + &gfs2_debug_fops); if (!sdp->debugfs_dentry_glocks) - goto fail; - - sdp->debugfs_dentry_glstats = debugfs_create_file("glstats", - S_IFREG | S_IRUGO, - sdp->debugfs_dir, sdp, - &gfs2_glstats_fops); - if (!sdp->debugfs_dentry_glstats) - goto fail; - - sdp->debugfs_dentry_sbstats = debugfs_create_file("sbstats", - S_IFREG | S_IRUGO, - sdp->debugfs_dir, sdp, - &gfs2_sbstats_fops); - if (!sdp->debugfs_dentry_sbstats) - goto fail; + return -ENOMEM; return 0; -fail: - gfs2_delete_debugfs_file(sdp); - return -ENOMEM; } void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp) { - if (sdp->debugfs_dir) { + if (sdp && sdp->debugfs_dir) { if (sdp->debugfs_dentry_glocks) { debugfs_remove(sdp->debugfs_dentry_glocks); sdp->debugfs_dentry_glocks = NULL; } - if (sdp->debugfs_dentry_glstats) { - debugfs_remove(sdp->debugfs_dentry_glstats); - sdp->debugfs_dentry_glstats = NULL; - } - if (sdp->debugfs_dentry_sbstats) { - debugfs_remove(sdp->debugfs_dentry_sbstats); - sdp->debugfs_dentry_sbstats = NULL; - } debugfs_remove(sdp->debugfs_dir); sdp->debugfs_dir = NULL; } diff --git a/trunk/fs/gfs2/incore.h b/trunk/fs/gfs2/incore.h index 47d0bda5ac2b..97742a7ea9cc 100644 --- a/trunk/fs/gfs2/incore.h +++ b/trunk/fs/gfs2/incore.h @@ -19,8 +19,6 @@ #include #include #include -#include -#include #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 @@ -206,22 +204,6 @@ struct gfs2_glock_operations { #define GLOF_ASPACE 1 }; -enum { - GFS2_LKS_SRTT = 0, /* Non blocking smoothed round trip time */ - GFS2_LKS_SRTTVAR = 1, /* Non blocking smoothed variance */ - GFS2_LKS_SRTTB = 2, /* Blocking smoothed round trip time */ - GFS2_LKS_SRTTVARB = 3, /* Blocking smoothed variance */ - GFS2_LKS_SIRT = 4, /* Smoothed Inter-request time */ - GFS2_LKS_SIRTVAR = 5, /* Smoothed Inter-request variance */ - GFS2_LKS_DCOUNT = 6, /* Count of dlm requests */ - GFS2_LKS_QCOUNT = 7, /* Count of gfs2_holder queues */ - GFS2_NR_LKSTATS -}; - -struct gfs2_lkstats { - s64 stats[GFS2_NR_LKSTATS]; -}; - enum { /* States */ HIF_HOLDER = 6, /* Set for gh that "holds" the glock */ @@ -256,12 +238,10 @@ enum { GLF_QUEUED = 12, GLF_LRU = 13, GLF_OBJECT = 14, /* Used only for tracing */ - GLF_BLOCKING = 15, }; struct gfs2_glock { struct hlist_bl_node gl_list; - struct gfs2_sbd *gl_sbd; unsigned long gl_flags; /* GLF_... */ struct lm_lockname gl_name; atomic_t gl_ref; @@ -281,14 +261,16 @@ struct gfs2_glock { struct list_head gl_holders; const struct gfs2_glock_operations *gl_ops; - ktime_t gl_dstamp; - struct gfs2_lkstats gl_stats; + char gl_strname[GDLM_STRNAME_BYTES]; struct dlm_lksb gl_lksb; char gl_lvb[32]; unsigned long gl_tchange; void *gl_object; struct list_head gl_lru; + + struct gfs2_sbd *gl_sbd; + struct list_head gl_ail_list; atomic_t gl_ail_count; atomic_t gl_revokes; @@ -578,14 +560,8 @@ struct lm_lockstruct { uint32_t *ls_recover_result; /* result of last jid recovery */ }; -struct gfs2_pcpu_lkstats { - /* One struct for each glock type */ - struct gfs2_lkstats lkstats[10]; -}; - struct gfs2_sbd { struct super_block *sd_vfs; - struct gfs2_pcpu_lkstats __percpu *sd_lkstats; struct kobject sd_kobj; unsigned long sd_flags; /* SDF_... */ struct gfs2_sb_host sd_sb; @@ -644,6 +620,7 @@ struct gfs2_sbd { int sd_rindex_uptodate; spinlock_t sd_rindex_spin; + struct mutex sd_rindex_mutex; struct rb_root sd_rindex_tree; unsigned int sd_rgrps; unsigned int sd_max_rg_data; @@ -748,23 +725,8 @@ struct gfs2_sbd { unsigned long sd_last_warning; struct dentry *debugfs_dir; /* debugfs directory */ - struct dentry *debugfs_dentry_glocks; - struct dentry *debugfs_dentry_glstats; - struct dentry *debugfs_dentry_sbstats; + struct dentry *debugfs_dentry_glocks; /* for debugfs */ }; -static inline void gfs2_glstats_inc(struct gfs2_glock *gl, int which) -{ - gl->gl_stats.stats[which]++; -} - -static inline void gfs2_sbstats_inc(const struct gfs2_glock *gl, int which) -{ - const struct gfs2_sbd *sdp = gl->gl_sbd; - preempt_disable(); - this_cpu_ptr(sdp->sd_lkstats)->lkstats[gl->gl_name.ln_type].stats[which]++; - preempt_enable(); -} - #endif /* __INCORE_DOT_H__ */ diff --git a/trunk/fs/gfs2/inode.c b/trunk/fs/gfs2/inode.c index c98a60ee6dfd..56987460cdae 100644 --- a/trunk/fs/gfs2/inode.c +++ b/trunk/fs/gfs2/inode.c @@ -1036,7 +1036,7 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry) gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs); gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1); - rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1); + rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); if (!rgd) goto out_inodes; @@ -1255,7 +1255,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry, * this is the case of the target file already existing * so we unlink before doing the rename */ - nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr, 1); + nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr); if (nrgd) gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); } diff --git a/trunk/fs/gfs2/lock_dlm.c b/trunk/fs/gfs2/lock_dlm.c index f8411bd1b805..8944d1e32ab5 100644 --- a/trunk/fs/gfs2/lock_dlm.c +++ b/trunk/fs/gfs2/lock_dlm.c @@ -18,106 +18,14 @@ #include "glock.h" #include "util.h" #include "sys.h" -#include "trace_gfs2.h" extern struct workqueue_struct *gfs2_control_wq; -/** - * gfs2_update_stats - Update time based stats - * @mv: Pointer to mean/variance structure to update - * @sample: New data to include - * - * @delta is the difference between the current rtt sample and the - * running average srtt. We add 1/8 of that to the srtt in order to - * update the current srtt estimate. The varience estimate is a bit - * more complicated. We subtract the abs value of the @delta from - * the current variance estimate and add 1/4 of that to the running - * total. - * - * Note that the index points at the array entry containing the smoothed - * mean value, and the variance is always in the following entry - * - * Reference: TCP/IP Illustrated, vol 2, p. 831,832 - * All times are in units of integer nanoseconds. Unlike the TCP/IP case, - * they are not scaled fixed point. - */ - -static inline void gfs2_update_stats(struct gfs2_lkstats *s, unsigned index, - s64 sample) -{ - s64 delta = sample - s->stats[index]; - s->stats[index] += (delta >> 3); - index++; - s->stats[index] += ((abs64(delta) - s->stats[index]) >> 2); -} - -/** - * gfs2_update_reply_times - Update locking statistics - * @gl: The glock to update - * - * This assumes that gl->gl_dstamp has been set earlier. - * - * The rtt (lock round trip time) is an estimate of the time - * taken to perform a dlm lock request. We update it on each - * reply from the dlm. - * - * The blocking flag is set on the glock for all dlm requests - * which may potentially block due to lock requests from other nodes. - * DLM requests where the current lock state is exclusive, the - * requested state is null (or unlocked) or where the TRY or - * TRY_1CB flags are set are classified as non-blocking. All - * other DLM requests are counted as (potentially) blocking. - */ -static inline void gfs2_update_reply_times(struct gfs2_glock *gl) -{ - struct gfs2_pcpu_lkstats *lks; - const unsigned gltype = gl->gl_name.ln_type; - unsigned index = test_bit(GLF_BLOCKING, &gl->gl_flags) ? - GFS2_LKS_SRTTB : GFS2_LKS_SRTT; - s64 rtt; - - preempt_disable(); - rtt = ktime_to_ns(ktime_sub(ktime_get_real(), gl->gl_dstamp)); - lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats); - gfs2_update_stats(&gl->gl_stats, index, rtt); /* Local */ - gfs2_update_stats(&lks->lkstats[gltype], index, rtt); /* Global */ - preempt_enable(); - - trace_gfs2_glock_lock_time(gl, rtt); -} - -/** - * gfs2_update_request_times - Update locking statistics - * @gl: The glock to update - * - * The irt (lock inter-request times) measures the average time - * between requests to the dlm. It is updated immediately before - * each dlm call. - */ - -static inline void gfs2_update_request_times(struct gfs2_glock *gl) -{ - struct gfs2_pcpu_lkstats *lks; - const unsigned gltype = gl->gl_name.ln_type; - ktime_t dstamp; - s64 irt; - - preempt_disable(); - dstamp = gl->gl_dstamp; - gl->gl_dstamp = ktime_get_real(); - irt = ktime_to_ns(ktime_sub(gl->gl_dstamp, dstamp)); - lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats); - gfs2_update_stats(&gl->gl_stats, GFS2_LKS_SIRT, irt); /* Local */ - gfs2_update_stats(&lks->lkstats[gltype], GFS2_LKS_SIRT, irt); /* Global */ - preempt_enable(); -} - static void gdlm_ast(void *arg) { struct gfs2_glock *gl = arg; unsigned ret = gl->gl_state; - gfs2_update_reply_times(gl); BUG_ON(gl->gl_lksb.sb_flags & DLM_SBF_DEMOTED); if (gl->gl_lksb.sb_flags & DLM_SBF_VALNOTVALID) @@ -203,7 +111,7 @@ static int make_mode(const unsigned int lmstate) static u32 make_flags(const u32 lkid, const unsigned int gfs_flags, const int req) { - u32 lkf = DLM_LKF_VALBLK; + u32 lkf = 0; if (gfs_flags & LM_FLAG_TRY) lkf |= DLM_LKF_NOQUEUE; @@ -230,15 +138,9 @@ static u32 make_flags(const u32 lkid, const unsigned int gfs_flags, if (lkid != 0) lkf |= DLM_LKF_CONVERT; - return lkf; -} + lkf |= DLM_LKF_VALBLK; -static void gfs2_reverse_hex(char *c, u64 value) -{ - while (value) { - *c-- = hex_asc[value & 0x0f]; - value >>= 4; - } + return lkf; } static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, @@ -247,26 +149,15 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; int req; u32 lkf; - char strname[GDLM_STRNAME_BYTES] = ""; req = make_mode(req_state); lkf = make_flags(gl->gl_lksb.sb_lkid, flags, req); - gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT); - gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT); - if (gl->gl_lksb.sb_lkid) { - gfs2_update_request_times(gl); - } else { - memset(strname, ' ', GDLM_STRNAME_BYTES - 1); - strname[GDLM_STRNAME_BYTES - 1] = '\0'; - gfs2_reverse_hex(strname + 7, gl->gl_name.ln_type); - gfs2_reverse_hex(strname + 23, gl->gl_name.ln_number); - gl->gl_dstamp = ktime_get_real(); - } + /* * Submit the actual lock request. */ - return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname, + return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, gl->gl_strname, GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); } @@ -281,10 +172,6 @@ static void gdlm_put_lock(struct gfs2_glock *gl) return; } - clear_bit(GLF_BLOCKING, &gl->gl_flags); - gfs2_glstats_inc(gl, GFS2_LKS_DCOUNT); - gfs2_sbstats_inc(gl, GFS2_LKS_DCOUNT); - gfs2_update_request_times(gl); error = dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_VALBLK, NULL, gl); if (error) { diff --git a/trunk/fs/gfs2/log.c b/trunk/fs/gfs2/log.c index 4752eadc7f6e..756fae9eaf8f 100644 --- a/trunk/fs/gfs2/log.c +++ b/trunk/fs/gfs2/log.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "gfs2.h" #include "incore.h" @@ -359,7 +358,7 @@ int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks) return 0; } -u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) +static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) { struct gfs2_journal_extent *je; @@ -468,8 +467,8 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) void gfs2_log_incr_head(struct gfs2_sbd *sdp) { - BUG_ON((sdp->sd_log_flush_head == sdp->sd_log_tail) && - (sdp->sd_log_flush_head != sdp->sd_log_head)); + if (sdp->sd_log_flush_head == sdp->sd_log_tail) + BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head); if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) { sdp->sd_log_flush_head = 0; @@ -477,6 +476,99 @@ void gfs2_log_incr_head(struct gfs2_sbd *sdp) } } +/** + * gfs2_log_write_endio - End of I/O for a log buffer + * @bh: The buffer head + * @uptodate: I/O Status + * + */ + +static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate) +{ + struct gfs2_sbd *sdp = bh->b_private; + bh->b_private = NULL; + + end_buffer_write_sync(bh, uptodate); + if (atomic_dec_and_test(&sdp->sd_log_in_flight)) + wake_up(&sdp->sd_log_flush_wait); +} + +/** + * gfs2_log_get_buf - Get and initialize a buffer to use for log control data + * @sdp: The GFS2 superblock + * + * Returns: the buffer_head + */ + +struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) +{ + u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); + struct buffer_head *bh; + + bh = sb_getblk(sdp->sd_vfs, blkno); + lock_buffer(bh); + memset(bh->b_data, 0, bh->b_size); + set_buffer_uptodate(bh); + clear_buffer_dirty(bh); + gfs2_log_incr_head(sdp); + atomic_inc(&sdp->sd_log_in_flight); + bh->b_private = sdp; + bh->b_end_io = gfs2_log_write_endio; + + return bh; +} + +/** + * gfs2_fake_write_endio - + * @bh: The buffer head + * @uptodate: The I/O Status + * + */ + +static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate) +{ + struct buffer_head *real_bh = bh->b_private; + struct gfs2_bufdata *bd = real_bh->b_private; + struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd; + + end_buffer_write_sync(bh, uptodate); + free_buffer_head(bh); + unlock_buffer(real_bh); + brelse(real_bh); + if (atomic_dec_and_test(&sdp->sd_log_in_flight)) + wake_up(&sdp->sd_log_flush_wait); +} + +/** + * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log + * @sdp: the filesystem + * @data: the data the buffer_head should point to + * + * Returns: the log buffer descriptor + */ + +struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, + struct buffer_head *real) +{ + u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); + struct buffer_head *bh; + + bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL); + atomic_set(&bh->b_count, 1); + bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); + set_bh_page(bh, real->b_page, bh_offset(real)); + bh->b_blocknr = blkno; + bh->b_size = sdp->sd_sb.sb_bsize; + bh->b_bdev = sdp->sd_vfs->s_bdev; + bh->b_private = real; + bh->b_end_io = gfs2_fake_write_endio; + + gfs2_log_incr_head(sdp); + atomic_inc(&sdp->sd_log_in_flight); + + return bh; +} + static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail) { unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail); @@ -491,8 +583,66 @@ static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail) sdp->sd_log_tail = new_tail; } +/** + * log_write_header - Get and initialize a journal header buffer + * @sdp: The GFS2 superblock + * + * Returns: the initialized log buffer descriptor + */ -static void log_flush_wait(struct gfs2_sbd *sdp) +static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) +{ + u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head); + struct buffer_head *bh; + struct gfs2_log_header *lh; + unsigned int tail; + u32 hash; + + bh = sb_getblk(sdp->sd_vfs, blkno); + lock_buffer(bh); + memset(bh->b_data, 0, bh->b_size); + set_buffer_uptodate(bh); + clear_buffer_dirty(bh); + + gfs2_ail1_empty(sdp); + tail = current_tail(sdp); + + lh = (struct gfs2_log_header *)bh->b_data; + memset(lh, 0, sizeof(struct gfs2_log_header)); + lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); + lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); + lh->lh_header.__pad0 = cpu_to_be64(0); + lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); + lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); + lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++); + lh->lh_flags = cpu_to_be32(flags); + lh->lh_tail = cpu_to_be32(tail); + lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head); + hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header)); + lh->lh_hash = cpu_to_be32(hash); + + bh->b_end_io = end_buffer_write_sync; + get_bh(bh); + if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) + submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh); + else + submit_bh(WRITE_FLUSH_FUA | REQ_META, bh); + wait_on_buffer(bh); + + if (!buffer_uptodate(bh)) + gfs2_io_error_bh(sdp, bh); + brelse(bh); + + if (sdp->sd_log_tail != tail) + log_pull_tail(sdp, tail); + else + gfs2_assert_withdraw(sdp, !pull); + + sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); + gfs2_log_incr_head(sdp); +} + +static void log_flush_commit(struct gfs2_sbd *sdp) { DEFINE_WAIT(wait); @@ -505,20 +655,8 @@ static void log_flush_wait(struct gfs2_sbd *sdp) } while(atomic_read(&sdp->sd_log_in_flight)); finish_wait(&sdp->sd_log_flush_wait, &wait); } -} - -static int bd_cmp(void *priv, struct list_head *a, struct list_head *b) -{ - struct gfs2_bufdata *bda, *bdb; - bda = list_entry(a, struct gfs2_bufdata, bd_le.le_list); - bdb = list_entry(b, struct gfs2_bufdata, bd_le.le_list); - - if (bda->bd_bh->b_blocknr < bdb->bd_bh->b_blocknr) - return -1; - if (bda->bd_bh->b_blocknr > bdb->bd_bh->b_blocknr) - return 1; - return 0; + log_write_header(sdp, 0, 0); } static void gfs2_ordered_write(struct gfs2_sbd *sdp) @@ -528,7 +666,6 @@ static void gfs2_ordered_write(struct gfs2_sbd *sdp) LIST_HEAD(written); gfs2_log_lock(sdp); - list_sort(NULL, &sdp->sd_log_le_ordered, &bd_cmp); while (!list_empty(&sdp->sd_log_le_ordered)) { bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_le.le_list); list_move(&bd->bd_le.le_list, &written); @@ -573,68 +710,6 @@ static void gfs2_ordered_wait(struct gfs2_sbd *sdp) gfs2_log_unlock(sdp); } -/** - * log_write_header - Get and initialize a journal header buffer - * @sdp: The GFS2 superblock - * - * Returns: the initialized log buffer descriptor - */ - -static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) -{ - u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head); - struct buffer_head *bh; - struct gfs2_log_header *lh; - unsigned int tail; - u32 hash; - - bh = sb_getblk(sdp->sd_vfs, blkno); - lock_buffer(bh); - memset(bh->b_data, 0, bh->b_size); - set_buffer_uptodate(bh); - clear_buffer_dirty(bh); - - gfs2_ail1_empty(sdp); - tail = current_tail(sdp); - - lh = (struct gfs2_log_header *)bh->b_data; - memset(lh, 0, sizeof(struct gfs2_log_header)); - lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC); - lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH); - lh->lh_header.__pad0 = cpu_to_be64(0); - lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH); - lh->lh_header.mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid); - lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++); - lh->lh_flags = cpu_to_be32(flags); - lh->lh_tail = cpu_to_be32(tail); - lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head); - hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header)); - lh->lh_hash = cpu_to_be32(hash); - - bh->b_end_io = end_buffer_write_sync; - get_bh(bh); - if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) { - gfs2_ordered_wait(sdp); - log_flush_wait(sdp); - submit_bh(WRITE_SYNC | REQ_META | REQ_PRIO, bh); - } else { - submit_bh(WRITE_FLUSH_FUA | REQ_META, bh); - } - wait_on_buffer(bh); - - if (!buffer_uptodate(bh)) - gfs2_io_error_bh(sdp, bh); - brelse(bh); - - if (sdp->sd_log_tail != tail) - log_pull_tail(sdp, tail); - else - gfs2_assert_withdraw(sdp, !pull); - - sdp->sd_log_idle = (tail == sdp->sd_log_flush_head); - gfs2_log_incr_head(sdp); -} - /** * gfs2_log_flush - flush incore transaction(s) * @sdp: the filesystem @@ -678,10 +753,11 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) gfs2_ordered_write(sdp); lops_before_commit(sdp); + gfs2_ordered_wait(sdp); - if (sdp->sd_log_head != sdp->sd_log_flush_head) { - log_write_header(sdp, 0, 0); - } else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ + if (sdp->sd_log_head != sdp->sd_log_flush_head) + log_flush_commit(sdp); + else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ gfs2_log_lock(sdp); atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ trace_gfs2_log_blocks(sdp, -1); diff --git a/trunk/fs/gfs2/log.h b/trunk/fs/gfs2/log.h index ff07454b582c..ab0621698b73 100644 --- a/trunk/fs/gfs2/log.h +++ b/trunk/fs/gfs2/log.h @@ -53,7 +53,10 @@ extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, extern int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks); extern void gfs2_log_incr_head(struct gfs2_sbd *sdp); -extern u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn); + +extern struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp); +extern struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, + struct buffer_head *real); extern void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl); extern void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans); extern void gfs2_remove_from_ail(struct gfs2_bufdata *bd); diff --git a/trunk/fs/gfs2/lops.c b/trunk/fs/gfs2/lops.c index 6b1efb594d90..df7c6e8d0764 100644 --- a/trunk/fs/gfs2/lops.c +++ b/trunk/fs/gfs2/lops.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -77,7 +76,7 @@ static void maybe_release_space(struct gfs2_bufdata *bd) if (bi->bi_clone == 0) return; if (sdp->sd_args.ar_discard) - gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL); + gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi); memcpy(bi->bi_clone + bi->bi_offset, bd->bd_bh->b_data + bi->bi_offset, bi->bi_len); clear_bit(GBF_FULL, &bi->bi_flags); @@ -144,98 +143,6 @@ static inline __be64 *bh_ptr_end(struct buffer_head *bh) return (__force __be64 *)(bh->b_data + bh->b_size); } -/** - * gfs2_log_write_endio - End of I/O for a log buffer - * @bh: The buffer head - * @uptodate: I/O Status - * - */ - -static void gfs2_log_write_endio(struct buffer_head *bh, int uptodate) -{ - struct gfs2_sbd *sdp = bh->b_private; - bh->b_private = NULL; - - end_buffer_write_sync(bh, uptodate); - if (atomic_dec_and_test(&sdp->sd_log_in_flight)) - wake_up(&sdp->sd_log_flush_wait); -} - -/** - * gfs2_log_get_buf - Get and initialize a buffer to use for log control data - * @sdp: The GFS2 superblock - * - * tReturns: the buffer_head - */ - -static struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp) -{ - u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head); - struct buffer_head *bh; - - bh = sb_getblk(sdp->sd_vfs, blkno); - lock_buffer(bh); - memset(bh->b_data, 0, bh->b_size); - set_buffer_uptodate(bh); - clear_buffer_dirty(bh); - gfs2_log_incr_head(sdp); - atomic_inc(&sdp->sd_log_in_flight); - bh->b_private = sdp; - bh->b_end_io = gfs2_log_write_endio; - - return bh; -} - -/** - * gfs2_fake_write_endio - - * @bh: The buffer head - * @uptodate: The I/O Status - * - */ - -static void gfs2_fake_write_endio(struct buffer_head *bh, int uptodate) -{ - struct buffer_head *real_bh = bh->b_private; - struct gfs2_bufdata *bd = real_bh->b_private; - struct gfs2_sbd *sdp = bd->bd_gl->gl_sbd; - - end_buffer_write_sync(bh, uptodate); - mempool_free(bh, gfs2_bh_pool); - unlock_buffer(real_bh); - brelse(real_bh); - if (atomic_dec_and_test(&sdp->sd_log_in_flight)) - wake_up(&sdp->sd_log_flush_wait); -} - -/** - * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log - * @sdp: the filesystem - * @data: the data the buffer_head should point to - * - * Returns: the log buffer descriptor - */ - -static struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp, - struct buffer_head *real) -{ - u64 blkno = gfs2_log_bmap(sdp, sdp->sd_log_flush_head); - struct buffer_head *bh; - - bh = mempool_alloc(gfs2_bh_pool, GFP_NOFS); - atomic_set(&bh->b_count, 1); - bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate) | (1 << BH_Lock); - set_bh_page(bh, real->b_page, bh_offset(real)); - bh->b_blocknr = blkno; - bh->b_size = sdp->sd_sb.sb_bsize; - bh->b_bdev = sdp->sd_vfs->s_bdev; - bh->b_private = real; - bh->b_end_io = gfs2_fake_write_endio; - - gfs2_log_incr_head(sdp); - atomic_inc(&sdp->sd_log_in_flight); - - return bh; -} static struct buffer_head *gfs2_get_log_desc(struct gfs2_sbd *sdp, u32 ld_type) { diff --git a/trunk/fs/gfs2/main.c b/trunk/fs/gfs2/main.c index 754426b1e52c..a8d9bcd0e19c 100644 --- a/trunk/fs/gfs2/main.c +++ b/trunk/fs/gfs2/main.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "gfs2.h" #include "incore.h" @@ -70,16 +69,6 @@ static void gfs2_init_gl_aspace_once(void *foo) address_space_init_once(mapping); } -static void *gfs2_bh_alloc(gfp_t mask, void *data) -{ - return alloc_buffer_head(mask); -} - -static void gfs2_bh_free(void *ptr, void *data) -{ - return free_buffer_head(ptr); -} - /** * init_gfs2_fs - Register GFS2 as a filesystem * @@ -162,10 +151,6 @@ static int __init init_gfs2_fs(void) gfs2_control_wq = alloc_workqueue("gfs2_control", WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE, 0); if (!gfs2_control_wq) - goto fail_recovery; - - gfs2_bh_pool = mempool_create(1024, gfs2_bh_alloc, gfs2_bh_free, NULL); - if (!gfs2_bh_pool) goto fail_control; gfs2_register_debugfs(); @@ -175,8 +160,6 @@ static int __init init_gfs2_fs(void) return 0; fail_control: - destroy_workqueue(gfs2_control_wq); -fail_recovery: destroy_workqueue(gfs_recovery_wq); fail_wq: unregister_filesystem(&gfs2meta_fs_type); @@ -225,7 +208,6 @@ static void __exit exit_gfs2_fs(void) rcu_barrier(); - mempool_destroy(gfs2_bh_pool); kmem_cache_destroy(gfs2_quotad_cachep); kmem_cache_destroy(gfs2_rgrpd_cachep); kmem_cache_destroy(gfs2_bufdata_cachep); diff --git a/trunk/fs/gfs2/ops_fstype.c b/trunk/fs/gfs2/ops_fstype.c index 6f3a18f9e176..24f609c9ef91 100644 --- a/trunk/fs/gfs2/ops_fstype.c +++ b/trunk/fs/gfs2/ops_fstype.c @@ -68,12 +68,6 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) sb->s_fs_info = sdp; sdp->sd_vfs = sb; - sdp->sd_lkstats = alloc_percpu(struct gfs2_pcpu_lkstats); - if (!sdp->sd_lkstats) { - kfree(sdp); - return NULL; - } - set_bit(SDF_NOJOURNALID, &sdp->sd_flags); gfs2_tune_init(&sdp->sd_tune); @@ -83,6 +77,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) spin_lock_init(&sdp->sd_statfs_spin); spin_lock_init(&sdp->sd_rindex_spin); + mutex_init(&sdp->sd_rindex_mutex); sdp->sd_rindex_tree.rb_node = NULL; INIT_LIST_HEAD(&sdp->sd_jindex_list); @@ -436,9 +431,10 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr, fs_err(sdp, "can't read in %s inode: %ld\n", name, PTR_ERR(inode)); return PTR_ERR(inode); } - dentry = d_make_root(inode); + dentry = d_alloc_root(inode); if (!dentry) { fs_err(sdp, "can't alloc %s dentry\n", name); + iput(inode); return -ENOMEM; } *dptr = dentry; @@ -1225,7 +1221,6 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent gfs2_sys_fs_del(sdp); fail: gfs2_delete_debugfs_file(sdp); - free_percpu(sdp->sd_lkstats); kfree(sdp); sb->s_fs_info = NULL; return error; @@ -1398,7 +1393,6 @@ static void gfs2_kill_sb(struct super_block *sb) shrink_dcache_sb(sb); kill_block_super(sb); gfs2_delete_debugfs_file(sdp); - free_percpu(sdp->sd_lkstats); kfree(sdp); } diff --git a/trunk/fs/gfs2/quota.c b/trunk/fs/gfs2/quota.c index 6019da3dcaed..c0f8904f0860 100644 --- a/trunk/fs/gfs2/quota.c +++ b/trunk/fs/gfs2/quota.c @@ -681,7 +681,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, ptr = qp; nbytes = sizeof(struct gfs2_quota); get_a_page: - page = find_or_create_page(mapping, index, GFP_NOFS); + page = grab_cache_page(mapping, index); if (!page) return -ENOMEM; diff --git a/trunk/fs/gfs2/rgrp.c b/trunk/fs/gfs2/rgrp.c index 19bde40b4864..49ada95209d0 100644 --- a/trunk/fs/gfs2/rgrp.c +++ b/trunk/fs/gfs2/rgrp.c @@ -327,34 +327,23 @@ static inline int rgrp_contains_block(struct gfs2_rgrpd *rgd, u64 block) * Returns: The resource group, or NULL if not found */ -struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact) +struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk) { - struct rb_node *n, *next; + struct rb_node **newn; struct gfs2_rgrpd *cur; - if (gfs2_rindex_update(sdp)) - return NULL; - spin_lock(&sdp->sd_rindex_spin); - n = sdp->sd_rindex_tree.rb_node; - while (n) { - cur = rb_entry(n, struct gfs2_rgrpd, rd_node); - next = NULL; + newn = &sdp->sd_rindex_tree.rb_node; + while (*newn) { + cur = rb_entry(*newn, struct gfs2_rgrpd, rd_node); if (blk < cur->rd_addr) - next = n->rb_left; + newn = &((*newn)->rb_left); else if (blk >= cur->rd_data0 + cur->rd_data) - next = n->rb_right; - if (next == NULL) { + newn = &((*newn)->rb_right); + else { spin_unlock(&sdp->sd_rindex_spin); - if (exact) { - if (blk < cur->rd_addr) - return NULL; - if (blk >= cur->rd_data0 + cur->rd_data) - return NULL; - } return cur; } - n = next; } spin_unlock(&sdp->sd_rindex_spin); @@ -543,6 +532,7 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp) struct file_ra_state ra_state; int error, rgrps; + mutex_lock(&sdp->sd_rindex_mutex); file_ra_state_init(&ra_state, inode->i_mapping); for (rgrps = 0;; rgrps++) { loff_t pos = rgrps * sizeof(struct gfs2_rindex); @@ -555,10 +545,11 @@ u64 gfs2_ri_total(struct gfs2_sbd *sdp) break; total_data += be32_to_cpu(((struct gfs2_rindex *)buf)->ri_data); } + mutex_unlock(&sdp->sd_rindex_mutex); return total_data; } -static int rgd_insert(struct gfs2_rgrpd *rgd) +static void rgd_insert(struct gfs2_rgrpd *rgd) { struct gfs2_sbd *sdp = rgd->rd_sbd; struct rb_node **newn = &sdp->sd_rindex_tree.rb_node, *parent = NULL; @@ -574,13 +565,11 @@ static int rgd_insert(struct gfs2_rgrpd *rgd) else if (rgd->rd_addr > cur->rd_addr) newn = &((*newn)->rb_right); else - return -EEXIST; + return; } rb_link_node(&rgd->rd_node, parent, newn); rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree); - sdp->sd_rgrps++; - return 0; } /** @@ -634,12 +623,10 @@ static int read_rindex_entry(struct gfs2_inode *ip, if (rgd->rd_data > sdp->sd_max_rg_data) sdp->sd_max_rg_data = rgd->rd_data; spin_lock(&sdp->sd_rindex_spin); - error = rgd_insert(rgd); + rgd_insert(rgd); + sdp->sd_rgrps++; spin_unlock(&sdp->sd_rindex_spin); - if (!error) - return 0; - - error = 0; /* someone else read in the rgrp; free it and ignore it */ + return error; fail: kfree(rgd->rd_bits); @@ -700,6 +687,7 @@ int gfs2_rindex_update(struct gfs2_sbd *sdp) /* Read new copy from disk if we don't have the latest */ if (!sdp->sd_rindex_uptodate) { + mutex_lock(&sdp->sd_rindex_mutex); if (!gfs2_glock_is_locked_by_me(gl)) { error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, &ri_gh); if (error) @@ -710,8 +698,10 @@ int gfs2_rindex_update(struct gfs2_sbd *sdp) error = gfs2_ri_update(ip); if (unlock_required) gfs2_glock_dq_uninit(&ri_gh); + mutex_unlock(&sdp->sd_rindex_mutex); } + return error; } @@ -820,9 +810,9 @@ void gfs2_rgrp_go_unlock(struct gfs2_holder *gh) } -int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, +void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, struct buffer_head *bh, - const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed) + const struct gfs2_bitmap *bi) { struct super_block *sb = sdp->sd_vfs; struct block_device *bdev = sb->s_bdev; @@ -833,19 +823,11 @@ int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, sector_t nr_sects = 0; int rv; unsigned int x; - u32 trimmed = 0; - u8 diff; for (x = 0; x < bi->bi_len; x++) { - const u8 *clone = bi->bi_clone ? bi->bi_clone : bi->bi_bh->b_data; - clone += bi->bi_offset; - clone += x; - if (bh) { - const u8 *orig = bh->b_data + bi->bi_offset + x; - diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1)); - } else { - diff = ~(*clone | (*clone >> 1)); - } + const u8 *orig = bh->b_data + bi->bi_offset + x; + const u8 *clone = bi->bi_clone + bi->bi_offset + x; + u8 diff = ~(*orig | (*orig >> 1)) & (*clone | (*clone >> 1)); diff &= 0x55; if (diff == 0) continue; @@ -856,14 +838,11 @@ int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, if (nr_sects == 0) goto start_new_extent; if ((start + nr_sects) != blk) { - if (nr_sects >= minlen) { - rv = blkdev_issue_discard(bdev, - start, nr_sects, - GFP_NOFS, 0); - if (rv) - goto fail; - trimmed += nr_sects; - } + rv = blkdev_issue_discard(bdev, start, + nr_sects, GFP_NOFS, + 0); + if (rv) + goto fail; nr_sects = 0; start_new_extent: start = blk; @@ -874,104 +853,15 @@ int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, blk += sects_per_blk; } } - if (nr_sects >= minlen) { + if (nr_sects) { rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS, 0); if (rv) goto fail; - trimmed += nr_sects; } - if (ptrimmed) - *ptrimmed = trimmed; - return 0; - + return; fail: - if (sdp->sd_args.ar_discard) - fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv); + fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv); sdp->sd_args.ar_discard = 0; - return -EIO; -} - -/** - * gfs2_fitrim - Generate discard requests for unused bits of the filesystem - * @filp: Any file on the filesystem - * @argp: Pointer to the arguments (also used to pass result) - * - * Returns: 0 on success, otherwise error code - */ - -int gfs2_fitrim(struct file *filp, void __user *argp) -{ - struct inode *inode = filp->f_dentry->d_inode; - struct gfs2_sbd *sdp = GFS2_SB(inode); - struct request_queue *q = bdev_get_queue(sdp->sd_vfs->s_bdev); - struct buffer_head *bh; - struct gfs2_rgrpd *rgd; - struct gfs2_rgrpd *rgd_end; - struct gfs2_holder gh; - struct fstrim_range r; - int ret = 0; - u64 amt; - u64 trimmed = 0; - unsigned int x; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!blk_queue_discard(q)) - return -EOPNOTSUPP; - - if (argp == NULL) { - r.start = 0; - r.len = ULLONG_MAX; - r.minlen = 0; - } else if (copy_from_user(&r, argp, sizeof(r))) - return -EFAULT; - - rgd = gfs2_blk2rgrpd(sdp, r.start, 0); - rgd_end = gfs2_blk2rgrpd(sdp, r.start + r.len, 0); - - while (1) { - - ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &gh); - if (ret) - goto out; - - if (!(rgd->rd_flags & GFS2_RGF_TRIMMED)) { - /* Trim each bitmap in the rgrp */ - for (x = 0; x < rgd->rd_length; x++) { - struct gfs2_bitmap *bi = rgd->rd_bits + x; - ret = gfs2_rgrp_send_discards(sdp, rgd->rd_data0, NULL, bi, r.minlen, &amt); - if (ret) { - gfs2_glock_dq_uninit(&gh); - goto out; - } - trimmed += amt; - } - - /* Mark rgrp as having been trimmed */ - ret = gfs2_trans_begin(sdp, RES_RG_HDR, 0); - if (ret == 0) { - bh = rgd->rd_bits[0].bi_bh; - rgd->rd_flags |= GFS2_RGF_TRIMMED; - gfs2_trans_add_bh(rgd->rd_gl, bh, 1); - gfs2_rgrp_out(rgd, bh->b_data); - gfs2_trans_end(sdp); - } - } - gfs2_glock_dq_uninit(&gh); - - if (rgd == rgd_end) - break; - - rgd = gfs2_rgrpd_get_next(rgd); - } - -out: - r.len = trimmed << 9; - if (argp && copy_to_user(argp, &r, sizeof(r))) - return -EFAULT; - - return ret; } /** @@ -1118,7 +1008,7 @@ static int get_local_rgrp(struct gfs2_inode *ip, u64 *last_unlinked) if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, ip->i_goal)) rgd = begin = ip->i_rgd; else - rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1); + rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal); if (rgd == NULL) return -EBADSLT; @@ -1403,7 +1293,7 @@ static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart, u32 length, rgrp_blk, buf_blk; unsigned int buf; - rgd = gfs2_blk2rgrpd(sdp, bstart, 1); + rgd = gfs2_blk2rgrpd(sdp, bstart); if (!rgd) { if (gfs2_consist(sdp)) fs_err(sdp, "block = %llu\n", (unsigned long long)bstart); @@ -1584,7 +1474,7 @@ void __gfs2_free_blocks(struct gfs2_inode *ip, u64 bstart, u32 blen, int meta) return; trace_gfs2_block_alloc(ip, bstart, blen, GFS2_BLKST_FREE); rgd->rd_free += blen; - rgd->rd_flags &= ~GFS2_RGF_TRIMMED; + gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1); gfs2_rgrp_out(rgd, rgd->rd_bits[0].bi_bh->b_data); @@ -1670,9 +1560,14 @@ int gfs2_check_blk_type(struct gfs2_sbd *sdp, u64 no_addr, unsigned int type) { struct gfs2_rgrpd *rgd; struct gfs2_holder rgd_gh; - int error = -EINVAL; + int error; + + error = gfs2_rindex_update(sdp); + if (error) + return error; - rgd = gfs2_blk2rgrpd(sdp, no_addr, 1); + error = -EINVAL; + rgd = gfs2_blk2rgrpd(sdp, no_addr); if (!rgd) goto fail; @@ -1715,7 +1610,7 @@ void gfs2_rlist_add(struct gfs2_inode *ip, struct gfs2_rgrp_list *rlist, if (ip->i_rgd && rgrp_contains_block(ip->i_rgd, block)) rgd = ip->i_rgd; else - rgd = gfs2_blk2rgrpd(sdp, block, 1); + rgd = gfs2_blk2rgrpd(sdp, block); if (!rgd) { fs_err(sdp, "rlist_add: no rgrp for block %llu\n", (unsigned long long)block); return; diff --git a/trunk/fs/gfs2/rgrp.h b/trunk/fs/gfs2/rgrp.h index b4b10f4de25f..ceec9106cdf4 100644 --- a/trunk/fs/gfs2/rgrp.h +++ b/trunk/fs/gfs2/rgrp.h @@ -11,7 +11,6 @@ #define __RGRP_DOT_H__ #include -#include struct gfs2_rgrpd; struct gfs2_sbd; @@ -19,7 +18,7 @@ struct gfs2_holder; extern void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd); -extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact); +extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk); extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp); extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd); @@ -63,9 +62,8 @@ extern void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state); extern void gfs2_rlist_free(struct gfs2_rgrp_list *rlist); extern u64 gfs2_ri_total(struct gfs2_sbd *sdp); extern int gfs2_rgrp_dump(struct seq_file *seq, const struct gfs2_glock *gl); -extern int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, - struct buffer_head *bh, - const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed); -extern int gfs2_fitrim(struct file *filp, void __user *argp); +extern void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, + struct buffer_head *bh, + const struct gfs2_bitmap *bi); #endif /* __RGRP_DOT_H__ */ diff --git a/trunk/fs/gfs2/super.c b/trunk/fs/gfs2/super.c index 6172fa77ad59..4553ce515f62 100644 --- a/trunk/fs/gfs2/super.c +++ b/trunk/fs/gfs2/super.c @@ -1417,7 +1417,7 @@ static int gfs2_dinode_dealloc(struct gfs2_inode *ip) if (error) goto out; - rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1); + rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr); if (!rgd) { gfs2_consist_inode(ip); error = -EIO; @@ -1557,7 +1557,6 @@ static void gfs2_evict_inode(struct inode *inode) end_writeback(inode); gfs2_dir_hash_inval(ip); ip->i_gl->gl_object = NULL; - flush_delayed_work_sync(&ip->i_gl->gl_work); gfs2_glock_add_to_lru(ip->i_gl); gfs2_glock_put(ip->i_gl); ip->i_gl = NULL; diff --git a/trunk/fs/gfs2/trace_gfs2.h b/trunk/fs/gfs2/trace_gfs2.h index dfa89cd75534..5d07609ec57d 100644 --- a/trunk/fs/gfs2/trace_gfs2.h +++ b/trunk/fs/gfs2/trace_gfs2.h @@ -11,7 +11,6 @@ #include #include #include -#include #include "incore.h" #include "glock.h" @@ -44,8 +43,7 @@ {(1UL << GLF_FROZEN), "F" }, \ {(1UL << GLF_QUEUED), "q" }, \ {(1UL << GLF_LRU), "L" }, \ - {(1UL << GLF_OBJECT), "o" }, \ - {(1UL << GLF_BLOCKING), "b" }) + {(1UL << GLF_OBJECT), "o" }) #ifndef NUMPTY #define NUMPTY @@ -238,62 +236,6 @@ TRACE_EVENT(gfs2_glock_queue, glock_trace_name(__entry->state)) ); -/* DLM sends a reply to GFS2 */ -TRACE_EVENT(gfs2_glock_lock_time, - - TP_PROTO(const struct gfs2_glock *gl, s64 tdiff), - - TP_ARGS(gl, tdiff), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( u64, glnum ) - __field( u32, gltype ) - __field( int, status ) - __field( char, flags ) - __field( s64, tdiff ) - __field( s64, srtt ) - __field( s64, srttvar ) - __field( s64, srttb ) - __field( s64, srttvarb ) - __field( s64, sirt ) - __field( s64, sirtvar ) - __field( s64, dcount ) - __field( s64, qcount ) - ), - - TP_fast_assign( - __entry->dev = gl->gl_sbd->sd_vfs->s_dev; - __entry->glnum = gl->gl_name.ln_number; - __entry->gltype = gl->gl_name.ln_type; - __entry->status = gl->gl_lksb.sb_status; - __entry->flags = gl->gl_lksb.sb_flags; - __entry->tdiff = tdiff; - __entry->srtt = gl->gl_stats.stats[GFS2_LKS_SRTT]; - __entry->srttvar = gl->gl_stats.stats[GFS2_LKS_SRTTVAR]; - __entry->srttb = gl->gl_stats.stats[GFS2_LKS_SRTTB]; - __entry->srttvarb = gl->gl_stats.stats[GFS2_LKS_SRTTVARB]; - __entry->sirt = gl->gl_stats.stats[GFS2_LKS_SIRT]; - __entry->sirtvar = gl->gl_stats.stats[GFS2_LKS_SIRTVAR]; - __entry->dcount = gl->gl_stats.stats[GFS2_LKS_DCOUNT]; - __entry->qcount = gl->gl_stats.stats[GFS2_LKS_QCOUNT]; - ), - - TP_printk("%u,%u glock %d:%lld status:%d flags:%02x tdiff:%lld srtt:%lld/%lld srttb:%lld/%lld sirt:%lld/%lld dcnt:%lld qcnt:%lld", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->gltype, - (unsigned long long)__entry->glnum, - __entry->status, __entry->flags, - (long long)__entry->tdiff, - (long long)__entry->srtt, - (long long)__entry->srttvar, - (long long)__entry->srttb, - (long long)__entry->srttvarb, - (long long)__entry->sirt, - (long long)__entry->sirtvar, - (long long)__entry->dcount, - (long long)__entry->qcount) -); - /* Section 2 - Log/journal * * Objectives: diff --git a/trunk/fs/gfs2/util.c b/trunk/fs/gfs2/util.c index 9e7765e8e7b0..53511291fe36 100644 --- a/trunk/fs/gfs2/util.c +++ b/trunk/fs/gfs2/util.c @@ -25,7 +25,6 @@ struct kmem_cache *gfs2_inode_cachep __read_mostly; struct kmem_cache *gfs2_bufdata_cachep __read_mostly; struct kmem_cache *gfs2_rgrpd_cachep __read_mostly; struct kmem_cache *gfs2_quotad_cachep __read_mostly; -mempool_t *gfs2_bh_pool __read_mostly; void gfs2_assert_i(struct gfs2_sbd *sdp) { diff --git a/trunk/fs/gfs2/util.h b/trunk/fs/gfs2/util.h index a4ce76c67dbb..b432e04600de 100644 --- a/trunk/fs/gfs2/util.h +++ b/trunk/fs/gfs2/util.h @@ -10,8 +10,6 @@ #ifndef __UTIL_DOT_H__ #define __UTIL_DOT_H__ -#include - #include "incore.h" #define fs_printk(level, fs, fmt, arg...) \ @@ -152,7 +150,6 @@ extern struct kmem_cache *gfs2_inode_cachep; extern struct kmem_cache *gfs2_bufdata_cachep; extern struct kmem_cache *gfs2_rgrpd_cachep; extern struct kmem_cache *gfs2_quotad_cachep; -extern mempool_t *gfs2_bh_pool; static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt, unsigned int *p) diff --git a/trunk/fs/gfs2/xattr.c b/trunk/fs/gfs2/xattr.c index 2e5ba425cae7..e9636591b5d5 100644 --- a/trunk/fs/gfs2/xattr.c +++ b/trunk/fs/gfs2/xattr.c @@ -251,7 +251,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh, if (!blks) return 0; - rgd = gfs2_blk2rgrpd(sdp, bn, 1); + rgd = gfs2_blk2rgrpd(sdp, bn); if (!rgd) { gfs2_consist_inode(ip); return -EIO; @@ -1439,7 +1439,7 @@ static int ea_dealloc_block(struct gfs2_inode *ip) struct gfs2_holder gh; int error; - rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr, 1); + rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr); if (!rgd) { gfs2_consist_inode(ip); return -EIO; diff --git a/trunk/fs/hfs/super.c b/trunk/fs/hfs/super.c index 7b4c537d6e13..8137fb3e6780 100644 --- a/trunk/fs/hfs/super.c +++ b/trunk/fs/hfs/super.c @@ -430,13 +430,15 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_d_op = &hfs_dentry_operations; res = -ENOMEM; - sb->s_root = d_make_root(root_inode); + sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) - goto bail_no_root; + goto bail_iput; /* everything's okay */ return 0; +bail_iput: + iput(root_inode); bail_no_root: printk(KERN_ERR "hfs: get root inode failed.\n"); bail: diff --git a/trunk/fs/hfsplus/hfsplus_fs.h b/trunk/fs/hfsplus/hfsplus_fs.h index 4e75ac646fea..21a5b7fc6db4 100644 --- a/trunk/fs/hfsplus/hfsplus_fs.h +++ b/trunk/fs/hfsplus/hfsplus_fs.h @@ -316,11 +316,6 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb) #define HFSPLUS_IOC_EXT2_SETFLAGS FS_IOC_SETFLAGS -/* - * hfs+-specific ioctl for making the filesystem bootable - */ -#define HFSPLUS_IOC_BLESS _IO('h', 0x80) - /* * Functions in any *.c used in other files */ diff --git a/trunk/fs/hfsplus/hfsplus_raw.h b/trunk/fs/hfsplus/hfsplus_raw.h index 921967e5abb1..927cdd6d5bf5 100644 --- a/trunk/fs/hfsplus/hfsplus_raw.h +++ b/trunk/fs/hfsplus/hfsplus_raw.h @@ -117,7 +117,7 @@ struct hfsplus_vh { __be32 write_count; __be64 encodings_bmp; - u32 finder_info[8]; + u8 finder_info[32]; struct hfsplus_fork_raw alloc_file; struct hfsplus_fork_raw ext_file; diff --git a/trunk/fs/hfsplus/inode.c b/trunk/fs/hfsplus/inode.c index 82b69ee4dacc..6643b242bdd7 100644 --- a/trunk/fs/hfsplus/inode.c +++ b/trunk/fs/hfsplus/inode.c @@ -193,7 +193,6 @@ static struct dentry *hfsplus_file_lookup(struct inode *dir, mutex_init(&hip->extents_lock); hip->extent_state = 0; hip->flags = 0; - hip->userflags = 0; set_bit(HFSPLUS_I_RSRC, &hip->flags); err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); @@ -401,7 +400,6 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode) atomic_set(&hip->opencnt, 0); hip->extent_state = 0; hip->flags = 0; - hip->userflags = 0; memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec)); memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); hip->alloc_blocks = 0; diff --git a/trunk/fs/hfsplus/ioctl.c b/trunk/fs/hfsplus/ioctl.c index c640ba57074b..f66c7655b3f7 100644 --- a/trunk/fs/hfsplus/ioctl.c +++ b/trunk/fs/hfsplus/ioctl.c @@ -20,38 +20,6 @@ #include #include "hfsplus_fs.h" -/* - * "Blessing" an HFS+ filesystem writes metadata to the superblock informing - * the platform firmware which file to boot from - */ -static int hfsplus_ioctl_bless(struct file *file, int __user *user_flags) -{ - struct dentry *dentry = file->f_path.dentry; - struct inode *inode = dentry->d_inode; - struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); - struct hfsplus_vh *vh = sbi->s_vhdr; - struct hfsplus_vh *bvh = sbi->s_backup_vhdr; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - mutex_lock(&sbi->vh_mutex); - - /* Directory containing the bootable system */ - vh->finder_info[0] = bvh->finder_info[0] = - cpu_to_be32(parent_ino(dentry)); - - /* Bootloader */ - vh->finder_info[1] = bvh->finder_info[1] = cpu_to_be32(inode->i_ino); - - /* Per spec, the OS X system folder - same as finder_info[0] here */ - vh->finder_info[5] = bvh->finder_info[5] = - cpu_to_be32(parent_ino(dentry)); - - mutex_unlock(&sbi->vh_mutex); - return 0; -} - static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags) { struct inode *inode = file->f_path.dentry->d_inode; @@ -140,8 +108,6 @@ long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return hfsplus_ioctl_getflags(file, argp); case HFSPLUS_IOC_EXT2_SETFLAGS: return hfsplus_ioctl_setflags(file, argp); - case HFSPLUS_IOC_BLESS: - return hfsplus_ioctl_bless(file, argp); default: return -ENOTTY; } diff --git a/trunk/fs/hfsplus/super.c b/trunk/fs/hfsplus/super.c index ceb1c281eefb..427682ca9e48 100644 --- a/trunk/fs/hfsplus/super.c +++ b/trunk/fs/hfsplus/super.c @@ -465,13 +465,6 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) goto out_put_alloc_file; } - sb->s_d_op = &hfsplus_dentry_operations; - sb->s_root = d_make_root(root); - if (!sb->s_root) { - err = -ENOMEM; - goto out_put_alloc_file; - } - str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; str.name = HFSP_HIDDENDIR_NAME; err = hfs_find_init(sbi->cat_tree, &fd); @@ -522,6 +515,13 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) } } + sb->s_d_op = &hfsplus_dentry_operations; + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + err = -ENOMEM; + goto out_put_hidden_dir; + } + unload_nls(sbi->nls); sbi->nls = nls; return 0; @@ -529,8 +529,7 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) out_put_hidden_dir: iput(sbi->hidden_dir); out_put_root: - dput(sb->s_root); - sb->s_root = NULL; + iput(root); out_put_alloc_file: iput(sbi->alloc_file); out_close_cat_tree: diff --git a/trunk/fs/hostfs/hostfs_kern.c b/trunk/fs/hostfs/hostfs_kern.c index 588d45885a6f..e130bd46d671 100644 --- a/trunk/fs/hostfs/hostfs_kern.c +++ b/trunk/fs/hostfs/hostfs_kern.c @@ -966,9 +966,9 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) } err = -ENOMEM; - sb->s_root = d_make_root(root_inode); + sb->s_root = d_alloc_root(root_inode); if (sb->s_root == NULL) - goto out; + goto out_put; return 0; diff --git a/trunk/fs/hpfs/super.c b/trunk/fs/hpfs/super.c index 54f6eccb79d9..3690467c944e 100644 --- a/trunk/fs/hpfs/super.c +++ b/trunk/fs/hpfs/super.c @@ -625,9 +625,11 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) hpfs_init_inode(root); hpfs_read_inode(root); unlock_new_inode(root); - s->s_root = d_make_root(root); - if (!s->s_root) + s->s_root = d_alloc_root(root); + if (!s->s_root) { + iput(root); goto bail0; + } /* * find the root directory's . pointer & finish filling in the inode diff --git a/trunk/fs/hppfs/hppfs.c b/trunk/fs/hppfs/hppfs.c index a80e45a690ac..d92f4ce80925 100644 --- a/trunk/fs/hppfs/hppfs.c +++ b/trunk/fs/hppfs/hppfs.c @@ -726,12 +726,17 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent) err = -ENOMEM; root_inode = get_inode(sb, dget(proc_mnt->mnt_root)); - sb->s_root = d_make_root(root_inode); - if (!sb->s_root) + if (!root_inode) goto out_mntput; + sb->s_root = d_alloc_root(root_inode); + if (!sb->s_root) + goto out_iput; + return 0; + out_iput: + iput(root_inode); out_mntput: mntput(proc_mnt); out: diff --git a/trunk/fs/hugetlbfs/inode.c b/trunk/fs/hugetlbfs/inode.c index 81932fa1861a..1e85a7ac0217 100644 --- a/trunk/fs/hugetlbfs/inode.c +++ b/trunk/fs/hugetlbfs/inode.c @@ -831,6 +831,8 @@ hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) static int hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) { + struct inode * inode; + struct dentry * root; int ret; struct hugetlbfs_config config; struct hugetlbfs_sb_info *sbinfo; @@ -863,9 +865,16 @@ hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_magic = HUGETLBFS_MAGIC; sb->s_op = &hugetlbfs_ops; sb->s_time_gran = 1; - sb->s_root = d_make_root(hugetlbfs_get_root(sb, &config)); - if (!sb->s_root) + inode = hugetlbfs_get_root(sb, &config); + if (!inode) + goto out_free; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); goto out_free; + } + sb->s_root = root; return 0; out_free: kfree(sbinfo); diff --git a/trunk/fs/inode.c b/trunk/fs/inode.c index 9f4f5fecc096..83ab215baab1 100644 --- a/trunk/fs/inode.c +++ b/trunk/fs/inode.c @@ -2,19 +2,29 @@ * (C) 1997 Linus Torvalds * (C) 1999 Andrea Arcangeli (dynamic inode allocation) */ -#include #include #include +#include +#include +#include +#include +#include #include +#include +#include #include #include #include +#include #include #include #include #include +#include #include #include +#include +#include #include /* for inode_has_buffers */ #include #include "internal.h" @@ -1358,6 +1368,17 @@ int generic_delete_inode(struct inode *inode) } EXPORT_SYMBOL(generic_delete_inode); +/* + * Normal UNIX filesystem behaviour: delete the + * inode when the usage count drops to zero, and + * i_nlink is zero. + */ +int generic_drop_inode(struct inode *inode) +{ + return !inode->i_nlink || inode_unhashed(inode); +} +EXPORT_SYMBOL_GPL(generic_drop_inode); + /* * Called when we're dropping the last reference * to an inode. @@ -1489,10 +1510,9 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode, * This function automatically handles read only file systems and media, * as well as the "noatime" flag and inode specific "noatime" markers. */ -void touch_atime(struct path *path) +void touch_atime(struct vfsmount *mnt, struct dentry *dentry) { - struct vfsmount *mnt = path->mnt; - struct inode *inode = path->dentry->d_inode; + struct inode *inode = dentry->d_inode; struct timespec now; if (inode->i_flags & S_NOATIME) diff --git a/trunk/fs/isofs/inode.c b/trunk/fs/isofs/inode.c index 29037c365ba4..bd62c76fb5df 100644 --- a/trunk/fs/isofs/inode.c +++ b/trunk/fs/isofs/inode.c @@ -947,8 +947,9 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) s->s_d_op = &isofs_dentry_ops[table]; /* get the root dentry */ - s->s_root = d_make_root(inode); + s->s_root = d_alloc_root(inode); if (!(s->s_root)) { + iput(inode); error = -ENOMEM; goto out_no_inode; } diff --git a/trunk/fs/jffs2/fs.c b/trunk/fs/jffs2/fs.c index c0d5c9d770da..2e0123867cb1 100644 --- a/trunk/fs/jffs2/fs.c +++ b/trunk/fs/jffs2/fs.c @@ -561,9 +561,9 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) ret = -ENOMEM; D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n")); - sb->s_root = d_make_root(root_i); + sb->s_root = d_alloc_root(root_i); if (!sb->s_root) - goto out_root; + goto out_root_i; sb->s_maxbytes = 0xFFFFFFFF; sb->s_blocksize = PAGE_CACHE_SIZE; @@ -573,6 +573,8 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) jffs2_start_garbage_collect_thread(c); return 0; + out_root_i: + iput(root_i); out_root: jffs2_free_ino_caches(c); jffs2_free_raw_node_refs(c); diff --git a/trunk/fs/jfs/namei.c b/trunk/fs/jfs/namei.c index 07c91ca6017d..5f7c160ea64f 100644 --- a/trunk/fs/jfs/namei.c +++ b/trunk/fs/jfs/namei.c @@ -220,6 +220,12 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) dquot_initialize(dip); + /* link count overflow on parent directory ? */ + if (dip->i_nlink == JFS_LINK_MAX) { + rc = -EMLINK; + goto out1; + } + /* * search parent directory for entry/freespace * (dtSearch() returns parent directory page pinned) @@ -800,6 +806,9 @@ static int jfs_link(struct dentry *old_dentry, jfs_info("jfs_link: %s %s", old_dentry->d_name.name, dentry->d_name.name); + if (ip->i_nlink == JFS_LINK_MAX) + return -EMLINK; + dquot_initialize(dir); tid = txBegin(ip->i_sb, 0); @@ -1129,6 +1138,10 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, rc = -ENOTEMPTY; goto out3; } + } else if ((new_dir != old_dir) && + (new_dir->i_nlink == JFS_LINK_MAX)) { + rc = -EMLINK; + goto out3; } } else if (new_ip) { IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL); diff --git a/trunk/fs/jfs/super.c b/trunk/fs/jfs/super.c index 4a82950f412f..682bca642f38 100644 --- a/trunk/fs/jfs/super.c +++ b/trunk/fs/jfs/super.c @@ -441,7 +441,6 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; sb->s_fs_info = sbi; - sb->s_max_links = JFS_LINK_MAX; sbi->sb = sb; sbi->uid = sbi->gid = sbi->umask = -1; @@ -522,7 +521,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) ret = PTR_ERR(inode); goto out_no_rw; } - sb->s_root = d_make_root(inode); + sb->s_root = d_alloc_root(inode); if (!sb->s_root) goto out_no_root; @@ -540,6 +539,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) out_no_root: jfs_err("jfs_read_super: get root dentry failed"); + iput(inode); out_no_rw: rc = jfs_umount(sb); @@ -860,14 +860,8 @@ static int __init init_jfs_fs(void) jfs_proc_init(); #endif - rc = register_filesystem(&jfs_fs_type); - if (!rc) - return 0; + return register_filesystem(&jfs_fs_type); -#ifdef PROC_FS_JFS - jfs_proc_clean(); -#endif - kthread_stop(jfsSyncThread); kill_committask: for (i = 0; i < commit_threads; i++) kthread_stop(jfsCommitThread[i]); diff --git a/trunk/fs/libfs.c b/trunk/fs/libfs.c index 722e0d5ba182..5b2dbb3ba4fc 100644 --- a/trunk/fs/libfs.c +++ b/trunk/fs/libfs.c @@ -491,9 +491,11 @@ int simple_fill_super(struct super_block *s, unsigned long magic, inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; set_nlink(inode, 2); - root = d_make_root(inode); - if (!root) + root = d_alloc_root(inode); + if (!root) { + iput(inode); return -ENOMEM; + } for (i = 0; !files->name || files->name[0]; i++, files++) { if (!files->name) continue; @@ -534,7 +536,7 @@ int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *c spin_lock(&pin_fs_lock); if (unlikely(!*mount)) { spin_unlock(&pin_fs_lock); - mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, NULL); + mnt = vfs_kern_mount(type, 0, type->name, NULL); if (IS_ERR(mnt)) return PTR_ERR(mnt); spin_lock(&pin_fs_lock); diff --git a/trunk/fs/logfs/dir.c b/trunk/fs/logfs/dir.c index bea5d1b9954b..1b6e21dda286 100644 --- a/trunk/fs/logfs/dir.c +++ b/trunk/fs/logfs/dir.c @@ -558,6 +558,9 @@ static int logfs_link(struct dentry *old_dentry, struct inode *dir, { struct inode *inode = old_dentry->d_inode; + if (inode->i_nlink >= LOGFS_LINK_MAX) + return -EMLINK; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; ihold(inode); inc_nlink(inode); diff --git a/trunk/fs/logfs/super.c b/trunk/fs/logfs/super.c index 97bca623d893..c9ee7f5d1caf 100644 --- a/trunk/fs/logfs/super.c +++ b/trunk/fs/logfs/super.c @@ -315,9 +315,11 @@ static int logfs_get_sb_final(struct super_block *sb) if (IS_ERR(rootdir)) goto fail; - sb->s_root = d_make_root(rootdir); - if (!sb->s_root) + sb->s_root = d_alloc_root(rootdir); + if (!sb->s_root) { + iput(rootdir); goto fail; + } /* at that point we know that ->put_super() will be called */ super->s_erase_page = alloc_pages(GFP_KERNEL, 0); @@ -540,7 +542,6 @@ static struct dentry *logfs_get_sb_device(struct logfs_super *super, * the filesystem incompatible with 32bit systems. */ sb->s_maxbytes = (1ull << 43) - 1; - sb->s_max_links = LOGFS_LINK_MAX; sb->s_op = &logfs_super_operations; sb->s_flags = flags | MS_NOATIME; @@ -626,10 +627,7 @@ static int __init logfs_init(void) if (ret) goto out2; - ret = register_filesystem(&logfs_fs_type); - if (!ret) - return 0; - logfs_destroy_inode_cache(); + return register_filesystem(&logfs_fs_type); out2: logfs_compr_exit(); out1: diff --git a/trunk/fs/minix/inode.c b/trunk/fs/minix/inode.c index fcb05d2c6b5f..fa8b612b8ce2 100644 --- a/trunk/fs/minix/inode.c +++ b/trunk/fs/minix/inode.c @@ -190,24 +190,24 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) sbi->s_version = MINIX_V1; sbi->s_dirsize = 16; sbi->s_namelen = 14; - s->s_max_links = MINIX_LINK_MAX; + sbi->s_link_max = MINIX_LINK_MAX; } else if (s->s_magic == MINIX_SUPER_MAGIC2) { sbi->s_version = MINIX_V1; sbi->s_dirsize = 32; sbi->s_namelen = 30; - s->s_max_links = MINIX_LINK_MAX; + sbi->s_link_max = MINIX_LINK_MAX; } else if (s->s_magic == MINIX2_SUPER_MAGIC) { sbi->s_version = MINIX_V2; sbi->s_nzones = ms->s_zones; sbi->s_dirsize = 16; sbi->s_namelen = 14; - s->s_max_links = MINIX2_LINK_MAX; + sbi->s_link_max = MINIX2_LINK_MAX; } else if (s->s_magic == MINIX2_SUPER_MAGIC2) { sbi->s_version = MINIX_V2; sbi->s_nzones = ms->s_zones; sbi->s_dirsize = 32; sbi->s_namelen = 30; - s->s_max_links = MINIX2_LINK_MAX; + sbi->s_link_max = MINIX2_LINK_MAX; } else if ( *(__u16 *)(bh->b_data + 24) == MINIX3_SUPER_MAGIC) { m3s = (struct minix3_super_block *) bh->b_data; s->s_magic = m3s->s_magic; @@ -221,9 +221,9 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) sbi->s_dirsize = 64; sbi->s_namelen = 60; sbi->s_version = MINIX_V3; + sbi->s_link_max = MINIX2_LINK_MAX; sbi->s_mount_state = MINIX_VALID_FS; sb_set_blocksize(s, m3s->s_blocksize); - s->s_max_links = MINIX2_LINK_MAX; } else goto out_no_fs; @@ -254,6 +254,14 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) minix_set_bit(0,sbi->s_imap[0]->b_data); minix_set_bit(0,sbi->s_zmap[0]->b_data); + /* set up enough so that it can read an inode */ + s->s_op = &minix_sops; + root_inode = minix_iget(s, MINIX_ROOT_INO); + if (IS_ERR(root_inode)) { + ret = PTR_ERR(root_inode); + goto out_no_root; + } + /* Apparently minix can create filesystems that allocate more blocks for * the bitmaps than needed. We simply ignore that, but verify it didn't * create one with not enough blocks and bail out if so. @@ -262,7 +270,7 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) if (sbi->s_imap_blocks < block) { printk("MINIX-fs: file system does not have enough " "imap blocks allocated. Refusing to mount\n"); - goto out_no_bitmap; + goto out_iput; } block = minix_blocks_needed( @@ -271,21 +279,13 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) if (sbi->s_zmap_blocks < block) { printk("MINIX-fs: file system does not have enough " "zmap blocks allocated. Refusing to mount.\n"); - goto out_no_bitmap; - } - - /* set up enough so that it can read an inode */ - s->s_op = &minix_sops; - root_inode = minix_iget(s, MINIX_ROOT_INO); - if (IS_ERR(root_inode)) { - ret = PTR_ERR(root_inode); - goto out_no_root; + goto out_iput; } ret = -ENOMEM; - s->s_root = d_make_root(root_inode); + s->s_root = d_alloc_root(root_inode); if (!s->s_root) - goto out_no_root; + goto out_iput; if (!(s->s_flags & MS_RDONLY)) { if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ @@ -301,6 +301,10 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) return 0; +out_iput: + iput(root_inode); + goto out_freemap; + out_no_root: if (!silent) printk("MINIX-fs: get root inode failed\n"); diff --git a/trunk/fs/minix/minix.h b/trunk/fs/minix/minix.h index 1ebd11854622..c889ef0aa571 100644 --- a/trunk/fs/minix/minix.h +++ b/trunk/fs/minix/minix.h @@ -34,6 +34,7 @@ struct minix_sb_info { unsigned long s_max_size; int s_dirsize; int s_namelen; + int s_link_max; struct buffer_head ** s_imap; struct buffer_head ** s_zmap; struct buffer_head * s_sbh; diff --git a/trunk/fs/minix/namei.c b/trunk/fs/minix/namei.c index 2d0ee1786305..2f76e38c2065 100644 --- a/trunk/fs/minix/namei.c +++ b/trunk/fs/minix/namei.c @@ -94,6 +94,9 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir, { struct inode *inode = old_dentry->d_inode; + if (inode->i_nlink >= minix_sb(inode->i_sb)->s_link_max) + return -EMLINK; + inode->i_ctime = CURRENT_TIME_SEC; inode_inc_link_count(inode); ihold(inode); @@ -103,7 +106,10 @@ static int minix_link(struct dentry * old_dentry, struct inode * dir, static int minix_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode) { struct inode * inode; - int err; + int err = -EMLINK; + + if (dir->i_nlink >= minix_sb(dir->i_sb)->s_link_max) + goto out; inode_inc_link_count(dir); @@ -175,6 +181,7 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry) static int minix_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir, struct dentry *new_dentry) { + struct minix_sb_info * info = minix_sb(old_dir->i_sb); struct inode * old_inode = old_dentry->d_inode; struct inode * new_inode = new_dentry->d_inode; struct page * dir_page = NULL; @@ -212,6 +219,11 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry, drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { + if (dir_de) { + err = -EMLINK; + if (new_dir->i_nlink >= info->s_link_max) + goto out_dir; + } err = minix_add_link(new_dentry, old_inode); if (err) goto out_dir; diff --git a/trunk/fs/namei.c b/trunk/fs/namei.c index 13e6a1f191a9..20a4fcf001ec 100644 --- a/trunk/fs/namei.c +++ b/trunk/fs/namei.c @@ -642,7 +642,7 @@ follow_link(struct path *link, struct nameidata *nd, void **p) cond_resched(); current->total_link_count++; - touch_atime(link); + touch_atime(link->mnt, dentry); nd_set_link(nd, NULL); error = security_inode_follow_link(link->dentry, nd); @@ -2691,7 +2691,6 @@ SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, d int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { int error = may_create(dir, dentry); - unsigned max_links = dir->i_sb->s_max_links; if (error) return error; @@ -2704,9 +2703,6 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) if (error) return error; - if (max_links && dir->i_nlink >= max_links) - return -EMLINK; - error = dir->i_op->mkdir(dir, dentry, mode); if (!error) fsnotify_mkdir(dir, dentry); @@ -3037,7 +3033,6 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) { struct inode *inode = old_dentry->d_inode; - unsigned max_links = dir->i_sb->s_max_links; int error; if (!inode) @@ -3068,8 +3063,6 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de /* Make sure we don't allow creating hardlink to an unlinked file */ if (inode->i_nlink == 0) error = -ENOENT; - else if (max_links && inode->i_nlink >= max_links) - error = -EMLINK; else error = dir->i_op->link(old_dentry, dir, new_dentry); mutex_unlock(&inode->i_mutex); @@ -3179,7 +3172,6 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, { int error = 0; struct inode *target = new_dentry->d_inode; - unsigned max_links = new_dir->i_sb->s_max_links; /* * If we are going to change the parent - check write permissions, @@ -3203,11 +3195,6 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry)) goto out; - error = -EMLINK; - if (max_links && !target && new_dir != old_dir && - new_dir->i_nlink >= max_links) - goto out; - if (target) shrink_dcache_parent(new_dentry); error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); diff --git a/trunk/fs/ncpfs/inode.c b/trunk/fs/ncpfs/inode.c index 49df0e7f8379..3d1e34f8a68e 100644 --- a/trunk/fs/ncpfs/inode.c +++ b/trunk/fs/ncpfs/inode.c @@ -716,11 +716,13 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) if (!root_inode) goto out_disconnect; DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber); - sb->s_root = d_make_root(root_inode); + sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) - goto out_disconnect; + goto out_no_root; return 0; +out_no_root: + iput(root_inode); out_disconnect: ncp_lock_server(server); ncp_disconnect(server); diff --git a/trunk/fs/nfs/client.c b/trunk/fs/nfs/client.c index d4f772ebd1ef..31778f74357d 100644 --- a/trunk/fs/nfs/client.c +++ b/trunk/fs/nfs/client.c @@ -36,7 +36,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/fs/nfs/getroot.c b/trunk/fs/nfs/getroot.c index 801d6d830787..dcb61548887f 100644 --- a/trunk/fs/nfs/getroot.c +++ b/trunk/fs/nfs/getroot.c @@ -49,9 +49,11 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i { /* The mntroot acts as the dummy root dentry for this superblock */ if (sb->s_root == NULL) { - sb->s_root = d_make_root(inode); - if (sb->s_root == NULL) + sb->s_root = d_alloc_root(inode); + if (sb->s_root == NULL) { + iput(inode); return -ENOMEM; + } ihold(inode); /* * Ensure that this dentry is invisible to d_find_alias(). diff --git a/trunk/fs/nfs/idmap.c b/trunk/fs/nfs/idmap.c index a1bbf7780dfc..2c05f1991e1e 100644 --- a/trunk/fs/nfs/idmap.c +++ b/trunk/fs/nfs/idmap.c @@ -198,7 +198,6 @@ int nfs_idmap_init(void) if (ret < 0) goto failed_put_key; - set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); cred->thread_keyring = keyring; cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; id_resolver_cache = cred; diff --git a/trunk/fs/nfsd/fault_inject.c b/trunk/fs/nfsd/fault_inject.c index 9559ce468732..ce7f0758d84c 100644 --- a/trunk/fs/nfsd/fault_inject.c +++ b/trunk/fs/nfsd/fault_inject.c @@ -72,7 +72,7 @@ int nfsd_fault_inject_init(void) { unsigned int i; struct nfsd_fault_inject_op *op; - umode_t mode = S_IFREG | S_IRUSR | S_IWUSR; + mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; debug_dir = debugfs_create_dir("nfsd", NULL); if (!debug_dir) diff --git a/trunk/fs/nfsd/vfs.c b/trunk/fs/nfsd/vfs.c index e59f71d0cf73..edf6d3ed8777 100644 --- a/trunk/fs/nfsd/vfs.c +++ b/trunk/fs/nfsd/vfs.c @@ -1541,31 +1541,30 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, __be32 nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) { + struct dentry *dentry; struct inode *inode; mm_segment_t oldfs; __be32 err; int host_err; - struct path path; err = fh_verify(rqstp, fhp, S_IFLNK, NFSD_MAY_NOP); if (err) goto out; - path.mnt = fhp->fh_export->ex_path.mnt; - path.dentry = fhp->fh_dentry; - inode = path.dentry->d_inode; + dentry = fhp->fh_dentry; + inode = dentry->d_inode; err = nfserr_inval; if (!inode->i_op->readlink) goto out; - touch_atime(&path); + touch_atime(fhp->fh_export->ex_path.mnt, dentry); /* N.B. Why does this call need a get_fs()?? * Remove the set_fs and watch the fireworks:-) --okir */ oldfs = get_fs(); set_fs(KERNEL_DS); - host_err = inode->i_op->readlink(path.dentry, buf, *lenp); + host_err = inode->i_op->readlink(dentry, buf, *lenp); set_fs(oldfs); if (host_err < 0) diff --git a/trunk/fs/nilfs2/namei.c b/trunk/fs/nilfs2/namei.c index fce2bbee66d4..1cd3f624dffc 100644 --- a/trunk/fs/nilfs2/namei.c +++ b/trunk/fs/nilfs2/namei.c @@ -193,6 +193,9 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir, struct nilfs_transaction_info ti; int err; + if (inode->i_nlink >= NILFS_LINK_MAX) + return -EMLINK; + err = nilfs_transaction_begin(dir->i_sb, &ti, 1); if (err) return err; @@ -216,6 +219,9 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) struct nilfs_transaction_info ti; int err; + if (dir->i_nlink >= NILFS_LINK_MAX) + return -EMLINK; + err = nilfs_transaction_begin(dir->i_sb, &ti, 1); if (err) return err; @@ -394,6 +400,11 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry, drop_nlink(new_inode); nilfs_mark_inode_dirty(new_inode); } else { + if (dir_de) { + err = -EMLINK; + if (new_dir->i_nlink >= NILFS_LINK_MAX) + goto out_dir; + } err = nilfs_add_link(new_dentry, old_inode); if (err) goto out_dir; diff --git a/trunk/fs/nilfs2/super.c b/trunk/fs/nilfs2/super.c index 1099a76cee59..08e3d4f9df18 100644 --- a/trunk/fs/nilfs2/super.c +++ b/trunk/fs/nilfs2/super.c @@ -917,8 +917,9 @@ static int nilfs_get_root_dentry(struct super_block *sb, if (root->cno == NILFS_CPTREE_CURRENT_CNO) { dentry = d_find_alias(inode); if (!dentry) { - dentry = d_make_root(inode); + dentry = d_alloc_root(inode); if (!dentry) { + iput(inode); ret = -ENOMEM; goto failed_dentry; } @@ -1058,7 +1059,6 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_export_op = &nilfs_export_ops; sb->s_root = NULL; sb->s_time_gran = 1; - sb->s_max_links = NILFS_LINK_MAX; bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info; sb->s_bdi = bdi ? : &default_backing_dev_info; diff --git a/trunk/fs/ntfs/super.c b/trunk/fs/ntfs/super.c index b341492542ca..28d4e6ab6634 100644 --- a/trunk/fs/ntfs/super.c +++ b/trunk/fs/ntfs/super.c @@ -2908,10 +2908,9 @@ static int ntfs_fill_super(struct super_block *sb, void *opt, const int silent) ntfs_error(sb, "Failed to load system files."); goto unl_upcase_iput_tmp_ino_err_out_now; } - - /* We grab a reference, simulating an ntfs_iget(). */ - ihold(vol->root_ino); - if ((sb->s_root = d_make_root(vol->root_ino))) { + if ((sb->s_root = d_alloc_root(vol->root_ino))) { + /* We grab a reference, simulating an ntfs_iget(). */ + ihold(vol->root_ino); ntfs_debug("Exiting, status successful."); /* Release the default upcase if it has no users. */ mutex_lock(&ntfs_lock); @@ -3159,8 +3158,6 @@ static int __init init_ntfs_fs(void) } printk(KERN_CRIT "NTFS: Failed to register NTFS filesystem driver!\n"); - /* Unregister the ntfs sysctls. */ - ntfs_sysctl(0); sysctl_err_out: kmem_cache_destroy(ntfs_big_inode_cache); big_inode_err_out: diff --git a/trunk/fs/ocfs2/dlmfs/dlmfs.c b/trunk/fs/ocfs2/dlmfs/dlmfs.c index 3b5825ef3193..abfac0d7ae9c 100644 --- a/trunk/fs/ocfs2/dlmfs/dlmfs.c +++ b/trunk/fs/ocfs2/dlmfs/dlmfs.c @@ -582,14 +582,24 @@ static int dlmfs_fill_super(struct super_block * sb, void * data, int silent) { + struct inode * inode; + struct dentry * root; + sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = DLMFS_MAGIC; sb->s_op = &dlmfs_ops; - sb->s_root = d_make_root(dlmfs_get_root_inode(sb)); - if (!sb->s_root) + inode = dlmfs_get_root_inode(sb); + if (!inode) + return -ENOMEM; + + root = d_alloc_root(inode); + if (!root) { + iput(inode); return -ENOMEM; + } + sb->s_root = root; return 0; } diff --git a/trunk/fs/ocfs2/super.c b/trunk/fs/ocfs2/super.c index 68f4541c2db9..604e12c4e979 100644 --- a/trunk/fs/ocfs2/super.c +++ b/trunk/fs/ocfs2/super.c @@ -1154,19 +1154,19 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) } status = ocfs2_mount_volume(sb); - if (status < 0) - goto read_super_error; - if (osb->root_inode) inode = igrab(osb->root_inode); + if (status < 0) + goto read_super_error; + if (!inode) { status = -EIO; mlog_errno(status); goto read_super_error; } - root = d_make_root(inode); + root = d_alloc_root(inode); if (!root) { status = -ENOMEM; mlog_errno(status); @@ -1220,6 +1220,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent) read_super_error: brelse(bh); + if (inode) + iput(inode); + if (osb) { atomic_set(&osb->vol_state, VOLUME_DISABLED); wake_up(&osb->osb_mount_event); @@ -1624,17 +1627,21 @@ static int __init ocfs2_init(void) init_waitqueue_head(&ocfs2__ioend_wq[i]); status = init_ocfs2_uptodate_cache(); - if (status < 0) - goto out1; + if (status < 0) { + mlog_errno(status); + goto leave; + } status = ocfs2_initialize_mem_caches(); - if (status < 0) - goto out2; + if (status < 0) { + mlog_errno(status); + goto leave; + } ocfs2_wq = create_singlethread_workqueue("ocfs2_wq"); if (!ocfs2_wq) { status = -ENOMEM; - goto out3; + goto leave; } ocfs2_debugfs_root = debugfs_create_dir("ocfs2", NULL); @@ -1646,23 +1653,17 @@ static int __init ocfs2_init(void) ocfs2_set_locking_protocol(); status = register_quota_format(&ocfs2_quota_format); - if (status < 0) - goto out4; - status = register_filesystem(&ocfs2_fs_type); - if (!status) - return 0; +leave: + if (status < 0) { + ocfs2_free_mem_caches(); + exit_ocfs2_uptodate_cache(); + mlog_errno(status); + } - unregister_quota_format(&ocfs2_quota_format); -out4: - destroy_workqueue(ocfs2_wq); - debugfs_remove(ocfs2_debugfs_root); -out3: - ocfs2_free_mem_caches(); -out2: - exit_ocfs2_uptodate_cache(); -out1: - mlog_errno(status); - return status; + if (status >= 0) { + return register_filesystem(&ocfs2_fs_type); + } else + return -1; } static void __exit ocfs2_exit(void) diff --git a/trunk/fs/omfs/inode.c b/trunk/fs/omfs/inode.c index dbc842222589..6065bb0ba207 100644 --- a/trunk/fs/omfs/inode.c +++ b/trunk/fs/omfs/inode.c @@ -539,9 +539,11 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) goto out_brelse_bh2; } - sb->s_root = d_make_root(root); - if (!sb->s_root) + sb->s_root = d_alloc_root(root); + if (!sb->s_root) { + iput(root); goto out_brelse_bh2; + } printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name); ret = 0; diff --git a/trunk/fs/openpromfs/inode.c b/trunk/fs/openpromfs/inode.c index bc49c975d501..a88c03bc749d 100644 --- a/trunk/fs/openpromfs/inode.c +++ b/trunk/fs/openpromfs/inode.c @@ -408,12 +408,13 @@ static int openprom_fill_super(struct super_block *s, void *data, int silent) oi->type = op_inode_node; oi->u.node = of_find_node_by_path("/"); - s->s_root = d_make_root(root_inode); + s->s_root = d_alloc_root(root_inode); if (!s->s_root) goto out_no_root_dentry; return 0; out_no_root_dentry: + iput(root_inode); ret = -ENOMEM; out_no_root: printk("openprom_fill_super: get root inode failed\n"); diff --git a/trunk/fs/proc/inode.c b/trunk/fs/proc/inode.c index 8461a7b82fdb..84fd3235a590 100644 --- a/trunk/fs/proc/inode.c +++ b/trunk/fs/proc/inode.c @@ -486,6 +486,8 @@ struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) int proc_fill_super(struct super_block *s) { + struct inode * root_inode; + s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; s->s_blocksize = 1024; s->s_blocksize_bits = 10; @@ -494,11 +496,19 @@ int proc_fill_super(struct super_block *s) s->s_time_gran = 1; pde_get(&proc_root); - s->s_root = d_make_root(proc_get_inode(s, &proc_root)); - if (s->s_root) - return 0; + root_inode = proc_get_inode(s, &proc_root); + if (!root_inode) + goto out_no_root; + root_inode->i_uid = 0; + root_inode->i_gid = 0; + s->s_root = d_alloc_root(root_inode); + if (!s->s_root) + goto out_no_root; + return 0; +out_no_root: printk("proc_read_super: get root inode failed\n"); + iput(root_inode); pde_put(&proc_root); return -ENOMEM; } diff --git a/trunk/fs/proc/proc_sysctl.c b/trunk/fs/proc/proc_sysctl.c index 67bbf6e4e197..a6b62173d4c3 100644 --- a/trunk/fs/proc/proc_sysctl.c +++ b/trunk/fs/proc/proc_sysctl.c @@ -6,9 +6,7 @@ #include #include #include -#include #include -#include #include "internal.h" static const struct dentry_operations proc_sys_dentry_operations; diff --git a/trunk/fs/proc/task_mmu.c b/trunk/fs/proc/task_mmu.c index 7dcd2a250495..3efa7253523e 100644 --- a/trunk/fs/proc/task_mmu.c +++ b/trunk/fs/proc/task_mmu.c @@ -409,6 +409,9 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, } else { spin_unlock(&walk->mm->page_table_lock); } + + if (pmd_trans_unstable(pmd)) + return 0; /* * The mmap_sem held all the way back in m_start() is what * keeps khugepaged out of here and from collapsing things @@ -507,6 +510,8 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, struct page *page; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); for (; addr != end; pte++, addr += PAGE_SIZE) { @@ -670,6 +675,8 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, int err = 0; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; /* find the first VMA at or above 'addr' */ vma = find_vma(walk->mm, addr); @@ -961,6 +968,8 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, spin_unlock(&walk->mm->page_table_lock); } + if (pmd_trans_unstable(pmd)) + return 0; orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); do { struct page *page = can_gather_numa_stats(*pte, md->vma, addr); diff --git a/trunk/fs/proc/vmcore.c b/trunk/fs/proc/vmcore.c index 0d5071d29985..b0f450a2bb7c 100644 --- a/trunk/fs/proc/vmcore.c +++ b/trunk/fs/proc/vmcore.c @@ -700,26 +700,3 @@ static int __init vmcore_init(void) return 0; } module_init(vmcore_init) - -/* Cleanup function for vmcore module. */ -void vmcore_cleanup(void) -{ - struct list_head *pos, *next; - - if (proc_vmcore) { - remove_proc_entry(proc_vmcore->name, proc_vmcore->parent); - proc_vmcore = NULL; - } - - /* clear the vmcore list. */ - list_for_each_safe(pos, next, &vmcore_list) { - struct vmcore *m; - - m = list_entry(pos, struct vmcore, list); - list_del(&m->list); - kfree(m); - } - kfree(elfcorebuf); - elfcorebuf = NULL; -} -EXPORT_SYMBOL_GPL(vmcore_cleanup); diff --git a/trunk/fs/pstore/inode.c b/trunk/fs/pstore/inode.c index f37c32b94525..b3b426edb2fd 100644 --- a/trunk/fs/pstore/inode.c +++ b/trunk/fs/pstore/inode.c @@ -278,7 +278,9 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id, int pstore_fill_super(struct super_block *sb, void *data, int silent) { - struct inode *inode; + struct inode *inode = NULL; + struct dentry *root; + int err; save_mount_options(sb, data); @@ -294,17 +296,26 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent) parse_options(data); inode = pstore_get_inode(sb, NULL, S_IFDIR | 0755, 0); - if (inode) { - /* override ramfs "dir" options so we catch unlink(2) */ - inode->i_op = &pstore_dir_inode_operations; + if (!inode) { + err = -ENOMEM; + goto fail; + } + /* override ramfs "dir" options so we catch unlink(2) */ + inode->i_op = &pstore_dir_inode_operations; + + root = d_alloc_root(inode); + sb->s_root = root; + if (!root) { + err = -ENOMEM; + goto fail; } - sb->s_root = d_make_root(inode); - if (!sb->s_root) - return -ENOMEM; pstore_get_records(0); return 0; +fail: + iput(inode); + return err; } static struct dentry *pstore_mount(struct file_system_type *fs_type, diff --git a/trunk/fs/qnx4/inode.c b/trunk/fs/qnx4/inode.c index 552e994e3aa1..6b009548d2e0 100644 --- a/trunk/fs/qnx4/inode.c +++ b/trunk/fs/qnx4/inode.c @@ -52,6 +52,38 @@ static int qnx4_remount(struct super_block *sb, int *flags, char *data) return 0; } +static struct buffer_head *qnx4_getblk(struct inode *inode, int nr, + int create) +{ + struct buffer_head *result = NULL; + + if ( nr >= 0 ) + nr = qnx4_block_map( inode, nr ); + if (nr) { + result = sb_getblk(inode->i_sb, nr); + return result; + } + return NULL; +} + +struct buffer_head *qnx4_bread(struct inode *inode, int block, int create) +{ + struct buffer_head *bh; + + bh = qnx4_getblk(inode, block, create); + if (!bh || buffer_uptodate(bh)) { + return bh; + } + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (buffer_uptodate(bh)) { + return bh; + } + brelse(bh); + + return NULL; +} + static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_head *bh, int create ) { unsigned long phys; @@ -66,31 +98,23 @@ static int qnx4_get_block( struct inode *inode, sector_t iblock, struct buffer_h return 0; } -static inline u32 try_extent(qnx4_xtnt_t *extent, u32 *offset) -{ - u32 size = le32_to_cpu(extent->xtnt_size); - if (*offset < size) - return le32_to_cpu(extent->xtnt_blk) + *offset - 1; - *offset -= size; - return 0; -} - unsigned long qnx4_block_map( struct inode *inode, long iblock ) { int ix; - long i_xblk; + long offset, i_xblk; + unsigned long block = 0; struct buffer_head *bh = NULL; struct qnx4_xblk *xblk = NULL; struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode); u16 nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts); - u32 offset = iblock; - u32 block = try_extent(&qnx4_inode->di_first_xtnt, &offset); - if (block) { + if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) { // iblock is in the first extent. This is easy. + block = le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_blk) + iblock - 1; } else { // iblock is beyond first extent. We have to follow the extent chain. i_xblk = le32_to_cpu(qnx4_inode->di_xblk); + offset = iblock - le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size); ix = 0; while ( --nxtnt > 0 ) { if ( ix == 0 ) { @@ -106,11 +130,12 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock ) return -EIO; } } - block = try_extent(&xblk->xblk_xtnts[ix], &offset); - if (block) { + if ( offset < le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size) ) { // got it! + block = le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_blk) + offset - 1; break; } + offset -= le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size); if ( ++ix >= xblk->xblk_num_xtnts ) { i_xblk = le32_to_cpu(xblk->xblk_next_xblk); ix = 0; @@ -235,13 +260,15 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) } ret = -ENOMEM; - s->s_root = d_make_root(root); + s->s_root = d_alloc_root(root); if (s->s_root == NULL) - goto outb; + goto outi; brelse(bh); return 0; + outi: + iput(root); outb: kfree(qs->BitMap); out: @@ -261,17 +288,44 @@ static void qnx4_put_super(struct super_block *sb) return; } +static int qnx4_writepage(struct page *page, struct writeback_control *wbc) +{ + return block_write_full_page(page,qnx4_get_block, wbc); +} + static int qnx4_readpage(struct file *file, struct page *page) { return block_read_full_page(page,qnx4_get_block); } +static int qnx4_write_begin(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata) +{ + struct qnx4_inode_info *qnx4_inode = qnx4_i(mapping->host); + int ret; + + *pagep = NULL; + ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, + qnx4_get_block, + &qnx4_inode->mmu_private); + if (unlikely(ret)) { + loff_t isize = mapping->host->i_size; + if (pos + len > isize) + vmtruncate(mapping->host, isize); + } + + return ret; +} static sector_t qnx4_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,qnx4_get_block); } static const struct address_space_operations qnx4_aops = { .readpage = qnx4_readpage, + .writepage = qnx4_writepage, + .write_begin = qnx4_write_begin, + .write_end = generic_write_end, .bmap = qnx4_bmap }; diff --git a/trunk/fs/qnx4/namei.c b/trunk/fs/qnx4/namei.c index a512c0b30e8e..275327b5615e 100644 --- a/trunk/fs/qnx4/namei.c +++ b/trunk/fs/qnx4/namei.c @@ -39,6 +39,10 @@ static int qnx4_match(int len, const char *name, } else { namelen = QNX4_SHORT_NAME_MAX; } + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (de->di_fname[0] == '.') && (de->di_fname[1] == '\0')) { + return 1; + } thislen = strlen( de->di_fname ); if ( thislen > namelen ) thislen = namelen; @@ -68,9 +72,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir, block = offset = blkofs = 0; while (blkofs * QNX4_BLOCK_SIZE + offset < dir->i_size) { if (!bh) { - block = qnx4_block_map(dir, blkofs); - if (block) - bh = sb_bread(dir->i_sb, block); + bh = qnx4_bread(dir, blkofs, 0); if (!bh) { blkofs++; continue; @@ -78,6 +80,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir, } *res_dir = (struct qnx4_inode_entry *) (bh->b_data + offset); if (qnx4_match(len, name, bh, &offset)) { + block = qnx4_block_map( dir, blkofs ); *ino = block * QNX4_INODES_PER_BLOCK + (offset / QNX4_DIR_ENTRY_SIZE) - 1; return bh; diff --git a/trunk/fs/qnx4/qnx4.h b/trunk/fs/qnx4/qnx4.h index 244d4620189b..33a60858203b 100644 --- a/trunk/fs/qnx4/qnx4.h +++ b/trunk/fs/qnx4/qnx4.h @@ -27,6 +27,8 @@ extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, stru extern unsigned long qnx4_count_free_blocks(struct super_block *sb); extern unsigned long qnx4_block_map(struct inode *inode, long iblock); +extern struct buffer_head *qnx4_bread(struct inode *, int, int); + extern const struct inode_operations qnx4_dir_inode_operations; extern const struct file_operations qnx4_dir_operations; extern int qnx4_is_free(struct super_block *sb, long block); diff --git a/trunk/fs/qnx6/Kconfig b/trunk/fs/qnx6/Kconfig deleted file mode 100644 index edbba5c17cc8..000000000000 --- a/trunk/fs/qnx6/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config QNX6FS_FS - tristate "QNX6 file system support (read only)" - depends on BLOCK && CRC32 - help - This is the file system used by the real-time operating systems - QNX 6 (also called QNX RTP). - Further information is available at . - Say Y if you intend to mount QNX hard disks or floppies formatted - with a mkqnx6fs. - However, keep in mind that this currently is a readonly driver! - - To compile this file system support as a module, choose M here: the - module will be called qnx6. - - If you don't know whether you need it, then you don't need it: - answer N. - -config QNX6FS_DEBUG - bool "QNX6 debugging information" - depends on QNX6FS_FS - help - Turns on extended debugging output. - - If you are not a developer working on the QNX6FS, you probably don't - want this: - answer N. diff --git a/trunk/fs/qnx6/Makefile b/trunk/fs/qnx6/Makefile deleted file mode 100644 index 9dd06199afc9..000000000000 --- a/trunk/fs/qnx6/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the linux qnx4-filesystem routines. -# - -obj-$(CONFIG_QNX6FS_FS) += qnx6.o - -qnx6-objs := inode.o dir.o namei.o super_mmi.o diff --git a/trunk/fs/qnx6/README b/trunk/fs/qnx6/README deleted file mode 100644 index 116d622026cc..000000000000 --- a/trunk/fs/qnx6/README +++ /dev/null @@ -1,8 +0,0 @@ - - This is a snapshot of the QNX6 filesystem for Linux. - Please send diffs and remarks to . - -Credits : - -Al Viro (endless patience with me & support ;)) -Kai Bankett (Maintainer) diff --git a/trunk/fs/qnx6/dir.c b/trunk/fs/qnx6/dir.c deleted file mode 100644 index dc597353db3b..000000000000 --- a/trunk/fs/qnx6/dir.c +++ /dev/null @@ -1,291 +0,0 @@ -/* - * QNX6 file system, Linux implementation. - * - * Version : 1.0.0 - * - * History : - * - * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release. - * 16-02-2012 pagemap extension by Al Viro - * - */ - -#include "qnx6.h" - -static unsigned qnx6_lfile_checksum(char *name, unsigned size) -{ - unsigned crc = 0; - char *end = name + size; - while (name < end) { - crc = ((crc >> 1) + *(name++)) ^ - ((crc & 0x00000001) ? 0x80000000 : 0); - } - return crc; -} - -static struct page *qnx6_get_page(struct inode *dir, unsigned long n) -{ - struct address_space *mapping = dir->i_mapping; - struct page *page = read_mapping_page(mapping, n, NULL); - if (!IS_ERR(page)) - kmap(page); - return page; -} - -static inline unsigned long dir_pages(struct inode *inode) -{ - return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; -} - -static unsigned last_entry(struct inode *inode, unsigned long page_nr) -{ - unsigned long last_byte = inode->i_size; - last_byte -= page_nr << PAGE_CACHE_SHIFT; - if (last_byte > PAGE_CACHE_SIZE) - last_byte = PAGE_CACHE_SIZE; - return last_byte / QNX6_DIR_ENTRY_SIZE; -} - -static struct qnx6_long_filename *qnx6_longname(struct super_block *sb, - struct qnx6_long_dir_entry *de, - struct page **p) -{ - struct qnx6_sb_info *sbi = QNX6_SB(sb); - u32 s = fs32_to_cpu(sbi, de->de_long_inode); /* in block units */ - u32 n = s >> (PAGE_CACHE_SHIFT - sb->s_blocksize_bits); /* in pages */ - /* within page */ - u32 offs = (s << sb->s_blocksize_bits) & ~PAGE_CACHE_MASK; - struct address_space *mapping = sbi->longfile->i_mapping; - struct page *page = read_mapping_page(mapping, n, NULL); - if (IS_ERR(page)) - return ERR_CAST(page); - kmap(*p = page); - return (struct qnx6_long_filename *)(page_address(page) + offs); -} - -static int qnx6_dir_longfilename(struct inode *inode, - struct qnx6_long_dir_entry *de, - void *dirent, loff_t pos, - unsigned de_inode, filldir_t filldir) -{ - struct qnx6_long_filename *lf; - struct super_block *s = inode->i_sb; - struct qnx6_sb_info *sbi = QNX6_SB(s); - struct page *page; - int lf_size; - - if (de->de_size != 0xff) { - /* error - long filename entries always have size 0xff - in direntry */ - printk(KERN_ERR "qnx6: invalid direntry size (%i).\n", - de->de_size); - return 0; - } - lf = qnx6_longname(s, de, &page); - if (IS_ERR(lf)) { - printk(KERN_ERR "qnx6:Error reading longname\n"); - return 0; - } - - lf_size = fs16_to_cpu(sbi, lf->lf_size); - - if (lf_size > QNX6_LONG_NAME_MAX) { - QNX6DEBUG((KERN_INFO "file %s\n", lf->lf_fname)); - printk(KERN_ERR "qnx6:Filename too long (%i)\n", lf_size); - qnx6_put_page(page); - return 0; - } - - /* calc & validate longfilename checksum - mmi 3g filesystem does not have that checksum */ - if (!test_opt(s, MMI_FS) && fs32_to_cpu(sbi, de->de_checksum) != - qnx6_lfile_checksum(lf->lf_fname, lf_size)) - printk(KERN_INFO "qnx6: long filename checksum error.\n"); - - QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s inode:%u\n", - lf_size, lf->lf_fname, de_inode)); - if (filldir(dirent, lf->lf_fname, lf_size, pos, de_inode, - DT_UNKNOWN) < 0) { - qnx6_put_page(page); - return 0; - } - - qnx6_put_page(page); - /* success */ - return 1; -} - -static int qnx6_readdir(struct file *filp, void *dirent, filldir_t filldir) -{ - struct inode *inode = filp->f_path.dentry->d_inode; - struct super_block *s = inode->i_sb; - struct qnx6_sb_info *sbi = QNX6_SB(s); - loff_t pos = filp->f_pos & (QNX6_DIR_ENTRY_SIZE - 1); - unsigned long npages = dir_pages(inode); - unsigned long n = pos >> PAGE_CACHE_SHIFT; - unsigned start = (pos & ~PAGE_CACHE_MASK) / QNX6_DIR_ENTRY_SIZE; - bool done = false; - - if (filp->f_pos >= inode->i_size) - return 0; - - for ( ; !done && n < npages; n++, start = 0) { - struct page *page = qnx6_get_page(inode, n); - int limit = last_entry(inode, n); - struct qnx6_dir_entry *de; - int i = start; - - if (IS_ERR(page)) { - printk(KERN_ERR "qnx6_readdir: read failed\n"); - filp->f_pos = (n + 1) << PAGE_CACHE_SHIFT; - return PTR_ERR(page); - } - de = ((struct qnx6_dir_entry *)page_address(page)) + start; - for (; i < limit; i++, de++, pos += QNX6_DIR_ENTRY_SIZE) { - int size = de->de_size; - u32 no_inode = fs32_to_cpu(sbi, de->de_inode); - - if (!no_inode || !size) - continue; - - if (size > QNX6_SHORT_NAME_MAX) { - /* long filename detected - get the filename from long filename - structure / block */ - if (!qnx6_dir_longfilename(inode, - (struct qnx6_long_dir_entry *)de, - dirent, pos, no_inode, - filldir)) { - done = true; - break; - } - } else { - QNX6DEBUG((KERN_INFO "qnx6_readdir:%.*s" - " inode:%u\n", size, de->de_fname, - no_inode)); - if (filldir(dirent, de->de_fname, size, - pos, no_inode, DT_UNKNOWN) - < 0) { - done = true; - break; - } - } - } - qnx6_put_page(page); - } - filp->f_pos = pos; - return 0; -} - -/* - * check if the long filename is correct. - */ -static unsigned qnx6_long_match(int len, const char *name, - struct qnx6_long_dir_entry *de, struct inode *dir) -{ - struct super_block *s = dir->i_sb; - struct qnx6_sb_info *sbi = QNX6_SB(s); - struct page *page; - int thislen; - struct qnx6_long_filename *lf = qnx6_longname(s, de, &page); - - if (IS_ERR(lf)) - return 0; - - thislen = fs16_to_cpu(sbi, lf->lf_size); - if (len != thislen) { - qnx6_put_page(page); - return 0; - } - if (memcmp(name, lf->lf_fname, len) == 0) { - qnx6_put_page(page); - return fs32_to_cpu(sbi, de->de_inode); - } - qnx6_put_page(page); - return 0; -} - -/* - * check if the filename is correct. - */ -static unsigned qnx6_match(struct super_block *s, int len, const char *name, - struct qnx6_dir_entry *de) -{ - struct qnx6_sb_info *sbi = QNX6_SB(s); - if (memcmp(name, de->de_fname, len) == 0) - return fs32_to_cpu(sbi, de->de_inode); - return 0; -} - - -unsigned qnx6_find_entry(int len, struct inode *dir, const char *name, - struct page **res_page) -{ - struct super_block *s = dir->i_sb; - struct qnx6_inode_info *ei = QNX6_I(dir); - struct page *page = NULL; - unsigned long start, n; - unsigned long npages = dir_pages(dir); - unsigned ino; - struct qnx6_dir_entry *de; - struct qnx6_long_dir_entry *lde; - - *res_page = NULL; - - if (npages == 0) - return 0; - start = ei->i_dir_start_lookup; - if (start >= npages) - start = 0; - n = start; - - do { - page = qnx6_get_page(dir, n); - if (!IS_ERR(page)) { - int limit = last_entry(dir, n); - int i; - - de = (struct qnx6_dir_entry *)page_address(page); - for (i = 0; i < limit; i++, de++) { - if (len <= QNX6_SHORT_NAME_MAX) { - /* short filename */ - if (len != de->de_size) - continue; - ino = qnx6_match(s, len, name, de); - if (ino) - goto found; - } else if (de->de_size == 0xff) { - /* deal with long filename */ - lde = (struct qnx6_long_dir_entry *)de; - ino = qnx6_long_match(len, - name, lde, dir); - if (ino) - goto found; - } else - printk(KERN_ERR "qnx6: undefined " - "filename size in inode.\n"); - } - qnx6_put_page(page); - } - - if (++n >= npages) - n = 0; - } while (n != start); - return 0; - -found: - *res_page = page; - ei->i_dir_start_lookup = n; - return ino; -} - -const struct file_operations qnx6_dir_operations = { - .llseek = generic_file_llseek, - .read = generic_read_dir, - .readdir = qnx6_readdir, - .fsync = generic_file_fsync, -}; - -const struct inode_operations qnx6_dir_inode_operations = { - .lookup = qnx6_lookup, -}; diff --git a/trunk/fs/qnx6/inode.c b/trunk/fs/qnx6/inode.c deleted file mode 100644 index e44012dc5645..000000000000 --- a/trunk/fs/qnx6/inode.c +++ /dev/null @@ -1,698 +0,0 @@ -/* - * QNX6 file system, Linux implementation. - * - * Version : 1.0.0 - * - * History : - * - * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release. - * 16-02-2012 pagemap extension by Al Viro - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "qnx6.h" - -static const struct super_operations qnx6_sops; - -static void qnx6_put_super(struct super_block *sb); -static struct inode *qnx6_alloc_inode(struct super_block *sb); -static void qnx6_destroy_inode(struct inode *inode); -static int qnx6_remount(struct super_block *sb, int *flags, char *data); -static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf); -static int qnx6_show_options(struct seq_file *seq, struct dentry *root); - -static const struct super_operations qnx6_sops = { - .alloc_inode = qnx6_alloc_inode, - .destroy_inode = qnx6_destroy_inode, - .put_super = qnx6_put_super, - .statfs = qnx6_statfs, - .remount_fs = qnx6_remount, - .show_options = qnx6_show_options, -}; - -static int qnx6_show_options(struct seq_file *seq, struct dentry *root) -{ - struct super_block *sb = root->d_sb; - struct qnx6_sb_info *sbi = QNX6_SB(sb); - - if (sbi->s_mount_opt & QNX6_MOUNT_MMI_FS) - seq_puts(seq, ",mmi_fs"); - return 0; -} - -static int qnx6_remount(struct super_block *sb, int *flags, char *data) -{ - *flags |= MS_RDONLY; - return 0; -} - -static unsigned qnx6_get_devblock(struct super_block *sb, __fs32 block) -{ - struct qnx6_sb_info *sbi = QNX6_SB(sb); - return fs32_to_cpu(sbi, block) + sbi->s_blks_off; -} - -static unsigned qnx6_block_map(struct inode *inode, unsigned iblock); - -static int qnx6_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int create) -{ - unsigned phys; - - QNX6DEBUG((KERN_INFO "qnx6: qnx6_get_block inode=[%ld] iblock=[%ld]\n", - inode->i_ino, (unsigned long)iblock)); - - phys = qnx6_block_map(inode, iblock); - if (phys) { - /* logical block is before EOF */ - map_bh(bh, inode->i_sb, phys); - } - return 0; -} - -static int qnx6_check_blockptr(__fs32 ptr) -{ - if (ptr == ~(__fs32)0) { - printk(KERN_ERR "qnx6: hit unused blockpointer.\n"); - return 0; - } - return 1; -} - -static int qnx6_readpage(struct file *file, struct page *page) -{ - return mpage_readpage(page, qnx6_get_block); -} - -static int qnx6_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - return mpage_readpages(mapping, pages, nr_pages, qnx6_get_block); -} - -/* - * returns the block number for the no-th element in the tree - * inodebits requred as there are multiple inodes in one inode block - */ -static unsigned qnx6_block_map(struct inode *inode, unsigned no) -{ - struct super_block *s = inode->i_sb; - struct qnx6_sb_info *sbi = QNX6_SB(s); - struct qnx6_inode_info *ei = QNX6_I(inode); - unsigned block = 0; - struct buffer_head *bh; - __fs32 ptr; - int levelptr; - int ptrbits = sbi->s_ptrbits; - int bitdelta; - u32 mask = (1 << ptrbits) - 1; - int depth = ei->di_filelevels; - int i; - - bitdelta = ptrbits * depth; - levelptr = no >> bitdelta; - - if (levelptr > QNX6_NO_DIRECT_POINTERS - 1) { - printk(KERN_ERR "qnx6:Requested file block number (%u) too big.", - no); - return 0; - } - - block = qnx6_get_devblock(s, ei->di_block_ptr[levelptr]); - - for (i = 0; i < depth; i++) { - bh = sb_bread(s, block); - if (!bh) { - printk(KERN_ERR "qnx6:Error reading block (%u)\n", - block); - return 0; - } - bitdelta -= ptrbits; - levelptr = (no >> bitdelta) & mask; - ptr = ((__fs32 *)bh->b_data)[levelptr]; - - if (!qnx6_check_blockptr(ptr)) - return 0; - - block = qnx6_get_devblock(s, ptr); - brelse(bh); - } - return block; -} - -static int qnx6_statfs(struct dentry *dentry, struct kstatfs *buf) -{ - struct super_block *sb = dentry->d_sb; - struct qnx6_sb_info *sbi = QNX6_SB(sb); - u64 id = huge_encode_dev(sb->s_bdev->bd_dev); - - buf->f_type = sb->s_magic; - buf->f_bsize = sb->s_blocksize; - buf->f_blocks = fs32_to_cpu(sbi, sbi->sb->sb_num_blocks); - buf->f_bfree = fs32_to_cpu(sbi, sbi->sb->sb_free_blocks); - buf->f_files = fs32_to_cpu(sbi, sbi->sb->sb_num_inodes); - buf->f_ffree = fs32_to_cpu(sbi, sbi->sb->sb_free_inodes); - buf->f_bavail = buf->f_bfree; - buf->f_namelen = QNX6_LONG_NAME_MAX; - buf->f_fsid.val[0] = (u32)id; - buf->f_fsid.val[1] = (u32)(id >> 32); - - return 0; -} - -/* - * Check the root directory of the filesystem to make sure - * it really _is_ a qnx6 filesystem, and to check the size - * of the directory entry. - */ -static const char *qnx6_checkroot(struct super_block *s) -{ - static char match_root[2][3] = {".\0\0", "..\0"}; - int i, error = 0; - struct qnx6_dir_entry *dir_entry; - struct inode *root = s->s_root->d_inode; - struct address_space *mapping = root->i_mapping; - struct page *page = read_mapping_page(mapping, 0, NULL); - if (IS_ERR(page)) - return "error reading root directory"; - kmap(page); - dir_entry = page_address(page); - for (i = 0; i < 2; i++) { - /* maximum 3 bytes - due to match_root limitation */ - if (strncmp(dir_entry[i].de_fname, match_root[i], 3)) - error = 1; - } - qnx6_put_page(page); - if (error) - return "error reading root directory."; - return NULL; -} - -#ifdef CONFIG_QNX6FS_DEBUG -void qnx6_superblock_debug(struct qnx6_super_block *sb, struct super_block *s) -{ - struct qnx6_sb_info *sbi = QNX6_SB(s); - - QNX6DEBUG((KERN_INFO "magic: %08x\n", - fs32_to_cpu(sbi, sb->sb_magic))); - QNX6DEBUG((KERN_INFO "checksum: %08x\n", - fs32_to_cpu(sbi, sb->sb_checksum))); - QNX6DEBUG((KERN_INFO "serial: %llx\n", - fs64_to_cpu(sbi, sb->sb_serial))); - QNX6DEBUG((KERN_INFO "flags: %08x\n", - fs32_to_cpu(sbi, sb->sb_flags))); - QNX6DEBUG((KERN_INFO "blocksize: %08x\n", - fs32_to_cpu(sbi, sb->sb_blocksize))); - QNX6DEBUG((KERN_INFO "num_inodes: %08x\n", - fs32_to_cpu(sbi, sb->sb_num_inodes))); - QNX6DEBUG((KERN_INFO "free_inodes: %08x\n", - fs32_to_cpu(sbi, sb->sb_free_inodes))); - QNX6DEBUG((KERN_INFO "num_blocks: %08x\n", - fs32_to_cpu(sbi, sb->sb_num_blocks))); - QNX6DEBUG((KERN_INFO "free_blocks: %08x\n", - fs32_to_cpu(sbi, sb->sb_free_blocks))); - QNX6DEBUG((KERN_INFO "inode_levels: %02x\n", - sb->Inode.levels)); -} -#endif - -enum { - Opt_mmifs, - Opt_err -}; - -static const match_table_t tokens = { - {Opt_mmifs, "mmi_fs"}, - {Opt_err, NULL} -}; - -static int qnx6_parse_options(char *options, struct super_block *sb) -{ - char *p; - struct qnx6_sb_info *sbi = QNX6_SB(sb); - substring_t args[MAX_OPT_ARGS]; - - if (!options) - return 1; - - while ((p = strsep(&options, ",")) != NULL) { - int token; - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_mmifs: - set_opt(sbi->s_mount_opt, MMI_FS); - break; - default: - return 0; - } - } - return 1; -} - -static struct buffer_head *qnx6_check_first_superblock(struct super_block *s, - int offset, int silent) -{ - struct qnx6_sb_info *sbi = QNX6_SB(s); - struct buffer_head *bh; - struct qnx6_super_block *sb; - - /* Check the superblock signatures - start with the first superblock */ - bh = sb_bread(s, offset); - if (!bh) { - printk(KERN_ERR "qnx6: unable to read the first superblock\n"); - return NULL; - } - sb = (struct qnx6_super_block *)bh->b_data; - if (fs32_to_cpu(sbi, sb->sb_magic) != QNX6_SUPER_MAGIC) { - sbi->s_bytesex = BYTESEX_BE; - if (fs32_to_cpu(sbi, sb->sb_magic) == QNX6_SUPER_MAGIC) { - /* we got a big endian fs */ - QNX6DEBUG((KERN_INFO "qnx6: fs got different" - " endianess.\n")); - return bh; - } else - sbi->s_bytesex = BYTESEX_LE; - if (!silent) { - if (offset == 0) { - printk(KERN_ERR "qnx6: wrong signature (magic)" - " in superblock #1.\n"); - } else { - printk(KERN_INFO "qnx6: wrong signature (magic)" - " at position (0x%lx) - will try" - " alternative position (0x0000).\n", - offset * s->s_blocksize); - } - } - brelse(bh); - return NULL; - } - return bh; -} - -static struct inode *qnx6_private_inode(struct super_block *s, - struct qnx6_root_node *p); - -static int qnx6_fill_super(struct super_block *s, void *data, int silent) -{ - struct buffer_head *bh1 = NULL, *bh2 = NULL; - struct qnx6_super_block *sb1 = NULL, *sb2 = NULL; - struct qnx6_sb_info *sbi; - struct inode *root; - const char *errmsg; - struct qnx6_sb_info *qs; - int ret = -EINVAL; - u64 offset; - int bootblock_offset = QNX6_BOOTBLOCK_SIZE; - - qs = kzalloc(sizeof(struct qnx6_sb_info), GFP_KERNEL); - if (!qs) - return -ENOMEM; - s->s_fs_info = qs; - - /* Superblock always is 512 Byte long */ - if (!sb_set_blocksize(s, QNX6_SUPERBLOCK_SIZE)) { - printk(KERN_ERR "qnx6: unable to set blocksize\n"); - goto outnobh; - } - - /* parse the mount-options */ - if (!qnx6_parse_options((char *) data, s)) { - printk(KERN_ERR "qnx6: invalid mount options.\n"); - goto outnobh; - } - if (test_opt(s, MMI_FS)) { - sb1 = qnx6_mmi_fill_super(s, silent); - if (sb1) - goto mmi_success; - else - goto outnobh; - } - sbi = QNX6_SB(s); - sbi->s_bytesex = BYTESEX_LE; - /* Check the superblock signatures - start with the first superblock */ - bh1 = qnx6_check_first_superblock(s, - bootblock_offset / QNX6_SUPERBLOCK_SIZE, silent); - if (!bh1) { - /* try again without bootblock offset */ - bh1 = qnx6_check_first_superblock(s, 0, silent); - if (!bh1) { - printk(KERN_ERR "qnx6: unable to read the first superblock\n"); - goto outnobh; - } - /* seems that no bootblock at partition start */ - bootblock_offset = 0; - } - sb1 = (struct qnx6_super_block *)bh1->b_data; - -#ifdef CONFIG_QNX6FS_DEBUG - qnx6_superblock_debug(sb1, s); -#endif - - /* checksum check - start at byte 8 and end at byte 512 */ - if (fs32_to_cpu(sbi, sb1->sb_checksum) != - crc32_be(0, (char *)(bh1->b_data + 8), 504)) { - printk(KERN_ERR "qnx6: superblock #1 checksum error\n"); - goto out; - } - - /* set new blocksize */ - if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) { - printk(KERN_ERR "qnx6: unable to set blocksize\n"); - goto out; - } - /* blocksize invalidates bh - pull it back in */ - brelse(bh1); - bh1 = sb_bread(s, bootblock_offset >> s->s_blocksize_bits); - if (!bh1) - goto outnobh; - sb1 = (struct qnx6_super_block *)bh1->b_data; - - /* calculate second superblock blocknumber */ - offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) + - (bootblock_offset >> s->s_blocksize_bits) + - (QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits); - - /* set bootblock offset */ - sbi->s_blks_off = (bootblock_offset >> s->s_blocksize_bits) + - (QNX6_SUPERBLOCK_AREA >> s->s_blocksize_bits); - - /* next the second superblock */ - bh2 = sb_bread(s, offset); - if (!bh2) { - printk(KERN_ERR "qnx6: unable to read the second superblock\n"); - goto out; - } - sb2 = (struct qnx6_super_block *)bh2->b_data; - if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) { - if (!silent) - printk(KERN_ERR "qnx6: wrong signature (magic)" - " in superblock #2.\n"); - goto out; - } - - /* checksum check - start at byte 8 and end at byte 512 */ - if (fs32_to_cpu(sbi, sb2->sb_checksum) != - crc32_be(0, (char *)(bh2->b_data + 8), 504)) { - printk(KERN_ERR "qnx6: superblock #2 checksum error\n"); - goto out; - } - - if (fs64_to_cpu(sbi, sb1->sb_serial) >= - fs64_to_cpu(sbi, sb2->sb_serial)) { - /* superblock #1 active */ - sbi->sb_buf = bh1; - sbi->sb = (struct qnx6_super_block *)bh1->b_data; - brelse(bh2); - printk(KERN_INFO "qnx6: superblock #1 active\n"); - } else { - /* superblock #2 active */ - sbi->sb_buf = bh2; - sbi->sb = (struct qnx6_super_block *)bh2->b_data; - brelse(bh1); - printk(KERN_INFO "qnx6: superblock #2 active\n"); - } -mmi_success: - /* sanity check - limit maximum indirect pointer levels */ - if (sb1->Inode.levels > QNX6_PTR_MAX_LEVELS) { - printk(KERN_ERR "qnx6: too many inode levels (max %i, sb %i)\n", - QNX6_PTR_MAX_LEVELS, sb1->Inode.levels); - goto out; - } - if (sb1->Longfile.levels > QNX6_PTR_MAX_LEVELS) { - printk(KERN_ERR "qnx6: too many longfilename levels" - " (max %i, sb %i)\n", - QNX6_PTR_MAX_LEVELS, sb1->Longfile.levels); - goto out; - } - s->s_op = &qnx6_sops; - s->s_magic = QNX6_SUPER_MAGIC; - s->s_flags |= MS_RDONLY; /* Yup, read-only yet */ - - /* ease the later tree level calculations */ - sbi = QNX6_SB(s); - sbi->s_ptrbits = ilog2(s->s_blocksize / 4); - sbi->inodes = qnx6_private_inode(s, &sb1->Inode); - if (!sbi->inodes) - goto out; - sbi->longfile = qnx6_private_inode(s, &sb1->Longfile); - if (!sbi->longfile) - goto out1; - - /* prefetch root inode */ - root = qnx6_iget(s, QNX6_ROOT_INO); - if (IS_ERR(root)) { - printk(KERN_ERR "qnx6: get inode failed\n"); - ret = PTR_ERR(root); - goto out2; - } - - ret = -ENOMEM; - s->s_root = d_make_root(root); - if (!s->s_root) - goto out2; - - ret = -EINVAL; - errmsg = qnx6_checkroot(s); - if (errmsg != NULL) { - if (!silent) - printk(KERN_ERR "qnx6: %s\n", errmsg); - goto out3; - } - return 0; - -out3: - dput(s->s_root); - s->s_root = NULL; -out2: - iput(sbi->longfile); -out1: - iput(sbi->inodes); -out: - if (bh1) - brelse(bh1); - if (bh2) - brelse(bh2); -outnobh: - kfree(qs); - s->s_fs_info = NULL; - return ret; -} - -static void qnx6_put_super(struct super_block *sb) -{ - struct qnx6_sb_info *qs = QNX6_SB(sb); - brelse(qs->sb_buf); - iput(qs->longfile); - iput(qs->inodes); - kfree(qs); - sb->s_fs_info = NULL; - return; -} - -static sector_t qnx6_bmap(struct address_space *mapping, sector_t block) -{ - return generic_block_bmap(mapping, block, qnx6_get_block); -} -static const struct address_space_operations qnx6_aops = { - .readpage = qnx6_readpage, - .readpages = qnx6_readpages, - .bmap = qnx6_bmap -}; - -static struct inode *qnx6_private_inode(struct super_block *s, - struct qnx6_root_node *p) -{ - struct inode *inode = new_inode(s); - if (inode) { - struct qnx6_inode_info *ei = QNX6_I(inode); - struct qnx6_sb_info *sbi = QNX6_SB(s); - inode->i_size = fs64_to_cpu(sbi, p->size); - memcpy(ei->di_block_ptr, p->ptr, sizeof(p->ptr)); - ei->di_filelevels = p->levels; - inode->i_mode = S_IFREG | S_IRUSR; /* probably wrong */ - inode->i_mapping->a_ops = &qnx6_aops; - } - return inode; -} - -struct inode *qnx6_iget(struct super_block *sb, unsigned ino) -{ - struct qnx6_sb_info *sbi = QNX6_SB(sb); - struct qnx6_inode_entry *raw_inode; - struct inode *inode; - struct qnx6_inode_info *ei; - struct address_space *mapping; - struct page *page; - u32 n, offs; - - inode = iget_locked(sb, ino); - if (!inode) - return ERR_PTR(-ENOMEM); - if (!(inode->i_state & I_NEW)) - return inode; - - ei = QNX6_I(inode); - - inode->i_mode = 0; - - if (ino == 0) { - printk(KERN_ERR "qnx6: bad inode number on dev %s: %u is " - "out of range\n", - sb->s_id, ino); - iget_failed(inode); - return ERR_PTR(-EIO); - } - n = (ino - 1) >> (PAGE_CACHE_SHIFT - QNX6_INODE_SIZE_BITS); - offs = (ino - 1) & (~PAGE_CACHE_MASK >> QNX6_INODE_SIZE_BITS); - mapping = sbi->inodes->i_mapping; - page = read_mapping_page(mapping, n, NULL); - if (IS_ERR(page)) { - printk(KERN_ERR "qnx6: major problem: unable to read inode from " - "dev %s\n", sb->s_id); - iget_failed(inode); - return ERR_CAST(page); - } - kmap(page); - raw_inode = ((struct qnx6_inode_entry *)page_address(page)) + offs; - - inode->i_mode = fs16_to_cpu(sbi, raw_inode->di_mode); - inode->i_uid = (uid_t)fs32_to_cpu(sbi, raw_inode->di_uid); - inode->i_gid = (gid_t)fs32_to_cpu(sbi, raw_inode->di_gid); - inode->i_size = fs64_to_cpu(sbi, raw_inode->di_size); - inode->i_mtime.tv_sec = fs32_to_cpu(sbi, raw_inode->di_mtime); - inode->i_mtime.tv_nsec = 0; - inode->i_atime.tv_sec = fs32_to_cpu(sbi, raw_inode->di_atime); - inode->i_atime.tv_nsec = 0; - inode->i_ctime.tv_sec = fs32_to_cpu(sbi, raw_inode->di_ctime); - inode->i_ctime.tv_nsec = 0; - - /* calc blocks based on 512 byte blocksize */ - inode->i_blocks = (inode->i_size + 511) >> 9; - - memcpy(&ei->di_block_ptr, &raw_inode->di_block_ptr, - sizeof(raw_inode->di_block_ptr)); - ei->di_filelevels = raw_inode->di_filelevels; - - if (S_ISREG(inode->i_mode)) { - inode->i_fop = &generic_ro_fops; - inode->i_mapping->a_ops = &qnx6_aops; - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &qnx6_dir_inode_operations; - inode->i_fop = &qnx6_dir_operations; - inode->i_mapping->a_ops = &qnx6_aops; - } else if (S_ISLNK(inode->i_mode)) { - inode->i_op = &page_symlink_inode_operations; - inode->i_mapping->a_ops = &qnx6_aops; - } else - init_special_inode(inode, inode->i_mode, 0); - qnx6_put_page(page); - unlock_new_inode(inode); - return inode; -} - -static struct kmem_cache *qnx6_inode_cachep; - -static struct inode *qnx6_alloc_inode(struct super_block *sb) -{ - struct qnx6_inode_info *ei; - ei = kmem_cache_alloc(qnx6_inode_cachep, GFP_KERNEL); - if (!ei) - return NULL; - return &ei->vfs_inode; -} - -static void qnx6_i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - INIT_LIST_HEAD(&inode->i_dentry); - kmem_cache_free(qnx6_inode_cachep, QNX6_I(inode)); -} - -static void qnx6_destroy_inode(struct inode *inode) -{ - call_rcu(&inode->i_rcu, qnx6_i_callback); -} - -static void init_once(void *foo) -{ - struct qnx6_inode_info *ei = (struct qnx6_inode_info *) foo; - - inode_init_once(&ei->vfs_inode); -} - -static int init_inodecache(void) -{ - qnx6_inode_cachep = kmem_cache_create("qnx6_inode_cache", - sizeof(struct qnx6_inode_info), - 0, (SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD), - init_once); - if (!qnx6_inode_cachep) - return -ENOMEM; - return 0; -} - -static void destroy_inodecache(void) -{ - kmem_cache_destroy(qnx6_inode_cachep); -} - -static struct dentry *qnx6_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_bdev(fs_type, flags, dev_name, data, qnx6_fill_super); -} - -static struct file_system_type qnx6_fs_type = { - .owner = THIS_MODULE, - .name = "qnx6", - .mount = qnx6_mount, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; - -static int __init init_qnx6_fs(void) -{ - int err; - - err = init_inodecache(); - if (err) - return err; - - err = register_filesystem(&qnx6_fs_type); - if (err) { - destroy_inodecache(); - return err; - } - - printk(KERN_INFO "QNX6 filesystem 1.0.0 registered.\n"); - return 0; -} - -static void __exit exit_qnx6_fs(void) -{ - unregister_filesystem(&qnx6_fs_type); - destroy_inodecache(); -} - -module_init(init_qnx6_fs) -module_exit(exit_qnx6_fs) -MODULE_LICENSE("GPL"); diff --git a/trunk/fs/qnx6/namei.c b/trunk/fs/qnx6/namei.c deleted file mode 100644 index 8a97289e04ad..000000000000 --- a/trunk/fs/qnx6/namei.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * QNX6 file system, Linux implementation. - * - * Version : 1.0.0 - * - * History : - * - * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release. - * 16-02-2012 pagemap extension by Al Viro - * - */ - -#include "qnx6.h" - -struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *nd) -{ - unsigned ino; - struct page *page; - struct inode *foundinode = NULL; - const char *name = dentry->d_name.name; - int len = dentry->d_name.len; - - if (len > QNX6_LONG_NAME_MAX) - return ERR_PTR(-ENAMETOOLONG); - - ino = qnx6_find_entry(len, dir, name, &page); - if (ino) { - foundinode = qnx6_iget(dir->i_sb, ino); - qnx6_put_page(page); - if (IS_ERR(foundinode)) { - QNX6DEBUG((KERN_ERR "qnx6: lookup->iget -> " - " error %ld\n", PTR_ERR(foundinode))); - return ERR_CAST(foundinode); - } - } else { - QNX6DEBUG((KERN_INFO "qnx6_lookup: not found %s\n", name)); - return NULL; - } - d_add(dentry, foundinode); - return NULL; -} diff --git a/trunk/fs/qnx6/qnx6.h b/trunk/fs/qnx6/qnx6.h deleted file mode 100644 index 6c5e02a0b6a8..000000000000 --- a/trunk/fs/qnx6/qnx6.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * QNX6 file system, Linux implementation. - * - * Version : 1.0.0 - * - * History : - * - * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release. - * 16-02-2012 page map extension by Al Viro - * - */ - -#include -#include - -typedef __u16 __bitwise __fs16; -typedef __u32 __bitwise __fs32; -typedef __u64 __bitwise __fs64; - -#include - -#ifdef CONFIG_QNX6FS_DEBUG -#define QNX6DEBUG(X) printk X -#else -#define QNX6DEBUG(X) (void) 0 -#endif - -struct qnx6_sb_info { - struct buffer_head *sb_buf; /* superblock buffer */ - struct qnx6_super_block *sb; /* our superblock */ - int s_blks_off; /* blkoffset fs-startpoint */ - int s_ptrbits; /* indirect pointer bitfield */ - unsigned long s_mount_opt; /* all mount options */ - int s_bytesex; /* holds endianess info */ - struct inode * inodes; - struct inode * longfile; -}; - -struct qnx6_inode_info { - __fs32 di_block_ptr[QNX6_NO_DIRECT_POINTERS]; - __u8 di_filelevels; - __u32 i_dir_start_lookup; - struct inode vfs_inode; -}; - -extern struct inode *qnx6_iget(struct super_block *sb, unsigned ino); -extern struct dentry *qnx6_lookup(struct inode *dir, struct dentry *dentry, - struct nameidata *nd); - -#ifdef CONFIG_QNX6FS_DEBUG -extern void qnx6_superblock_debug(struct qnx6_super_block *, - struct super_block *); -#endif - -extern const struct inode_operations qnx6_dir_inode_operations; -extern const struct file_operations qnx6_dir_operations; - -static inline struct qnx6_sb_info *QNX6_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -static inline struct qnx6_inode_info *QNX6_I(struct inode *inode) -{ - return container_of(inode, struct qnx6_inode_info, vfs_inode); -} - -#define clear_opt(o, opt) (o &= ~(QNX6_MOUNT_##opt)) -#define set_opt(o, opt) (o |= (QNX6_MOUNT_##opt)) -#define test_opt(sb, opt) (QNX6_SB(sb)->s_mount_opt & \ - QNX6_MOUNT_##opt) -enum { - BYTESEX_LE, - BYTESEX_BE, -}; - -static inline __u64 fs64_to_cpu(struct qnx6_sb_info *sbi, __fs64 n) -{ - if (sbi->s_bytesex == BYTESEX_LE) - return le64_to_cpu((__force __le64)n); - else - return be64_to_cpu((__force __be64)n); -} - -static inline __fs64 cpu_to_fs64(struct qnx6_sb_info *sbi, __u64 n) -{ - if (sbi->s_bytesex == BYTESEX_LE) - return (__force __fs64)cpu_to_le64(n); - else - return (__force __fs64)cpu_to_be64(n); -} - -static inline __u32 fs32_to_cpu(struct qnx6_sb_info *sbi, __fs32 n) -{ - if (sbi->s_bytesex == BYTESEX_LE) - return le32_to_cpu((__force __le32)n); - else - return be32_to_cpu((__force __be32)n); -} - -static inline __fs32 cpu_to_fs32(struct qnx6_sb_info *sbi, __u32 n) -{ - if (sbi->s_bytesex == BYTESEX_LE) - return (__force __fs32)cpu_to_le32(n); - else - return (__force __fs32)cpu_to_be32(n); -} - -static inline __u16 fs16_to_cpu(struct qnx6_sb_info *sbi, __fs16 n) -{ - if (sbi->s_bytesex == BYTESEX_LE) - return le16_to_cpu((__force __le16)n); - else - return be16_to_cpu((__force __be16)n); -} - -static inline __fs16 cpu_to_fs16(struct qnx6_sb_info *sbi, __u16 n) -{ - if (sbi->s_bytesex == BYTESEX_LE) - return (__force __fs16)cpu_to_le16(n); - else - return (__force __fs16)cpu_to_be16(n); -} - -extern struct qnx6_super_block *qnx6_mmi_fill_super(struct super_block *s, - int silent); - -static inline void qnx6_put_page(struct page *page) -{ - kunmap(page); - page_cache_release(page); -} - -extern unsigned qnx6_find_entry(int len, struct inode *dir, const char *name, - struct page **res_page); diff --git a/trunk/fs/qnx6/super_mmi.c b/trunk/fs/qnx6/super_mmi.c deleted file mode 100644 index 29c32cba62d6..000000000000 --- a/trunk/fs/qnx6/super_mmi.c +++ /dev/null @@ -1,150 +0,0 @@ -/* - * QNX6 file system, Linux implementation. - * - * Version : 1.0.0 - * - * History : - * - * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release. - * - */ - -#include -#include -#include -#include "qnx6.h" - -static void qnx6_mmi_copy_sb(struct qnx6_super_block *qsb, - struct qnx6_mmi_super_block *sb) -{ - qsb->sb_magic = sb->sb_magic; - qsb->sb_checksum = sb->sb_checksum; - qsb->sb_serial = sb->sb_serial; - qsb->sb_blocksize = sb->sb_blocksize; - qsb->sb_num_inodes = sb->sb_num_inodes; - qsb->sb_free_inodes = sb->sb_free_inodes; - qsb->sb_num_blocks = sb->sb_num_blocks; - qsb->sb_free_blocks = sb->sb_free_blocks; - - /* the rest of the superblock is the same */ - memcpy(&qsb->Inode, &sb->Inode, sizeof(sb->Inode)); - memcpy(&qsb->Bitmap, &sb->Bitmap, sizeof(sb->Bitmap)); - memcpy(&qsb->Longfile, &sb->Longfile, sizeof(sb->Longfile)); -} - -struct qnx6_super_block *qnx6_mmi_fill_super(struct super_block *s, int silent) -{ - struct buffer_head *bh1, *bh2 = NULL; - struct qnx6_mmi_super_block *sb1, *sb2; - struct qnx6_super_block *qsb = NULL; - struct qnx6_sb_info *sbi; - __u64 offset; - - /* Check the superblock signatures - start with the first superblock */ - bh1 = sb_bread(s, 0); - if (!bh1) { - printk(KERN_ERR "qnx6: Unable to read first mmi superblock\n"); - return NULL; - } - sb1 = (struct qnx6_mmi_super_block *)bh1->b_data; - sbi = QNX6_SB(s); - if (fs32_to_cpu(sbi, sb1->sb_magic) != QNX6_SUPER_MAGIC) { - if (!silent) { - printk(KERN_ERR "qnx6: wrong signature (magic) in" - " superblock #1.\n"); - goto out; - } - } - - /* checksum check - start at byte 8 and end at byte 512 */ - if (fs32_to_cpu(sbi, sb1->sb_checksum) != - crc32_be(0, (char *)(bh1->b_data + 8), 504)) { - printk(KERN_ERR "qnx6: superblock #1 checksum error\n"); - goto out; - } - - /* calculate second superblock blocknumber */ - offset = fs32_to_cpu(sbi, sb1->sb_num_blocks) + QNX6_SUPERBLOCK_AREA / - fs32_to_cpu(sbi, sb1->sb_blocksize); - - /* set new blocksize */ - if (!sb_set_blocksize(s, fs32_to_cpu(sbi, sb1->sb_blocksize))) { - printk(KERN_ERR "qnx6: unable to set blocksize\n"); - goto out; - } - /* blocksize invalidates bh - pull it back in */ - brelse(bh1); - bh1 = sb_bread(s, 0); - if (!bh1) - goto out; - sb1 = (struct qnx6_mmi_super_block *)bh1->b_data; - - /* read second superblock */ - bh2 = sb_bread(s, offset); - if (!bh2) { - printk(KERN_ERR "qnx6: unable to read the second superblock\n"); - goto out; - } - sb2 = (struct qnx6_mmi_super_block *)bh2->b_data; - if (fs32_to_cpu(sbi, sb2->sb_magic) != QNX6_SUPER_MAGIC) { - if (!silent) - printk(KERN_ERR "qnx6: wrong signature (magic) in" - " superblock #2.\n"); - goto out; - } - - /* checksum check - start at byte 8 and end at byte 512 */ - if (fs32_to_cpu(sbi, sb2->sb_checksum) - != crc32_be(0, (char *)(bh2->b_data + 8), 504)) { - printk(KERN_ERR "qnx6: superblock #1 checksum error\n"); - goto out; - } - - qsb = kmalloc(sizeof(*qsb), GFP_KERNEL); - if (!qsb) { - printk(KERN_ERR "qnx6: unable to allocate memory.\n"); - goto out; - } - - if (fs64_to_cpu(sbi, sb1->sb_serial) > - fs64_to_cpu(sbi, sb2->sb_serial)) { - /* superblock #1 active */ - qnx6_mmi_copy_sb(qsb, sb1); -#ifdef CONFIG_QNX6FS_DEBUG - qnx6_superblock_debug(qsb, s); -#endif - memcpy(bh1->b_data, qsb, sizeof(struct qnx6_super_block)); - - sbi->sb_buf = bh1; - sbi->sb = (struct qnx6_super_block *)bh1->b_data; - brelse(bh2); - printk(KERN_INFO "qnx6: superblock #1 active\n"); - } else { - /* superblock #2 active */ - qnx6_mmi_copy_sb(qsb, sb2); -#ifdef CONFIG_QNX6FS_DEBUG - qnx6_superblock_debug(qsb, s); -#endif - memcpy(bh2->b_data, qsb, sizeof(struct qnx6_super_block)); - - sbi->sb_buf = bh2; - sbi->sb = (struct qnx6_super_block *)bh2->b_data; - brelse(bh1); - printk(KERN_INFO "qnx6: superblock #2 active\n"); - } - kfree(qsb); - - /* offset for mmi_fs is just SUPERBLOCK_AREA bytes */ - sbi->s_blks_off = QNX6_SUPERBLOCK_AREA / s->s_blocksize; - - /* success */ - return sbi->sb; - -out: - if (bh1 != NULL) - brelse(bh1); - if (bh2 != NULL) - brelse(bh2); - return NULL; -} diff --git a/trunk/fs/quota/dquot.c b/trunk/fs/quota/dquot.c index 8b4f12b33f57..46741970371b 100644 --- a/trunk/fs/quota/dquot.c +++ b/trunk/fs/quota/dquot.c @@ -71,7 +71,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/fs/ramfs/inode.c b/trunk/fs/ramfs/inode.c index a1fdabe21dec..aec766abe3af 100644 --- a/trunk/fs/ramfs/inode.c +++ b/trunk/fs/ramfs/inode.c @@ -209,19 +209,22 @@ static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts) int ramfs_fill_super(struct super_block *sb, void *data, int silent) { struct ramfs_fs_info *fsi; - struct inode *inode; + struct inode *inode = NULL; + struct dentry *root; int err; save_mount_options(sb, data); fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL); sb->s_fs_info = fsi; - if (!fsi) - return -ENOMEM; + if (!fsi) { + err = -ENOMEM; + goto fail; + } err = ramfs_parse_options(data, &fsi->mount_opts); if (err) - return err; + goto fail; sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = PAGE_CACHE_SIZE; @@ -231,11 +234,24 @@ int ramfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran = 1; inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0); - sb->s_root = d_make_root(inode); - if (!sb->s_root) - return -ENOMEM; + if (!inode) { + err = -ENOMEM; + goto fail; + } + + root = d_alloc_root(inode); + sb->s_root = root; + if (!root) { + err = -ENOMEM; + goto fail; + } return 0; +fail: + kfree(fsi); + sb->s_fs_info = NULL; + iput(inode); + return err; } struct dentry *ramfs_mount(struct file_system_type *fs_type, diff --git a/trunk/fs/reiserfs/bitmap.c b/trunk/fs/reiserfs/bitmap.c index 4c0c7d163d15..70de42f09f1d 100644 --- a/trunk/fs/reiserfs/bitmap.c +++ b/trunk/fs/reiserfs/bitmap.c @@ -4,12 +4,14 @@ /* Reiserfs block (de)allocator, bitmap-based. */ #include -#include "reiserfs.h" +#include #include #include #include #include #include +#include +#include #include #include diff --git a/trunk/fs/reiserfs/dir.c b/trunk/fs/reiserfs/dir.c index 66c53b642a88..133e9355dc6f 100644 --- a/trunk/fs/reiserfs/dir.c +++ b/trunk/fs/reiserfs/dir.c @@ -5,7 +5,7 @@ #include #include #include -#include "reiserfs.h" +#include #include #include #include diff --git a/trunk/fs/reiserfs/do_balan.c b/trunk/fs/reiserfs/do_balan.c index 2b7882b508db..60c080440661 100644 --- a/trunk/fs/reiserfs/do_balan.c +++ b/trunk/fs/reiserfs/do_balan.c @@ -17,7 +17,7 @@ #include #include -#include "reiserfs.h" +#include #include #include diff --git a/trunk/fs/reiserfs/file.c b/trunk/fs/reiserfs/file.c index 8375c922c0d5..ace635053a36 100644 --- a/trunk/fs/reiserfs/file.c +++ b/trunk/fs/reiserfs/file.c @@ -3,9 +3,9 @@ */ #include -#include "reiserfs.h" -#include "acl.h" -#include "xattr.h" +#include +#include +#include #include #include #include diff --git a/trunk/fs/reiserfs/fix_node.c b/trunk/fs/reiserfs/fix_node.c index 430e0658704c..1e4250bc3a6f 100644 --- a/trunk/fs/reiserfs/fix_node.c +++ b/trunk/fs/reiserfs/fix_node.c @@ -37,7 +37,7 @@ #include #include #include -#include "reiserfs.h" +#include #include /* To make any changes in the tree we find a node, that contains item diff --git a/trunk/fs/reiserfs/hashes.c b/trunk/fs/reiserfs/hashes.c index 91b0cc1242a2..6471c670743e 100644 --- a/trunk/fs/reiserfs/hashes.c +++ b/trunk/fs/reiserfs/hashes.c @@ -19,7 +19,7 @@ // #include -#include "reiserfs.h" +#include #include #define DELTA 0x9E3779B9 diff --git a/trunk/fs/reiserfs/ibalance.c b/trunk/fs/reiserfs/ibalance.c index e1978fd895f5..2074fd95046b 100644 --- a/trunk/fs/reiserfs/ibalance.c +++ b/trunk/fs/reiserfs/ibalance.c @@ -5,7 +5,7 @@ #include #include #include -#include "reiserfs.h" +#include #include /* this is one and only function that is used outside (do_balance.c) */ diff --git a/trunk/fs/reiserfs/inode.c b/trunk/fs/reiserfs/inode.c index 494c315c7417..9e8cd5acd79c 100644 --- a/trunk/fs/reiserfs/inode.c +++ b/trunk/fs/reiserfs/inode.c @@ -4,9 +4,9 @@ #include #include -#include "reiserfs.h" -#include "acl.h" -#include "xattr.h" +#include +#include +#include #include #include #include diff --git a/trunk/fs/reiserfs/ioctl.c b/trunk/fs/reiserfs/ioctl.c index 0c2185042d5f..950e3d1b5c9e 100644 --- a/trunk/fs/reiserfs/ioctl.c +++ b/trunk/fs/reiserfs/ioctl.c @@ -5,7 +5,7 @@ #include #include #include -#include "reiserfs.h" +#include #include #include #include diff --git a/trunk/fs/reiserfs/item_ops.c b/trunk/fs/reiserfs/item_ops.c index ee382ef3d300..72cb1cc51b87 100644 --- a/trunk/fs/reiserfs/item_ops.c +++ b/trunk/fs/reiserfs/item_ops.c @@ -3,7 +3,7 @@ */ #include -#include "reiserfs.h" +#include // this contains item handlers for old item types: sd, direct, // indirect, directory diff --git a/trunk/fs/reiserfs/journal.c b/trunk/fs/reiserfs/journal.c index cf9f4de00a95..c3cf54fd4de3 100644 --- a/trunk/fs/reiserfs/journal.c +++ b/trunk/fs/reiserfs/journal.c @@ -37,7 +37,7 @@ #include #include #include -#include "reiserfs.h" +#include #include #include #include diff --git a/trunk/fs/reiserfs/lbalance.c b/trunk/fs/reiserfs/lbalance.c index 79e5a8b4c226..b43d01556313 100644 --- a/trunk/fs/reiserfs/lbalance.c +++ b/trunk/fs/reiserfs/lbalance.c @@ -5,7 +5,7 @@ #include #include #include -#include "reiserfs.h" +#include #include /* these are used in do_balance.c */ diff --git a/trunk/fs/reiserfs/lock.c b/trunk/fs/reiserfs/lock.c index d735bc8470e3..7df1ce48203a 100644 --- a/trunk/fs/reiserfs/lock.c +++ b/trunk/fs/reiserfs/lock.c @@ -1,4 +1,4 @@ -#include "reiserfs.h" +#include #include /* diff --git a/trunk/fs/reiserfs/namei.c b/trunk/fs/reiserfs/namei.c index 84e8a69cee9d..146378865239 100644 --- a/trunk/fs/reiserfs/namei.c +++ b/trunk/fs/reiserfs/namei.c @@ -14,9 +14,9 @@ #include #include #include -#include "reiserfs.h" -#include "acl.h" -#include "xattr.h" +#include +#include +#include #include #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) set_nlink(i, 1); } diff --git a/trunk/fs/reiserfs/objectid.c b/trunk/fs/reiserfs/objectid.c index f732d6a5251d..3a6de810bd61 100644 --- a/trunk/fs/reiserfs/objectid.c +++ b/trunk/fs/reiserfs/objectid.c @@ -5,7 +5,8 @@ #include #include #include -#include "reiserfs.h" +#include +#include // find where objectid map starts #define objectid_map(s,rs) (old_format_only (s) ? \ diff --git a/trunk/fs/reiserfs/prints.c b/trunk/fs/reiserfs/prints.c index c0b1112ab7e3..45de98b59466 100644 --- a/trunk/fs/reiserfs/prints.c +++ b/trunk/fs/reiserfs/prints.c @@ -4,7 +4,7 @@ #include #include -#include "reiserfs.h" +#include #include #include @@ -329,7 +329,7 @@ void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...) Numbering scheme for panic used by Vladimir and Anatoly( Hans completely ignores this scheme, and considers it pointless complexity): - panics in reiserfs.h have numbers from 1000 to 1999 + panics in reiserfs_fs.h have numbers from 1000 to 1999 super.c 2000 to 2999 preserve.c (unused) 3000 to 3999 bitmap.c 4000 to 4999 diff --git a/trunk/fs/reiserfs/procfs.c b/trunk/fs/reiserfs/procfs.c index 2c1ade692cc8..7a9981196c1c 100644 --- a/trunk/fs/reiserfs/procfs.c +++ b/trunk/fs/reiserfs/procfs.c @@ -12,7 +12,8 @@ #include #include #include -#include "reiserfs.h" +#include +#include #include #include diff --git a/trunk/fs/reiserfs/reiserfs.h b/trunk/fs/reiserfs/reiserfs.h deleted file mode 100644 index 445d768eea44..000000000000 --- a/trunk/fs/reiserfs/reiserfs.h +++ /dev/null @@ -1,2922 +0,0 @@ -/* - * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* the 32 bit compat definitions with int argument */ -#define REISERFS_IOC32_UNPACK _IOW(0xCD, 1, int) -#define REISERFS_IOC32_GETFLAGS FS_IOC32_GETFLAGS -#define REISERFS_IOC32_SETFLAGS FS_IOC32_SETFLAGS -#define REISERFS_IOC32_GETVERSION FS_IOC32_GETVERSION -#define REISERFS_IOC32_SETVERSION FS_IOC32_SETVERSION - -struct reiserfs_journal_list; - -/** bitmasks for i_flags field in reiserfs-specific part of inode */ -typedef enum { - /** this says what format of key do all items (but stat data) of - an object have. If this is set, that format is 3.6 otherwise - - 3.5 */ - i_item_key_version_mask = 0x0001, - /** If this is unset, object has 3.5 stat data, otherwise, it has - 3.6 stat data with 64bit size, 32bit nlink etc. */ - i_stat_data_version_mask = 0x0002, - /** file might need tail packing on close */ - i_pack_on_close_mask = 0x0004, - /** don't pack tail of file */ - i_nopack_mask = 0x0008, - /** If those is set, "safe link" was created for this file during - truncate or unlink. Safe link is used to avoid leakage of disk - space on crash with some files open, but unlinked. */ - i_link_saved_unlink_mask = 0x0010, - i_link_saved_truncate_mask = 0x0020, - i_has_xattr_dir = 0x0040, - i_data_log = 0x0080, -} reiserfs_inode_flags; - -struct reiserfs_inode_info { - __u32 i_key[4]; /* key is still 4 32 bit integers */ - /** transient inode flags that are never stored on disk. Bitmasks - for this field are defined above. */ - __u32 i_flags; - - __u32 i_first_direct_byte; // offset of first byte stored in direct item. - - /* copy of persistent inode flags read from sd_attrs. */ - __u32 i_attrs; - - int i_prealloc_block; /* first unused block of a sequence of unused blocks */ - int i_prealloc_count; /* length of that sequence */ - struct list_head i_prealloc_list; /* per-transaction list of inodes which - * have preallocated blocks */ - - unsigned new_packing_locality:1; /* new_packig_locality is created; new blocks - * for the contents of this directory should be - * displaced */ - - /* we use these for fsync or O_SYNC to decide which transaction - ** needs to be committed in order for this inode to be properly - ** flushed */ - unsigned int i_trans_id; - struct reiserfs_journal_list *i_jl; - atomic_t openers; - struct mutex tailpack; -#ifdef CONFIG_REISERFS_FS_XATTR - struct rw_semaphore i_xattr_sem; -#endif - struct inode vfs_inode; -}; - -typedef enum { - reiserfs_attrs_cleared = 0x00000001, -} reiserfs_super_block_flags; - -/* struct reiserfs_super_block accessors/mutators - * since this is a disk structure, it will always be in - * little endian format. */ -#define sb_block_count(sbp) (le32_to_cpu((sbp)->s_v1.s_block_count)) -#define set_sb_block_count(sbp,v) ((sbp)->s_v1.s_block_count = cpu_to_le32(v)) -#define sb_free_blocks(sbp) (le32_to_cpu((sbp)->s_v1.s_free_blocks)) -#define set_sb_free_blocks(sbp,v) ((sbp)->s_v1.s_free_blocks = cpu_to_le32(v)) -#define sb_root_block(sbp) (le32_to_cpu((sbp)->s_v1.s_root_block)) -#define set_sb_root_block(sbp,v) ((sbp)->s_v1.s_root_block = cpu_to_le32(v)) - -#define sb_jp_journal_1st_block(sbp) \ - (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_1st_block)) -#define set_sb_jp_journal_1st_block(sbp,v) \ - ((sbp)->s_v1.s_journal.jp_journal_1st_block = cpu_to_le32(v)) -#define sb_jp_journal_dev(sbp) \ - (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_dev)) -#define set_sb_jp_journal_dev(sbp,v) \ - ((sbp)->s_v1.s_journal.jp_journal_dev = cpu_to_le32(v)) -#define sb_jp_journal_size(sbp) \ - (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_size)) -#define set_sb_jp_journal_size(sbp,v) \ - ((sbp)->s_v1.s_journal.jp_journal_size = cpu_to_le32(v)) -#define sb_jp_journal_trans_max(sbp) \ - (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_trans_max)) -#define set_sb_jp_journal_trans_max(sbp,v) \ - ((sbp)->s_v1.s_journal.jp_journal_trans_max = cpu_to_le32(v)) -#define sb_jp_journal_magic(sbp) \ - (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_magic)) -#define set_sb_jp_journal_magic(sbp,v) \ - ((sbp)->s_v1.s_journal.jp_journal_magic = cpu_to_le32(v)) -#define sb_jp_journal_max_batch(sbp) \ - (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_batch)) -#define set_sb_jp_journal_max_batch(sbp,v) \ - ((sbp)->s_v1.s_journal.jp_journal_max_batch = cpu_to_le32(v)) -#define sb_jp_jourmal_max_commit_age(sbp) \ - (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_commit_age)) -#define set_sb_jp_journal_max_commit_age(sbp,v) \ - ((sbp)->s_v1.s_journal.jp_journal_max_commit_age = cpu_to_le32(v)) - -#define sb_blocksize(sbp) (le16_to_cpu((sbp)->s_v1.s_blocksize)) -#define set_sb_blocksize(sbp,v) ((sbp)->s_v1.s_blocksize = cpu_to_le16(v)) -#define sb_oid_maxsize(sbp) (le16_to_cpu((sbp)->s_v1.s_oid_maxsize)) -#define set_sb_oid_maxsize(sbp,v) ((sbp)->s_v1.s_oid_maxsize = cpu_to_le16(v)) -#define sb_oid_cursize(sbp) (le16_to_cpu((sbp)->s_v1.s_oid_cursize)) -#define set_sb_oid_cursize(sbp,v) ((sbp)->s_v1.s_oid_cursize = cpu_to_le16(v)) -#define sb_umount_state(sbp) (le16_to_cpu((sbp)->s_v1.s_umount_state)) -#define set_sb_umount_state(sbp,v) ((sbp)->s_v1.s_umount_state = cpu_to_le16(v)) -#define sb_fs_state(sbp) (le16_to_cpu((sbp)->s_v1.s_fs_state)) -#define set_sb_fs_state(sbp,v) ((sbp)->s_v1.s_fs_state = cpu_to_le16(v)) -#define sb_hash_function_code(sbp) \ - (le32_to_cpu((sbp)->s_v1.s_hash_function_code)) -#define set_sb_hash_function_code(sbp,v) \ - ((sbp)->s_v1.s_hash_function_code = cpu_to_le32(v)) -#define sb_tree_height(sbp) (le16_to_cpu((sbp)->s_v1.s_tree_height)) -#define set_sb_tree_height(sbp,v) ((sbp)->s_v1.s_tree_height = cpu_to_le16(v)) -#define sb_bmap_nr(sbp) (le16_to_cpu((sbp)->s_v1.s_bmap_nr)) -#define set_sb_bmap_nr(sbp,v) ((sbp)->s_v1.s_bmap_nr = cpu_to_le16(v)) -#define sb_version(sbp) (le16_to_cpu((sbp)->s_v1.s_version)) -#define set_sb_version(sbp,v) ((sbp)->s_v1.s_version = cpu_to_le16(v)) - -#define sb_mnt_count(sbp) (le16_to_cpu((sbp)->s_mnt_count)) -#define set_sb_mnt_count(sbp, v) ((sbp)->s_mnt_count = cpu_to_le16(v)) - -#define sb_reserved_for_journal(sbp) \ - (le16_to_cpu((sbp)->s_v1.s_reserved_for_journal)) -#define set_sb_reserved_for_journal(sbp,v) \ - ((sbp)->s_v1.s_reserved_for_journal = cpu_to_le16(v)) - -/* LOGGING -- */ - -/* These all interelate for performance. -** -** If the journal block count is smaller than n transactions, you lose speed. -** I don't know what n is yet, I'm guessing 8-16. -** -** typical transaction size depends on the application, how often fsync is -** called, and how many metadata blocks you dirty in a 30 second period. -** The more small files (<16k) you use, the larger your transactions will -** be. -** -** If your journal fills faster than dirty buffers get flushed to disk, it must flush them before allowing the journal -** to wrap, which slows things down. If you need high speed meta data updates, the journal should be big enough -** to prevent wrapping before dirty meta blocks get to disk. -** -** If the batch max is smaller than the transaction max, you'll waste space at the end of the journal -** because journal_end sets the next transaction to start at 0 if the next transaction has any chance of wrapping. -** -** The large the batch max age, the better the speed, and the more meta data changes you'll lose after a crash. -** -*/ - -/* don't mess with these for a while */ - /* we have a node size define somewhere in reiserfs_fs.h. -Hans */ -#define JOURNAL_BLOCK_SIZE 4096 /* BUG gotta get rid of this */ -#define JOURNAL_MAX_CNODE 1500 /* max cnodes to allocate. */ -#define JOURNAL_HASH_SIZE 8192 -#define JOURNAL_NUM_BITMAPS 5 /* number of copies of the bitmaps to have floating. Must be >= 2 */ - -/* One of these for every block in every transaction -** Each one is in two hash tables. First, a hash of the current transaction, and after journal_end, a -** hash of all the in memory transactions. -** next and prev are used by the current transaction (journal_hash). -** hnext and hprev are used by journal_list_hash. If a block is in more than one transaction, the journal_list_hash -** links it in multiple times. This allows flush_journal_list to remove just the cnode belonging -** to a given transaction. -*/ -struct reiserfs_journal_cnode { - struct buffer_head *bh; /* real buffer head */ - struct super_block *sb; /* dev of real buffer head */ - __u32 blocknr; /* block number of real buffer head, == 0 when buffer on disk */ - unsigned long state; - struct reiserfs_journal_list *jlist; /* journal list this cnode lives in */ - struct reiserfs_journal_cnode *next; /* next in transaction list */ - struct reiserfs_journal_cnode *prev; /* prev in transaction list */ - struct reiserfs_journal_cnode *hprev; /* prev in hash list */ - struct reiserfs_journal_cnode *hnext; /* next in hash list */ -}; - -struct reiserfs_bitmap_node { - int id; - char *data; - struct list_head list; -}; - -struct reiserfs_list_bitmap { - struct reiserfs_journal_list *journal_list; - struct reiserfs_bitmap_node **bitmaps; -}; - -/* -** one of these for each transaction. The most important part here is the j_realblock. -** this list of cnodes is used to hash all the blocks in all the commits, to mark all the -** real buffer heads dirty once all the commits hit the disk, -** and to make sure every real block in a transaction is on disk before allowing the log area -** to be overwritten */ -struct reiserfs_journal_list { - unsigned long j_start; - unsigned long j_state; - unsigned long j_len; - atomic_t j_nonzerolen; - atomic_t j_commit_left; - atomic_t j_older_commits_done; /* all commits older than this on disk */ - struct mutex j_commit_mutex; - unsigned int j_trans_id; - time_t j_timestamp; - struct reiserfs_list_bitmap *j_list_bitmap; - struct buffer_head *j_commit_bh; /* commit buffer head */ - struct reiserfs_journal_cnode *j_realblock; - struct reiserfs_journal_cnode *j_freedlist; /* list of buffers that were freed during this trans. free each of these on flush */ - /* time ordered list of all active transactions */ - struct list_head j_list; - - /* time ordered list of all transactions we haven't tried to flush yet */ - struct list_head j_working_list; - - /* list of tail conversion targets in need of flush before commit */ - struct list_head j_tail_bh_list; - /* list of data=ordered buffers in need of flush before commit */ - struct list_head j_bh_list; - int j_refcount; -}; - -struct reiserfs_journal { - struct buffer_head **j_ap_blocks; /* journal blocks on disk */ - struct reiserfs_journal_cnode *j_last; /* newest journal block */ - struct reiserfs_journal_cnode *j_first; /* oldest journal block. start here for traverse */ - - struct block_device *j_dev_bd; - fmode_t j_dev_mode; - int j_1st_reserved_block; /* first block on s_dev of reserved area journal */ - - unsigned long j_state; - unsigned int j_trans_id; - unsigned long j_mount_id; - unsigned long j_start; /* start of current waiting commit (index into j_ap_blocks) */ - unsigned long j_len; /* length of current waiting commit */ - unsigned long j_len_alloc; /* number of buffers requested by journal_begin() */ - atomic_t j_wcount; /* count of writers for current commit */ - unsigned long j_bcount; /* batch count. allows turning X transactions into 1 */ - unsigned long j_first_unflushed_offset; /* first unflushed transactions offset */ - unsigned j_last_flush_trans_id; /* last fully flushed journal timestamp */ - struct buffer_head *j_header_bh; - - time_t j_trans_start_time; /* time this transaction started */ - struct mutex j_mutex; - struct mutex j_flush_mutex; - wait_queue_head_t j_join_wait; /* wait for current transaction to finish before starting new one */ - atomic_t j_jlock; /* lock for j_join_wait */ - int j_list_bitmap_index; /* number of next list bitmap to use */ - int j_must_wait; /* no more journal begins allowed. MUST sleep on j_join_wait */ - int j_next_full_flush; /* next journal_end will flush all journal list */ - int j_next_async_flush; /* next journal_end will flush all async commits */ - - int j_cnode_used; /* number of cnodes on the used list */ - int j_cnode_free; /* number of cnodes on the free list */ - - unsigned int j_trans_max; /* max number of blocks in a transaction. */ - unsigned int j_max_batch; /* max number of blocks to batch into a trans */ - unsigned int j_max_commit_age; /* in seconds, how old can an async commit be */ - unsigned int j_max_trans_age; /* in seconds, how old can a transaction be */ - unsigned int j_default_max_commit_age; /* the default for the max commit age */ - - struct reiserfs_journal_cnode *j_cnode_free_list; - struct reiserfs_journal_cnode *j_cnode_free_orig; /* orig pointer returned from vmalloc */ - - struct reiserfs_journal_list *j_current_jl; - int j_free_bitmap_nodes; - int j_used_bitmap_nodes; - - int j_num_lists; /* total number of active transactions */ - int j_num_work_lists; /* number that need attention from kreiserfsd */ - - /* debugging to make sure things are flushed in order */ - unsigned int j_last_flush_id; - - /* debugging to make sure things are committed in order */ - unsigned int j_last_commit_id; - - struct list_head j_bitmap_nodes; - struct list_head j_dirty_buffers; - spinlock_t j_dirty_buffers_lock; /* protects j_dirty_buffers */ - - /* list of all active transactions */ - struct list_head j_journal_list; - /* lists that haven't been touched by writeback attempts */ - struct list_head j_working_list; - - struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS]; /* array of bitmaps to record the deleted blocks */ - struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE]; /* hash table for real buffer heads in current trans */ - struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE]; /* hash table for all the real buffer heads in all - the transactions */ - struct list_head j_prealloc_list; /* list of inodes which have preallocated blocks */ - int j_persistent_trans; - unsigned long j_max_trans_size; - unsigned long j_max_batch_size; - - int j_errno; - - /* when flushing ordered buffers, throttle new ordered writers */ - struct delayed_work j_work; - struct super_block *j_work_sb; - atomic_t j_async_throttle; -}; - -enum journal_state_bits { - J_WRITERS_BLOCKED = 1, /* set when new writers not allowed */ - J_WRITERS_QUEUED, /* set when log is full due to too many writers */ - J_ABORTED, /* set when log is aborted */ -}; - -#define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */ - -typedef __u32(*hashf_t) (const signed char *, int); - -struct reiserfs_bitmap_info { - __u32 free_count; -}; - -struct proc_dir_entry; - -#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO ) -typedef unsigned long int stat_cnt_t; -typedef struct reiserfs_proc_info_data { - spinlock_t lock; - int exiting; - int max_hash_collisions; - - stat_cnt_t breads; - stat_cnt_t bread_miss; - stat_cnt_t search_by_key; - stat_cnt_t search_by_key_fs_changed; - stat_cnt_t search_by_key_restarted; - - stat_cnt_t insert_item_restarted; - stat_cnt_t paste_into_item_restarted; - stat_cnt_t cut_from_item_restarted; - stat_cnt_t delete_solid_item_restarted; - stat_cnt_t delete_item_restarted; - - stat_cnt_t leaked_oid; - stat_cnt_t leaves_removable; - - /* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */ - stat_cnt_t balance_at[5]; /* XXX */ - /* sbk == search_by_key */ - stat_cnt_t sbk_read_at[5]; /* XXX */ - stat_cnt_t sbk_fs_changed[5]; - stat_cnt_t sbk_restarted[5]; - stat_cnt_t items_at[5]; /* XXX */ - stat_cnt_t free_at[5]; /* XXX */ - stat_cnt_t can_node_be_removed[5]; /* XXX */ - long int lnum[5]; /* XXX */ - long int rnum[5]; /* XXX */ - long int lbytes[5]; /* XXX */ - long int rbytes[5]; /* XXX */ - stat_cnt_t get_neighbors[5]; - stat_cnt_t get_neighbors_restart[5]; - stat_cnt_t need_l_neighbor[5]; - stat_cnt_t need_r_neighbor[5]; - - stat_cnt_t free_block; - struct __scan_bitmap_stats { - stat_cnt_t call; - stat_cnt_t wait; - stat_cnt_t bmap; - stat_cnt_t retry; - stat_cnt_t in_journal_hint; - stat_cnt_t in_journal_nohint; - stat_cnt_t stolen; - } scan_bitmap; - struct __journal_stats { - stat_cnt_t in_journal; - stat_cnt_t in_journal_bitmap; - stat_cnt_t in_journal_reusable; - stat_cnt_t lock_journal; - stat_cnt_t lock_journal_wait; - stat_cnt_t journal_being; - stat_cnt_t journal_relock_writers; - stat_cnt_t journal_relock_wcount; - stat_cnt_t mark_dirty; - stat_cnt_t mark_dirty_already; - stat_cnt_t mark_dirty_notjournal; - stat_cnt_t restore_prepared; - stat_cnt_t prepare; - stat_cnt_t prepare_retry; - } journal; -} reiserfs_proc_info_data_t; -#else -typedef struct reiserfs_proc_info_data { -} reiserfs_proc_info_data_t; -#endif - -/* reiserfs union of in-core super block data */ -struct reiserfs_sb_info { - struct buffer_head *s_sbh; /* Buffer containing the super block */ - /* both the comment and the choice of - name are unclear for s_rs -Hans */ - struct reiserfs_super_block *s_rs; /* Pointer to the super block in the buffer */ - struct reiserfs_bitmap_info *s_ap_bitmap; - struct reiserfs_journal *s_journal; /* pointer to journal information */ - unsigned short s_mount_state; /* reiserfs state (valid, invalid) */ - - /* Serialize writers access, replace the old bkl */ - struct mutex lock; - /* Owner of the lock (can be recursive) */ - struct task_struct *lock_owner; - /* Depth of the lock, start from -1 like the bkl */ - int lock_depth; - - /* Comment? -Hans */ - void (*end_io_handler) (struct buffer_head *, int); - hashf_t s_hash_function; /* pointer to function which is used - to sort names in directory. Set on - mount */ - unsigned long s_mount_opt; /* reiserfs's mount options are set - here (currently - NOTAIL, NOLOG, - REPLAYONLY) */ - - struct { /* This is a structure that describes block allocator options */ - unsigned long bits; /* Bitfield for enable/disable kind of options */ - unsigned long large_file_size; /* size started from which we consider file to be a large one(in blocks) */ - int border; /* percentage of disk, border takes */ - int preallocmin; /* Minimal file size (in blocks) starting from which we do preallocations */ - int preallocsize; /* Number of blocks we try to prealloc when file - reaches preallocmin size (in blocks) or - prealloc_list is empty. */ - } s_alloc_options; - - /* Comment? -Hans */ - wait_queue_head_t s_wait; - /* To be obsoleted soon by per buffer seals.. -Hans */ - atomic_t s_generation_counter; // increased by one every time the - // tree gets re-balanced - unsigned long s_properties; /* File system properties. Currently holds - on-disk FS format */ - - /* session statistics */ - int s_disk_reads; - int s_disk_writes; - int s_fix_nodes; - int s_do_balance; - int s_unneeded_left_neighbor; - int s_good_search_by_key_reada; - int s_bmaps; - int s_bmaps_without_search; - int s_direct2indirect; - int s_indirect2direct; - /* set up when it's ok for reiserfs_read_inode2() to read from - disk inode with nlink==0. Currently this is only used during - finish_unfinished() processing at mount time */ - int s_is_unlinked_ok; - reiserfs_proc_info_data_t s_proc_info_data; - struct proc_dir_entry *procdir; - int reserved_blocks; /* amount of blocks reserved for further allocations */ - spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */ - struct dentry *priv_root; /* root of /.reiserfs_priv */ - struct dentry *xattr_root; /* root of /.reiserfs_priv/xattrs */ - int j_errno; -#ifdef CONFIG_QUOTA - char *s_qf_names[MAXQUOTAS]; - int s_jquota_fmt; -#endif - char *s_jdev; /* Stored jdev for mount option showing */ -#ifdef CONFIG_REISERFS_CHECK - - struct tree_balance *cur_tb; /* - * Detects whether more than one - * copy of tb exists per superblock - * as a means of checking whether - * do_balance is executing concurrently - * against another tree reader/writer - * on a same mount point. - */ -#endif -}; - -/* Definitions of reiserfs on-disk properties: */ -#define REISERFS_3_5 0 -#define REISERFS_3_6 1 -#define REISERFS_OLD_FORMAT 2 - -enum reiserfs_mount_options { -/* Mount options */ - REISERFS_LARGETAIL, /* large tails will be created in a session */ - REISERFS_SMALLTAIL, /* small (for files less than block size) tails will be created in a session */ - REPLAYONLY, /* replay journal and return 0. Use by fsck */ - REISERFS_CONVERT, /* -o conv: causes conversion of old - format super block to the new - format. If not specified - old - partition will be dealt with in a - manner of 3.5.x */ - -/* -o hash={tea, rupasov, r5, detect} is meant for properly mounting -** reiserfs disks from 3.5.19 or earlier. 99% of the time, this option -** is not required. If the normal autodection code can't determine which -** hash to use (because both hashes had the same value for a file) -** use this option to force a specific hash. It won't allow you to override -** the existing hash on the FS, so if you have a tea hash disk, and mount -** with -o hash=rupasov, the mount will fail. -*/ - FORCE_TEA_HASH, /* try to force tea hash on mount */ - FORCE_RUPASOV_HASH, /* try to force rupasov hash on mount */ - FORCE_R5_HASH, /* try to force rupasov hash on mount */ - FORCE_HASH_DETECT, /* try to detect hash function on mount */ - - REISERFS_DATA_LOG, - REISERFS_DATA_ORDERED, - REISERFS_DATA_WRITEBACK, - -/* used for testing experimental features, makes benchmarking new - features with and without more convenient, should never be used by - users in any code shipped to users (ideally) */ - - REISERFS_NO_BORDER, - REISERFS_NO_UNHASHED_RELOCATION, - REISERFS_HASHED_RELOCATION, - REISERFS_ATTRS, - REISERFS_XATTRS_USER, - REISERFS_POSIXACL, - REISERFS_EXPOSE_PRIVROOT, - REISERFS_BARRIER_NONE, - REISERFS_BARRIER_FLUSH, - - /* Actions on error */ - REISERFS_ERROR_PANIC, - REISERFS_ERROR_RO, - REISERFS_ERROR_CONTINUE, - - REISERFS_USRQUOTA, /* User quota option specified */ - REISERFS_GRPQUOTA, /* Group quota option specified */ - - REISERFS_TEST1, - REISERFS_TEST2, - REISERFS_TEST3, - REISERFS_TEST4, - REISERFS_UNSUPPORTED_OPT, -}; - -#define reiserfs_r5_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_R5_HASH)) -#define reiserfs_rupasov_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_RUPASOV_HASH)) -#define reiserfs_tea_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_TEA_HASH)) -#define reiserfs_hash_detect(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_HASH_DETECT)) -#define reiserfs_no_border(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_BORDER)) -#define reiserfs_no_unhashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_UNHASHED_RELOCATION)) -#define reiserfs_hashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_HASHED_RELOCATION)) -#define reiserfs_test4(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_TEST4)) - -#define have_large_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_LARGETAIL)) -#define have_small_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_SMALLTAIL)) -#define replay_only(s) (REISERFS_SB(s)->s_mount_opt & (1 << REPLAYONLY)) -#define reiserfs_attrs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ATTRS)) -#define old_format_only(s) (REISERFS_SB(s)->s_properties & (1 << REISERFS_3_5)) -#define convert_reiserfs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_CONVERT)) -#define reiserfs_data_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_LOG)) -#define reiserfs_data_ordered(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_ORDERED)) -#define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK)) -#define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER)) -#define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL)) -#define reiserfs_expose_privroot(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_EXPOSE_PRIVROOT)) -#define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s)) -#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE)) -#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH)) - -#define reiserfs_error_panic(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_PANIC)) -#define reiserfs_error_ro(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_RO)) - -void reiserfs_file_buffer(struct buffer_head *bh, int list); -extern struct file_system_type reiserfs_fs_type; -int reiserfs_resize(struct super_block *, unsigned long); - -#define CARRY_ON 0 -#define SCHEDULE_OCCURRED 1 - -#define SB_BUFFER_WITH_SB(s) (REISERFS_SB(s)->s_sbh) -#define SB_JOURNAL(s) (REISERFS_SB(s)->s_journal) -#define SB_JOURNAL_1st_RESERVED_BLOCK(s) (SB_JOURNAL(s)->j_1st_reserved_block) -#define SB_JOURNAL_LEN_FREE(s) (SB_JOURNAL(s)->j_journal_len_free) -#define SB_AP_BITMAP(s) (REISERFS_SB(s)->s_ap_bitmap) - -#define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->) - -/* A safe version of the "bdevname", which returns the "s_id" field of - * a superblock or else "Null superblock" if the super block is NULL. - */ -static inline char *reiserfs_bdevname(struct super_block *s) -{ - return (s == NULL) ? "Null superblock" : s->s_id; -} - -#define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal))) -static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal - *journal) -{ - return test_bit(J_ABORTED, &journal->j_state); -} - -/* - * Locking primitives. The write lock is a per superblock - * special mutex that has properties close to the Big Kernel Lock - * which was used in the previous locking scheme. - */ -void reiserfs_write_lock(struct super_block *s); -void reiserfs_write_unlock(struct super_block *s); -int reiserfs_write_lock_once(struct super_block *s); -void reiserfs_write_unlock_once(struct super_block *s, int lock_depth); - -#ifdef CONFIG_REISERFS_CHECK -void reiserfs_lock_check_recursive(struct super_block *s); -#else -static inline void reiserfs_lock_check_recursive(struct super_block *s) { } -#endif - -/* - * Several mutexes depend on the write lock. - * However sometimes we want to relax the write lock while we hold - * these mutexes, according to the release/reacquire on schedule() - * properties of the Bkl that were used. - * Reiserfs performances and locking were based on this scheme. - * Now that the write lock is a mutex and not the bkl anymore, doing so - * may result in a deadlock: - * - * A acquire write_lock - * A acquire j_commit_mutex - * A release write_lock and wait for something - * B acquire write_lock - * B can't acquire j_commit_mutex and sleep - * A can't acquire write lock anymore - * deadlock - * - * What we do here is avoiding such deadlock by playing the same game - * than the Bkl: if we can't acquire a mutex that depends on the write lock, - * we release the write lock, wait a bit and then retry. - * - * The mutexes concerned by this hack are: - * - The commit mutex of a journal list - * - The flush mutex - * - The journal lock - * - The inode mutex - */ -static inline void reiserfs_mutex_lock_safe(struct mutex *m, - struct super_block *s) -{ - reiserfs_lock_check_recursive(s); - reiserfs_write_unlock(s); - mutex_lock(m); - reiserfs_write_lock(s); -} - -static inline void -reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass, - struct super_block *s) -{ - reiserfs_lock_check_recursive(s); - reiserfs_write_unlock(s); - mutex_lock_nested(m, subclass); - reiserfs_write_lock(s); -} - -static inline void -reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s) -{ - reiserfs_lock_check_recursive(s); - reiserfs_write_unlock(s); - down_read(sem); - reiserfs_write_lock(s); -} - -/* - * When we schedule, we usually want to also release the write lock, - * according to the previous bkl based locking scheme of reiserfs. - */ -static inline void reiserfs_cond_resched(struct super_block *s) -{ - if (need_resched()) { - reiserfs_write_unlock(s); - schedule(); - reiserfs_write_lock(s); - } -} - -struct fid; - -/* in reading the #defines, it may help to understand that they employ - the following abbreviations: - - B = Buffer - I = Item header - H = Height within the tree (should be changed to LEV) - N = Number of the item in the node - STAT = stat data - DEH = Directory Entry Header - EC = Entry Count - E = Entry number - UL = Unsigned Long - BLKH = BLocK Header - UNFM = UNForMatted node - DC = Disk Child - P = Path - - These #defines are named by concatenating these abbreviations, - where first comes the arguments, and last comes the return value, - of the macro. - -*/ - -#define USE_INODE_GENERATION_COUNTER - -#define REISERFS_PREALLOCATE -#define DISPLACE_NEW_PACKING_LOCALITIES -#define PREALLOCATION_SIZE 9 - -/* n must be power of 2 */ -#define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u)) - -// to be ok for alpha and others we have to align structures to 8 byte -// boundary. -// FIXME: do not change 4 by anything else: there is code which relies on that -#define ROUND_UP(x) _ROUND_UP(x,8LL) - -/* debug levels. Right now, CONFIG_REISERFS_CHECK means print all debug -** messages. -*/ -#define REISERFS_DEBUG_CODE 5 /* extra messages to help find/debug errors */ - -void __reiserfs_warning(struct super_block *s, const char *id, - const char *func, const char *fmt, ...); -#define reiserfs_warning(s, id, fmt, args...) \ - __reiserfs_warning(s, id, __func__, fmt, ##args) -/* assertions handling */ - -/** always check a condition and panic if it's false. */ -#define __RASSERT(cond, scond, format, args...) \ -do { \ - if (!(cond)) \ - reiserfs_panic(NULL, "assertion failure", "(" #cond ") at " \ - __FILE__ ":%i:%s: " format "\n", \ - in_interrupt() ? -1 : task_pid_nr(current), \ - __LINE__, __func__ , ##args); \ -} while (0) - -#define RASSERT(cond, format, args...) __RASSERT(cond, #cond, format, ##args) - -#if defined( CONFIG_REISERFS_CHECK ) -#define RFALSE(cond, format, args...) __RASSERT(!(cond), "!(" #cond ")", format, ##args) -#else -#define RFALSE( cond, format, args... ) do {;} while( 0 ) -#endif - -#define CONSTF __attribute_const__ -/* - * Disk Data Structures - */ - -/***************************************************************************/ -/* SUPER BLOCK */ -/***************************************************************************/ - -/* - * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs - * the version in RAM is part of a larger structure containing fields never written to disk. - */ -#define UNSET_HASH 0 // read_super will guess about, what hash names - // in directories were sorted with -#define TEA_HASH 1 -#define YURA_HASH 2 -#define R5_HASH 3 -#define DEFAULT_HASH R5_HASH - -struct journal_params { - __le32 jp_journal_1st_block; /* where does journal start from on its - * device */ - __le32 jp_journal_dev; /* journal device st_rdev */ - __le32 jp_journal_size; /* size of the journal */ - __le32 jp_journal_trans_max; /* max number of blocks in a transaction. */ - __le32 jp_journal_magic; /* random value made on fs creation (this - * was sb_journal_block_count) */ - __le32 jp_journal_max_batch; /* max number of blocks to batch into a - * trans */ - __le32 jp_journal_max_commit_age; /* in seconds, how old can an async - * commit be */ - __le32 jp_journal_max_trans_age; /* in seconds, how old can a transaction - * be */ -}; - -/* this is the super from 3.5.X, where X >= 10 */ -struct reiserfs_super_block_v1 { - __le32 s_block_count; /* blocks count */ - __le32 s_free_blocks; /* free blocks count */ - __le32 s_root_block; /* root block number */ - struct journal_params s_journal; - __le16 s_blocksize; /* block size */ - __le16 s_oid_maxsize; /* max size of object id array, see - * get_objectid() commentary */ - __le16 s_oid_cursize; /* current size of object id array */ - __le16 s_umount_state; /* this is set to 1 when filesystem was - * umounted, to 2 - when not */ - char s_magic[10]; /* reiserfs magic string indicates that - * file system is reiserfs: - * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */ - __le16 s_fs_state; /* it is set to used by fsck to mark which - * phase of rebuilding is done */ - __le32 s_hash_function_code; /* indicate, what hash function is being use - * to sort names in a directory*/ - __le16 s_tree_height; /* height of disk tree */ - __le16 s_bmap_nr; /* amount of bitmap blocks needed to address - * each block of file system */ - __le16 s_version; /* this field is only reliable on filesystem - * with non-standard journal */ - __le16 s_reserved_for_journal; /* size in blocks of journal area on main - * device, we need to keep after - * making fs with non-standard journal */ -} __attribute__ ((__packed__)); - -#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1)) - -/* this is the on disk super block */ -struct reiserfs_super_block { - struct reiserfs_super_block_v1 s_v1; - __le32 s_inode_generation; - __le32 s_flags; /* Right now used only by inode-attributes, if enabled */ - unsigned char s_uuid[16]; /* filesystem unique identifier */ - unsigned char s_label[16]; /* filesystem volume label */ - __le16 s_mnt_count; /* Count of mounts since last fsck */ - __le16 s_max_mnt_count; /* Maximum mounts before check */ - __le32 s_lastcheck; /* Timestamp of last fsck */ - __le32 s_check_interval; /* Interval between checks */ - char s_unused[76]; /* zero filled by mkreiserfs and - * reiserfs_convert_objectid_map_v1() - * so any additions must be updated - * there as well. */ -} __attribute__ ((__packed__)); - -#define SB_SIZE (sizeof(struct reiserfs_super_block)) - -#define REISERFS_VERSION_1 0 -#define REISERFS_VERSION_2 2 - -// on-disk super block fields converted to cpu form -#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs) -#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1)) -#define SB_BLOCKSIZE(s) \ - le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize)) -#define SB_BLOCK_COUNT(s) \ - le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count)) -#define SB_FREE_BLOCKS(s) \ - le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks)) -#define SB_REISERFS_MAGIC(s) \ - (SB_V1_DISK_SUPER_BLOCK(s)->s_magic) -#define SB_ROOT_BLOCK(s) \ - le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block)) -#define SB_TREE_HEIGHT(s) \ - le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height)) -#define SB_REISERFS_STATE(s) \ - le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state)) -#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version)) -#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr)) - -#define PUT_SB_BLOCK_COUNT(s, val) \ - do { SB_V1_DISK_SUPER_BLOCK(s)->s_block_count = cpu_to_le32(val); } while (0) -#define PUT_SB_FREE_BLOCKS(s, val) \ - do { SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks = cpu_to_le32(val); } while (0) -#define PUT_SB_ROOT_BLOCK(s, val) \ - do { SB_V1_DISK_SUPER_BLOCK(s)->s_root_block = cpu_to_le32(val); } while (0) -#define PUT_SB_TREE_HEIGHT(s, val) \ - do { SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height = cpu_to_le16(val); } while (0) -#define PUT_SB_REISERFS_STATE(s, val) \ - do { SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state = cpu_to_le16(val); } while (0) -#define PUT_SB_VERSION(s, val) \ - do { SB_V1_DISK_SUPER_BLOCK(s)->s_version = cpu_to_le16(val); } while (0) -#define PUT_SB_BMAP_NR(s, val) \ - do { SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr = cpu_to_le16 (val); } while (0) - -#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal) -#define SB_ONDISK_JOURNAL_SIZE(s) \ - le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size)) -#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \ - le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block)) -#define SB_ONDISK_JOURNAL_DEVICE(s) \ - le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev)) -#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \ - le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal)) - -#define is_block_in_log_or_reserved_area(s, block) \ - block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \ - && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) + \ - ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \ - SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s))) - -int is_reiserfs_3_5(struct reiserfs_super_block *rs); -int is_reiserfs_3_6(struct reiserfs_super_block *rs); -int is_reiserfs_jr(struct reiserfs_super_block *rs); - -/* ReiserFS leaves the first 64k unused, so that partition labels have - enough space. If someone wants to write a fancy bootloader that - needs more than 64k, let us know, and this will be increased in size. - This number must be larger than than the largest block size on any - platform, or code will break. -Hans */ -#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) -#define REISERFS_FIRST_BLOCK unused_define -#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES - -/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */ -#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) - -/* reiserfs internal error code (used by search_by_key and fix_nodes)) */ -#define CARRY_ON 0 -#define REPEAT_SEARCH -1 -#define IO_ERROR -2 -#define NO_DISK_SPACE -3 -#define NO_BALANCING_NEEDED (-4) -#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5) -#define QUOTA_EXCEEDED -6 - -typedef __u32 b_blocknr_t; -typedef __le32 unp_t; - -struct unfm_nodeinfo { - unp_t unfm_nodenum; - unsigned short unfm_freespace; -}; - -/* there are two formats of keys: 3.5 and 3.6 - */ -#define KEY_FORMAT_3_5 0 -#define KEY_FORMAT_3_6 1 - -/* there are two stat datas */ -#define STAT_DATA_V1 0 -#define STAT_DATA_V2 1 - -static inline struct reiserfs_inode_info *REISERFS_I(const struct inode *inode) -{ - return container_of(inode, struct reiserfs_inode_info, vfs_inode); -} - -static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb) -{ - return sb->s_fs_info; -} - -/* Don't trust REISERFS_SB(sb)->s_bmap_nr, it's a u16 - * which overflows on large file systems. */ -static inline __u32 reiserfs_bmap_count(struct super_block *sb) -{ - return (SB_BLOCK_COUNT(sb) - 1) / (sb->s_blocksize * 8) + 1; -} - -static inline int bmap_would_wrap(unsigned bmap_nr) -{ - return bmap_nr > ((1LL << 16) - 1); -} - -/** this says about version of key of all items (but stat data) the - object consists of */ -#define get_inode_item_key_version( inode ) \ - ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5) - -#define set_inode_item_key_version( inode, version ) \ - ({ if((version)==KEY_FORMAT_3_6) \ - REISERFS_I(inode)->i_flags |= i_item_key_version_mask; \ - else \ - REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; }) - -#define get_inode_sd_version(inode) \ - ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1) - -#define set_inode_sd_version(inode, version) \ - ({ if((version)==STAT_DATA_V2) \ - REISERFS_I(inode)->i_flags |= i_stat_data_version_mask; \ - else \ - REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; }) - -/* This is an aggressive tail suppression policy, I am hoping it - improves our benchmarks. The principle behind it is that percentage - space saving is what matters, not absolute space saving. This is - non-intuitive, but it helps to understand it if you consider that the - cost to access 4 blocks is not much more than the cost to access 1 - block, if you have to do a seek and rotate. A tail risks a - non-linear disk access that is significant as a percentage of total - time cost for a 4 block file and saves an amount of space that is - less significant as a percentage of space, or so goes the hypothesis. - -Hans */ -#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \ -(\ - (!(n_tail_size)) || \ - (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \ - ( (n_file_size) >= (n_block_size) * 4 ) || \ - ( ( (n_file_size) >= (n_block_size) * 3 ) && \ - ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \ - ( ( (n_file_size) >= (n_block_size) * 2 ) && \ - ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \ - ( ( (n_file_size) >= (n_block_size) ) && \ - ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \ -) - -/* Another strategy for tails, this one means only create a tail if all the - file would fit into one DIRECT item. - Primary intention for this one is to increase performance by decreasing - seeking. -*/ -#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \ -(\ - (!(n_tail_size)) || \ - (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \ -) - -/* - * values for s_umount_state field - */ -#define REISERFS_VALID_FS 1 -#define REISERFS_ERROR_FS 2 - -// -// there are 5 item types currently -// -#define TYPE_STAT_DATA 0 -#define TYPE_INDIRECT 1 -#define TYPE_DIRECT 2 -#define TYPE_DIRENTRY 3 -#define TYPE_MAXTYPE 3 -#define TYPE_ANY 15 // FIXME: comment is required - -/***************************************************************************/ -/* KEY & ITEM HEAD */ -/***************************************************************************/ - -// -// directories use this key as well as old files -// -struct offset_v1 { - __le32 k_offset; - __le32 k_uniqueness; -} __attribute__ ((__packed__)); - -struct offset_v2 { - __le64 v; -} __attribute__ ((__packed__)); - -static inline __u16 offset_v2_k_type(const struct offset_v2 *v2) -{ - __u8 type = le64_to_cpu(v2->v) >> 60; - return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY; -} - -static inline void set_offset_v2_k_type(struct offset_v2 *v2, int type) -{ - v2->v = - (v2->v & cpu_to_le64(~0ULL >> 4)) | cpu_to_le64((__u64) type << 60); -} - -static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2) -{ - return le64_to_cpu(v2->v) & (~0ULL >> 4); -} - -static inline void set_offset_v2_k_offset(struct offset_v2 *v2, loff_t offset) -{ - offset &= (~0ULL >> 4); - v2->v = (v2->v & cpu_to_le64(15ULL << 60)) | cpu_to_le64(offset); -} - -/* Key of an item determines its location in the S+tree, and - is composed of 4 components */ -struct reiserfs_key { - __le32 k_dir_id; /* packing locality: by default parent - directory object id */ - __le32 k_objectid; /* object identifier */ - union { - struct offset_v1 k_offset_v1; - struct offset_v2 k_offset_v2; - } __attribute__ ((__packed__)) u; -} __attribute__ ((__packed__)); - -struct in_core_key { - __u32 k_dir_id; /* packing locality: by default parent - directory object id */ - __u32 k_objectid; /* object identifier */ - __u64 k_offset; - __u8 k_type; -}; - -struct cpu_key { - struct in_core_key on_disk_key; - int version; - int key_length; /* 3 in all cases but direct2indirect and - indirect2direct conversion */ -}; - -/* Our function for comparing keys can compare keys of different - lengths. It takes as a parameter the length of the keys it is to - compare. These defines are used in determining what is to be passed - to it as that parameter. */ -#define REISERFS_FULL_KEY_LEN 4 -#define REISERFS_SHORT_KEY_LEN 2 - -/* The result of the key compare */ -#define FIRST_GREATER 1 -#define SECOND_GREATER -1 -#define KEYS_IDENTICAL 0 -#define KEY_FOUND 1 -#define KEY_NOT_FOUND 0 - -#define KEY_SIZE (sizeof(struct reiserfs_key)) -#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32)) - -/* return values for search_by_key and clones */ -#define ITEM_FOUND 1 -#define ITEM_NOT_FOUND 0 -#define ENTRY_FOUND 1 -#define ENTRY_NOT_FOUND 0 -#define DIRECTORY_NOT_FOUND -1 -#define REGULAR_FILE_FOUND -2 -#define DIRECTORY_FOUND -3 -#define BYTE_FOUND 1 -#define BYTE_NOT_FOUND 0 -#define FILE_NOT_FOUND -1 - -#define POSITION_FOUND 1 -#define POSITION_NOT_FOUND 0 - -// return values for reiserfs_find_entry and search_by_entry_key -#define NAME_FOUND 1 -#define NAME_NOT_FOUND 0 -#define GOTO_PREVIOUS_ITEM 2 -#define NAME_FOUND_INVISIBLE 3 - -/* Everything in the filesystem is stored as a set of items. The - item head contains the key of the item, its free space (for - indirect items) and specifies the location of the item itself - within the block. */ - -struct item_head { - /* Everything in the tree is found by searching for it based on - * its key.*/ - struct reiserfs_key ih_key; - union { - /* The free space in the last unformatted node of an - indirect item if this is an indirect item. This - equals 0xFFFF iff this is a direct item or stat data - item. Note that the key, not this field, is used to - determine the item type, and thus which field this - union contains. */ - __le16 ih_free_space_reserved; - /* Iff this is a directory item, this field equals the - number of directory entries in the directory item. */ - __le16 ih_entry_count; - } __attribute__ ((__packed__)) u; - __le16 ih_item_len; /* total size of the item body */ - __le16 ih_item_location; /* an offset to the item body - * within the block */ - __le16 ih_version; /* 0 for all old items, 2 for new - ones. Highest bit is set by fsck - temporary, cleaned after all - done */ -} __attribute__ ((__packed__)); -/* size of item header */ -#define IH_SIZE (sizeof(struct item_head)) - -#define ih_free_space(ih) le16_to_cpu((ih)->u.ih_free_space_reserved) -#define ih_version(ih) le16_to_cpu((ih)->ih_version) -#define ih_entry_count(ih) le16_to_cpu((ih)->u.ih_entry_count) -#define ih_location(ih) le16_to_cpu((ih)->ih_item_location) -#define ih_item_len(ih) le16_to_cpu((ih)->ih_item_len) - -#define put_ih_free_space(ih, val) do { (ih)->u.ih_free_space_reserved = cpu_to_le16(val); } while(0) -#define put_ih_version(ih, val) do { (ih)->ih_version = cpu_to_le16(val); } while (0) -#define put_ih_entry_count(ih, val) do { (ih)->u.ih_entry_count = cpu_to_le16(val); } while (0) -#define put_ih_location(ih, val) do { (ih)->ih_item_location = cpu_to_le16(val); } while (0) -#define put_ih_item_len(ih, val) do { (ih)->ih_item_len = cpu_to_le16(val); } while (0) - -#define unreachable_item(ih) (ih_version(ih) & (1 << 15)) - -#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih)) -#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == KEY_FORMAT_3_6) ? 0 : (val))) - -/* these operate on indirect items, where you've got an array of ints -** at a possibly unaligned location. These are a noop on ia32 -** -** p is the array of __u32, i is the index into the array, v is the value -** to store there. -*/ -#define get_block_num(p, i) get_unaligned_le32((p) + (i)) -#define put_block_num(p, i, v) put_unaligned_le32((v), (p) + (i)) - -// -// in old version uniqueness field shows key type -// -#define V1_SD_UNIQUENESS 0 -#define V1_INDIRECT_UNIQUENESS 0xfffffffe -#define V1_DIRECT_UNIQUENESS 0xffffffff -#define V1_DIRENTRY_UNIQUENESS 500 -#define V1_ANY_UNIQUENESS 555 // FIXME: comment is required - -// -// here are conversion routines -// -static inline int uniqueness2type(__u32 uniqueness) CONSTF; -static inline int uniqueness2type(__u32 uniqueness) -{ - switch ((int)uniqueness) { - case V1_SD_UNIQUENESS: - return TYPE_STAT_DATA; - case V1_INDIRECT_UNIQUENESS: - return TYPE_INDIRECT; - case V1_DIRECT_UNIQUENESS: - return TYPE_DIRECT; - case V1_DIRENTRY_UNIQUENESS: - return TYPE_DIRENTRY; - case V1_ANY_UNIQUENESS: - default: - return TYPE_ANY; - } -} - -static inline __u32 type2uniqueness(int type) CONSTF; -static inline __u32 type2uniqueness(int type) -{ - switch (type) { - case TYPE_STAT_DATA: - return V1_SD_UNIQUENESS; - case TYPE_INDIRECT: - return V1_INDIRECT_UNIQUENESS; - case TYPE_DIRECT: - return V1_DIRECT_UNIQUENESS; - case TYPE_DIRENTRY: - return V1_DIRENTRY_UNIQUENESS; - case TYPE_ANY: - default: - return V1_ANY_UNIQUENESS; - } -} - -// -// key is pointer to on disk key which is stored in le, result is cpu, -// there is no way to get version of object from key, so, provide -// version to these defines -// -static inline loff_t le_key_k_offset(int version, - const struct reiserfs_key *key) -{ - return (version == KEY_FORMAT_3_5) ? - le32_to_cpu(key->u.k_offset_v1.k_offset) : - offset_v2_k_offset(&(key->u.k_offset_v2)); -} - -static inline loff_t le_ih_k_offset(const struct item_head *ih) -{ - return le_key_k_offset(ih_version(ih), &(ih->ih_key)); -} - -static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key) -{ - return (version == KEY_FORMAT_3_5) ? - uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) : - offset_v2_k_type(&(key->u.k_offset_v2)); -} - -static inline loff_t le_ih_k_type(const struct item_head *ih) -{ - return le_key_k_type(ih_version(ih), &(ih->ih_key)); -} - -static inline void set_le_key_k_offset(int version, struct reiserfs_key *key, - loff_t offset) -{ - (version == KEY_FORMAT_3_5) ? (void)(key->u.k_offset_v1.k_offset = cpu_to_le32(offset)) : /* jdm check */ - (void)(set_offset_v2_k_offset(&(key->u.k_offset_v2), offset)); -} - -static inline void set_le_ih_k_offset(struct item_head *ih, loff_t offset) -{ - set_le_key_k_offset(ih_version(ih), &(ih->ih_key), offset); -} - -static inline void set_le_key_k_type(int version, struct reiserfs_key *key, - int type) -{ - (version == KEY_FORMAT_3_5) ? - (void)(key->u.k_offset_v1.k_uniqueness = - cpu_to_le32(type2uniqueness(type))) - : (void)(set_offset_v2_k_type(&(key->u.k_offset_v2), type)); -} - -static inline void set_le_ih_k_type(struct item_head *ih, int type) -{ - set_le_key_k_type(ih_version(ih), &(ih->ih_key), type); -} - -static inline int is_direntry_le_key(int version, struct reiserfs_key *key) -{ - return le_key_k_type(version, key) == TYPE_DIRENTRY; -} - -static inline int is_direct_le_key(int version, struct reiserfs_key *key) -{ - return le_key_k_type(version, key) == TYPE_DIRECT; -} - -static inline int is_indirect_le_key(int version, struct reiserfs_key *key) -{ - return le_key_k_type(version, key) == TYPE_INDIRECT; -} - -static inline int is_statdata_le_key(int version, struct reiserfs_key *key) -{ - return le_key_k_type(version, key) == TYPE_STAT_DATA; -} - -// -// item header has version. -// -static inline int is_direntry_le_ih(struct item_head *ih) -{ - return is_direntry_le_key(ih_version(ih), &ih->ih_key); -} - -static inline int is_direct_le_ih(struct item_head *ih) -{ - return is_direct_le_key(ih_version(ih), &ih->ih_key); -} - -static inline int is_indirect_le_ih(struct item_head *ih) -{ - return is_indirect_le_key(ih_version(ih), &ih->ih_key); -} - -static inline int is_statdata_le_ih(struct item_head *ih) -{ - return is_statdata_le_key(ih_version(ih), &ih->ih_key); -} - -// -// key is pointer to cpu key, result is cpu -// -static inline loff_t cpu_key_k_offset(const struct cpu_key *key) -{ - return key->on_disk_key.k_offset; -} - -static inline loff_t cpu_key_k_type(const struct cpu_key *key) -{ - return key->on_disk_key.k_type; -} - -static inline void set_cpu_key_k_offset(struct cpu_key *key, loff_t offset) -{ - key->on_disk_key.k_offset = offset; -} - -static inline void set_cpu_key_k_type(struct cpu_key *key, int type) -{ - key->on_disk_key.k_type = type; -} - -static inline void cpu_key_k_offset_dec(struct cpu_key *key) -{ - key->on_disk_key.k_offset--; -} - -#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY) -#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT) -#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT) -#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA) - -/* are these used ? */ -#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key))) -#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key))) -#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key))) -#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key))) - -#define I_K_KEY_IN_ITEM(ih, key, n_blocksize) \ - (!COMP_SHORT_KEYS(ih, key) && \ - I_OFF_BYTE_IN_ITEM(ih, k_offset(key), n_blocksize)) - -/* maximal length of item */ -#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE) -#define MIN_ITEM_LEN 1 - -/* object identifier for root dir */ -#define REISERFS_ROOT_OBJECTID 2 -#define REISERFS_ROOT_PARENT_OBJECTID 1 - -extern struct reiserfs_key root_key; - -/* - * Picture represents a leaf of the S+tree - * ______________________________________________________ - * | | Array of | | | - * |Block | Object-Item | F r e e | Objects- | - * | head | Headers | S p a c e | Items | - * |______|_______________|___________________|___________| - */ - -/* Header of a disk block. More precisely, header of a formatted leaf - or internal node, and not the header of an unformatted node. */ -struct block_head { - __le16 blk_level; /* Level of a block in the tree. */ - __le16 blk_nr_item; /* Number of keys/items in a block. */ - __le16 blk_free_space; /* Block free space in bytes. */ - __le16 blk_reserved; - /* dump this in v4/planA */ - struct reiserfs_key blk_right_delim_key; /* kept only for compatibility */ -}; - -#define BLKH_SIZE (sizeof(struct block_head)) -#define blkh_level(p_blkh) (le16_to_cpu((p_blkh)->blk_level)) -#define blkh_nr_item(p_blkh) (le16_to_cpu((p_blkh)->blk_nr_item)) -#define blkh_free_space(p_blkh) (le16_to_cpu((p_blkh)->blk_free_space)) -#define blkh_reserved(p_blkh) (le16_to_cpu((p_blkh)->blk_reserved)) -#define set_blkh_level(p_blkh,val) ((p_blkh)->blk_level = cpu_to_le16(val)) -#define set_blkh_nr_item(p_blkh,val) ((p_blkh)->blk_nr_item = cpu_to_le16(val)) -#define set_blkh_free_space(p_blkh,val) ((p_blkh)->blk_free_space = cpu_to_le16(val)) -#define set_blkh_reserved(p_blkh,val) ((p_blkh)->blk_reserved = cpu_to_le16(val)) -#define blkh_right_delim_key(p_blkh) ((p_blkh)->blk_right_delim_key) -#define set_blkh_right_delim_key(p_blkh,val) ((p_blkh)->blk_right_delim_key = val) - -/* - * values for blk_level field of the struct block_head - */ - -#define FREE_LEVEL 0 /* when node gets removed from the tree its - blk_level is set to FREE_LEVEL. It is then - used to see whether the node is still in the - tree */ - -#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */ - -/* Given the buffer head of a formatted node, resolve to the block head of that node. */ -#define B_BLK_HEAD(bh) ((struct block_head *)((bh)->b_data)) -/* Number of items that are in buffer. */ -#define B_NR_ITEMS(bh) (blkh_nr_item(B_BLK_HEAD(bh))) -#define B_LEVEL(bh) (blkh_level(B_BLK_HEAD(bh))) -#define B_FREE_SPACE(bh) (blkh_free_space(B_BLK_HEAD(bh))) - -#define PUT_B_NR_ITEMS(bh, val) do { set_blkh_nr_item(B_BLK_HEAD(bh), val); } while (0) -#define PUT_B_LEVEL(bh, val) do { set_blkh_level(B_BLK_HEAD(bh), val); } while (0) -#define PUT_B_FREE_SPACE(bh, val) do { set_blkh_free_space(B_BLK_HEAD(bh), val); } while (0) - -/* Get right delimiting key. -- little endian */ -#define B_PRIGHT_DELIM_KEY(bh) (&(blk_right_delim_key(B_BLK_HEAD(bh)))) - -/* Does the buffer contain a disk leaf. */ -#define B_IS_ITEMS_LEVEL(bh) (B_LEVEL(bh) == DISK_LEAF_NODE_LEVEL) - -/* Does the buffer contain a disk internal node */ -#define B_IS_KEYS_LEVEL(bh) (B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL \ - && B_LEVEL(bh) <= MAX_HEIGHT) - -/***************************************************************************/ -/* STAT DATA */ -/***************************************************************************/ - -// -// old stat data is 32 bytes long. We are going to distinguish new one by -// different size -// -struct stat_data_v1 { - __le16 sd_mode; /* file type, permissions */ - __le16 sd_nlink; /* number of hard links */ - __le16 sd_uid; /* owner */ - __le16 sd_gid; /* group */ - __le32 sd_size; /* file size */ - __le32 sd_atime; /* time of last access */ - __le32 sd_mtime; /* time file was last modified */ - __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ - union { - __le32 sd_rdev; - __le32 sd_blocks; /* number of blocks file uses */ - } __attribute__ ((__packed__)) u; - __le32 sd_first_direct_byte; /* first byte of file which is stored - in a direct item: except that if it - equals 1 it is a symlink and if it - equals ~(__u32)0 there is no - direct item. The existence of this - field really grates on me. Let's - replace it with a macro based on - sd_size and our tail suppression - policy. Someday. -Hans */ -} __attribute__ ((__packed__)); - -#define SD_V1_SIZE (sizeof(struct stat_data_v1)) -#define stat_data_v1(ih) (ih_version (ih) == KEY_FORMAT_3_5) -#define sd_v1_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) -#define set_sd_v1_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) -#define sd_v1_nlink(sdp) (le16_to_cpu((sdp)->sd_nlink)) -#define set_sd_v1_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le16(v)) -#define sd_v1_uid(sdp) (le16_to_cpu((sdp)->sd_uid)) -#define set_sd_v1_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le16(v)) -#define sd_v1_gid(sdp) (le16_to_cpu((sdp)->sd_gid)) -#define set_sd_v1_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le16(v)) -#define sd_v1_size(sdp) (le32_to_cpu((sdp)->sd_size)) -#define set_sd_v1_size(sdp,v) ((sdp)->sd_size = cpu_to_le32(v)) -#define sd_v1_atime(sdp) (le32_to_cpu((sdp)->sd_atime)) -#define set_sd_v1_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v)) -#define sd_v1_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime)) -#define set_sd_v1_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v)) -#define sd_v1_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime)) -#define set_sd_v1_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v)) -#define sd_v1_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev)) -#define set_sd_v1_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v)) -#define sd_v1_blocks(sdp) (le32_to_cpu((sdp)->u.sd_blocks)) -#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v)) -#define sd_v1_first_direct_byte(sdp) \ - (le32_to_cpu((sdp)->sd_first_direct_byte)) -#define set_sd_v1_first_direct_byte(sdp,v) \ - ((sdp)->sd_first_direct_byte = cpu_to_le32(v)) - -/* inode flags stored in sd_attrs (nee sd_reserved) */ - -/* we want common flags to have the same values as in ext2, - so chattr(1) will work without problems */ -#define REISERFS_IMMUTABLE_FL FS_IMMUTABLE_FL -#define REISERFS_APPEND_FL FS_APPEND_FL -#define REISERFS_SYNC_FL FS_SYNC_FL -#define REISERFS_NOATIME_FL FS_NOATIME_FL -#define REISERFS_NODUMP_FL FS_NODUMP_FL -#define REISERFS_SECRM_FL FS_SECRM_FL -#define REISERFS_UNRM_FL FS_UNRM_FL -#define REISERFS_COMPR_FL FS_COMPR_FL -#define REISERFS_NOTAIL_FL FS_NOTAIL_FL - -/* persistent flags that file inherits from the parent directory */ -#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \ - REISERFS_SYNC_FL | \ - REISERFS_NOATIME_FL | \ - REISERFS_NODUMP_FL | \ - REISERFS_SECRM_FL | \ - REISERFS_COMPR_FL | \ - REISERFS_NOTAIL_FL ) - -/* Stat Data on disk (reiserfs version of UFS disk inode minus the - address blocks) */ -struct stat_data { - __le16 sd_mode; /* file type, permissions */ - __le16 sd_attrs; /* persistent inode flags */ - __le32 sd_nlink; /* number of hard links */ - __le64 sd_size; /* file size */ - __le32 sd_uid; /* owner */ - __le32 sd_gid; /* group */ - __le32 sd_atime; /* time of last access */ - __le32 sd_mtime; /* time file was last modified */ - __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ - __le32 sd_blocks; - union { - __le32 sd_rdev; - __le32 sd_generation; - //__le32 sd_first_direct_byte; - /* first byte of file which is stored in a - direct item: except that if it equals 1 - it is a symlink and if it equals - ~(__u32)0 there is no direct item. The - existence of this field really grates - on me. Let's replace it with a macro - based on sd_size and our tail - suppression policy? */ - } __attribute__ ((__packed__)) u; -} __attribute__ ((__packed__)); -// -// this is 44 bytes long -// -#define SD_SIZE (sizeof(struct stat_data)) -#define SD_V2_SIZE SD_SIZE -#define stat_data_v2(ih) (ih_version (ih) == KEY_FORMAT_3_6) -#define sd_v2_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) -#define set_sd_v2_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) -/* sd_reserved */ -/* set_sd_reserved */ -#define sd_v2_nlink(sdp) (le32_to_cpu((sdp)->sd_nlink)) -#define set_sd_v2_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le32(v)) -#define sd_v2_size(sdp) (le64_to_cpu((sdp)->sd_size)) -#define set_sd_v2_size(sdp,v) ((sdp)->sd_size = cpu_to_le64(v)) -#define sd_v2_uid(sdp) (le32_to_cpu((sdp)->sd_uid)) -#define set_sd_v2_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le32(v)) -#define sd_v2_gid(sdp) (le32_to_cpu((sdp)->sd_gid)) -#define set_sd_v2_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le32(v)) -#define sd_v2_atime(sdp) (le32_to_cpu((sdp)->sd_atime)) -#define set_sd_v2_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v)) -#define sd_v2_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime)) -#define set_sd_v2_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v)) -#define sd_v2_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime)) -#define set_sd_v2_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v)) -#define sd_v2_blocks(sdp) (le32_to_cpu((sdp)->sd_blocks)) -#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v)) -#define sd_v2_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev)) -#define set_sd_v2_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v)) -#define sd_v2_generation(sdp) (le32_to_cpu((sdp)->u.sd_generation)) -#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v)) -#define sd_v2_attrs(sdp) (le16_to_cpu((sdp)->sd_attrs)) -#define set_sd_v2_attrs(sdp,v) ((sdp)->sd_attrs = cpu_to_le16(v)) - -/***************************************************************************/ -/* DIRECTORY STRUCTURE */ -/***************************************************************************/ -/* - Picture represents the structure of directory items - ________________________________________________ - | Array of | | | | | | - | directory |N-1| N-2 | .... | 1st |0th| - | entry headers | | | | | | - |_______________|___|_____|________|_______|___| - <---- directory entries ------> - - First directory item has k_offset component 1. We store "." and ".." - in one item, always, we never split "." and ".." into differing - items. This makes, among other things, the code for removing - directories simpler. */ -#define SD_OFFSET 0 -#define SD_UNIQUENESS 0 -#define DOT_OFFSET 1 -#define DOT_DOT_OFFSET 2 -#define DIRENTRY_UNIQUENESS 500 - -/* */ -#define FIRST_ITEM_OFFSET 1 - -/* - Q: How to get key of object pointed to by entry from entry? - - A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key - of object, entry points to */ - -/* NOT IMPLEMENTED: - Directory will someday contain stat data of object */ - -struct reiserfs_de_head { - __le32 deh_offset; /* third component of the directory entry key */ - __le32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced - by directory entry */ - __le32 deh_objectid; /* objectid of the object, that is referenced by directory entry */ - __le16 deh_location; /* offset of name in the whole item */ - __le16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether - entry is hidden (unlinked) */ -} __attribute__ ((__packed__)); -#define DEH_SIZE sizeof(struct reiserfs_de_head) -#define deh_offset(p_deh) (le32_to_cpu((p_deh)->deh_offset)) -#define deh_dir_id(p_deh) (le32_to_cpu((p_deh)->deh_dir_id)) -#define deh_objectid(p_deh) (le32_to_cpu((p_deh)->deh_objectid)) -#define deh_location(p_deh) (le16_to_cpu((p_deh)->deh_location)) -#define deh_state(p_deh) (le16_to_cpu((p_deh)->deh_state)) - -#define put_deh_offset(p_deh,v) ((p_deh)->deh_offset = cpu_to_le32((v))) -#define put_deh_dir_id(p_deh,v) ((p_deh)->deh_dir_id = cpu_to_le32((v))) -#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v))) -#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v))) -#define put_deh_state(p_deh,v) ((p_deh)->deh_state = cpu_to_le16((v))) - -/* empty directory contains two entries "." and ".." and their headers */ -#define EMPTY_DIR_SIZE \ -(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen (".."))) - -/* old format directories have this size when empty */ -#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3) - -#define DEH_Statdata 0 /* not used now */ -#define DEH_Visible 2 - -/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */ -#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__) -# define ADDR_UNALIGNED_BITS (3) -#endif - -/* These are only used to manipulate deh_state. - * Because of this, we'll use the ext2_ bit routines, - * since they are little endian */ -#ifdef ADDR_UNALIGNED_BITS - -# define aligned_address(addr) ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1))) -# define unaligned_offset(addr) (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3) - -# define set_bit_unaligned(nr, addr) \ - __test_and_set_bit_le((nr) + unaligned_offset(addr), aligned_address(addr)) -# define clear_bit_unaligned(nr, addr) \ - __test_and_clear_bit_le((nr) + unaligned_offset(addr), aligned_address(addr)) -# define test_bit_unaligned(nr, addr) \ - test_bit_le((nr) + unaligned_offset(addr), aligned_address(addr)) - -#else - -# define set_bit_unaligned(nr, addr) __test_and_set_bit_le(nr, addr) -# define clear_bit_unaligned(nr, addr) __test_and_clear_bit_le(nr, addr) -# define test_bit_unaligned(nr, addr) test_bit_le(nr, addr) - -#endif - -#define mark_de_with_sd(deh) set_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) -#define mark_de_without_sd(deh) clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) -#define mark_de_visible(deh) set_bit_unaligned (DEH_Visible, &((deh)->deh_state)) -#define mark_de_hidden(deh) clear_bit_unaligned (DEH_Visible, &((deh)->deh_state)) - -#define de_with_sd(deh) test_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) -#define de_visible(deh) test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) -#define de_hidden(deh) !test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) - -extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid, - __le32 par_dirid, __le32 par_objid); -extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid, - __le32 par_dirid, __le32 par_objid); - -/* array of the entry headers */ - /* get item body */ -#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) ) -#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih))) - -/* length of the directory entry in directory item. This define - calculates length of i-th directory entry using directory entry - locations from dir entry head. When it calculates length of 0-th - directory entry, it uses length of whole item in place of entry - location of the non-existent following entry in the calculation. - See picture above.*/ -/* -#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \ -((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh)))) -*/ -static inline int entry_length(const struct buffer_head *bh, - const struct item_head *ih, int pos_in_item) -{ - struct reiserfs_de_head *deh; - - deh = B_I_DEH(bh, ih) + pos_in_item; - if (pos_in_item) - return deh_location(deh - 1) - deh_location(deh); - - return ih_item_len(ih) - deh_location(deh); -} - -/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */ -#define I_ENTRY_COUNT(ih) (ih_entry_count((ih))) - -/* name by bh, ih and entry_num */ -#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num)))) - -// two entries per block (at least) -#define REISERFS_MAX_NAME(block_size) 255 - -/* this structure is used for operations on directory entries. It is - not a disk structure. */ -/* When reiserfs_find_entry or search_by_entry_key find directory - entry, they return filled reiserfs_dir_entry structure */ -struct reiserfs_dir_entry { - struct buffer_head *de_bh; - int de_item_num; - struct item_head *de_ih; - int de_entry_num; - struct reiserfs_de_head *de_deh; - int de_entrylen; - int de_namelen; - char *de_name; - unsigned long *de_gen_number_bit_string; - - __u32 de_dir_id; - __u32 de_objectid; - - struct cpu_key de_entry_key; -}; - -/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */ - -/* pointer to file name, stored in entry */ -#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh)) - -/* length of name */ -#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \ -(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0)) - -/* hash value occupies bits from 7 up to 30 */ -#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL) -/* generation number occupies 7 bits starting from 0 up to 6 */ -#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL) -#define MAX_GENERATION_NUMBER 127 - -#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number)) - -/* - * Picture represents an internal node of the reiserfs tree - * ______________________________________________________ - * | | Array of | Array of | Free | - * |block | keys | pointers | space | - * | head | N | N+1 | | - * |______|_______________|___________________|___________| - */ - -/***************************************************************************/ -/* DISK CHILD */ -/***************************************************************************/ -/* Disk child pointer: The pointer from an internal node of the tree - to a node that is on disk. */ -struct disk_child { - __le32 dc_block_number; /* Disk child's block number. */ - __le16 dc_size; /* Disk child's used space. */ - __le16 dc_reserved; -}; - -#define DC_SIZE (sizeof(struct disk_child)) -#define dc_block_number(dc_p) (le32_to_cpu((dc_p)->dc_block_number)) -#define dc_size(dc_p) (le16_to_cpu((dc_p)->dc_size)) -#define put_dc_block_number(dc_p, val) do { (dc_p)->dc_block_number = cpu_to_le32(val); } while(0) -#define put_dc_size(dc_p, val) do { (dc_p)->dc_size = cpu_to_le16(val); } while(0) - -/* Get disk child by buffer header and position in the tree node. */ -#define B_N_CHILD(bh, n_pos) ((struct disk_child *)\ -((bh)->b_data + BLKH_SIZE + B_NR_ITEMS(bh) * KEY_SIZE + DC_SIZE * (n_pos))) - -/* Get disk child number by buffer header and position in the tree node. */ -#define B_N_CHILD_NUM(bh, n_pos) (dc_block_number(B_N_CHILD(bh, n_pos))) -#define PUT_B_N_CHILD_NUM(bh, n_pos, val) \ - (put_dc_block_number(B_N_CHILD(bh, n_pos), val)) - - /* maximal value of field child_size in structure disk_child */ - /* child size is the combined size of all items and their headers */ -#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE )) - -/* amount of used space in buffer (not including block head) */ -#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur))) - -/* max and min number of keys in internal node */ -#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) ) -#define MIN_NR_KEY(bh) (MAX_NR_KEY(bh)/2) - -/***************************************************************************/ -/* PATH STRUCTURES AND DEFINES */ -/***************************************************************************/ - -/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the - key. It uses reiserfs_bread to try to find buffers in the cache given their block number. If it - does not find them in the cache it reads them from disk. For each node search_by_key finds using - reiserfs_bread it then uses bin_search to look through that node. bin_search will find the - position of the block_number of the next node if it is looking through an internal node. If it - is looking through a leaf node bin_search will find the position of the item which has key either - equal to given key, or which is the maximal key less than the given key. */ - -struct path_element { - struct buffer_head *pe_buffer; /* Pointer to the buffer at the path in the tree. */ - int pe_position; /* Position in the tree node which is placed in the */ - /* buffer above. */ -}; - -#define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */ -#define EXTENDED_MAX_HEIGHT 7 /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */ -#define FIRST_PATH_ELEMENT_OFFSET 2 /* Must be equal to at least 2. */ - -#define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */ -#define MAX_FEB_SIZE 6 /* this MUST be MAX_HEIGHT + 1. See about FEB below */ - -/* We need to keep track of who the ancestors of nodes are. When we - perform a search we record which nodes were visited while - descending the tree looking for the node we searched for. This list - of nodes is called the path. This information is used while - performing balancing. Note that this path information may become - invalid, and this means we must check it when using it to see if it - is still valid. You'll need to read search_by_key and the comments - in it, especially about decrement_counters_in_path(), to understand - this structure. - -Paths make the code so much harder to work with and debug.... An -enormous number of bugs are due to them, and trying to write or modify -code that uses them just makes my head hurt. They are based on an -excessive effort to avoid disturbing the precious VFS code.:-( The -gods only know how we are going to SMP the code that uses them. -znodes are the way! */ - -#define PATH_READA 0x1 /* do read ahead */ -#define PATH_READA_BACK 0x2 /* read backwards */ - -struct treepath { - int path_length; /* Length of the array above. */ - int reada; - struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */ - int pos_in_item; -}; - -#define pos_in_item(path) ((path)->pos_in_item) - -#define INITIALIZE_PATH(var) \ -struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,} - -/* Get path element by path and path position. */ -#define PATH_OFFSET_PELEMENT(path, n_offset) ((path)->path_elements + (n_offset)) - -/* Get buffer header at the path by path and path position. */ -#define PATH_OFFSET_PBUFFER(path, n_offset) (PATH_OFFSET_PELEMENT(path, n_offset)->pe_buffer) - -/* Get position in the element at the path by path and path position. */ -#define PATH_OFFSET_POSITION(path, n_offset) (PATH_OFFSET_PELEMENT(path, n_offset)->pe_position) - -#define PATH_PLAST_BUFFER(path) (PATH_OFFSET_PBUFFER((path), (path)->path_length)) - /* you know, to the person who didn't - write this the macro name does not - at first suggest what it does. - Maybe POSITION_FROM_PATH_END? Or - maybe we should just focus on - dumping paths... -Hans */ -#define PATH_LAST_POSITION(path) (PATH_OFFSET_POSITION((path), (path)->path_length)) - -#define PATH_PITEM_HEAD(path) B_N_PITEM_HEAD(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION(path)) - -/* in do_balance leaf has h == 0 in contrast with path structure, - where root has level == 0. That is why we need these defines */ -#define PATH_H_PBUFFER(path, h) PATH_OFFSET_PBUFFER (path, path->path_length - (h)) /* tb->S[h] */ -#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */ -#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h)) -#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1) /* tb->S[h]->b_item_order */ - -#define PATH_H_PATH_OFFSET(path, n_h) ((path)->path_length - (n_h)) - -#define get_last_bh(path) PATH_PLAST_BUFFER(path) -#define get_ih(path) PATH_PITEM_HEAD(path) -#define get_item_pos(path) PATH_LAST_POSITION(path) -#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path))) -#define item_moved(ih,path) comp_items(ih, path) -#define path_changed(ih,path) comp_items (ih, path) - -/***************************************************************************/ -/* MISC */ -/***************************************************************************/ - -/* Size of pointer to the unformatted node. */ -#define UNFM_P_SIZE (sizeof(unp_t)) -#define UNFM_P_SHIFT 2 - -// in in-core inode key is stored on le form -#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key)) - -#define MAX_UL_INT 0xffffffff -#define MAX_INT 0x7ffffff -#define MAX_US_INT 0xffff - -// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset -#define U32_MAX (~(__u32)0) - -static inline loff_t max_reiserfs_offset(struct inode *inode) -{ - if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5) - return (loff_t) U32_MAX; - - return (loff_t) ((~(__u64) 0) >> 4); -} - -/*#define MAX_KEY_UNIQUENESS MAX_UL_INT*/ -#define MAX_KEY_OBJECTID MAX_UL_INT - -#define MAX_B_NUM MAX_UL_INT -#define MAX_FC_NUM MAX_US_INT - -/* the purpose is to detect overflow of an unsigned short */ -#define REISERFS_LINK_MAX (MAX_US_INT - 1000) - -/* The following defines are used in reiserfs_insert_item and reiserfs_append_item */ -#define REISERFS_KERNEL_MEM 0 /* reiserfs kernel memory mode */ -#define REISERFS_USER_MEM 1 /* reiserfs user memory mode */ - -#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter) -#define get_generation(s) atomic_read (&fs_generation(s)) -#define FILESYSTEM_CHANGED_TB(tb) (get_generation((tb)->tb_sb) != (tb)->fs_gen) -#define __fs_changed(gen,s) (gen != get_generation (s)) -#define fs_changed(gen,s) \ -({ \ - reiserfs_cond_resched(s); \ - __fs_changed(gen, s); \ -}) - -/***************************************************************************/ -/* FIXATE NODES */ -/***************************************************************************/ - -#define VI_TYPE_LEFT_MERGEABLE 1 -#define VI_TYPE_RIGHT_MERGEABLE 2 - -/* To make any changes in the tree we always first find node, that - contains item to be changed/deleted or place to insert a new - item. We call this node S. To do balancing we need to decide what - we will shift to left/right neighbor, or to a new node, where new - item will be etc. To make this analysis simpler we build virtual - node. Virtual node is an array of items, that will replace items of - node S. (For instance if we are going to delete an item, virtual - node does not contain it). Virtual node keeps information about - item sizes and types, mergeability of first and last items, sizes - of all entries in directory item. We use this array of items when - calculating what we can shift to neighbors and how many nodes we - have to have if we do not any shiftings, if we shift to left/right - neighbor or to both. */ -struct virtual_item { - int vi_index; // index in the array of item operations - unsigned short vi_type; // left/right mergeability - unsigned short vi_item_len; /* length of item that it will have after balancing */ - struct item_head *vi_ih; - const char *vi_item; // body of item (old or new) - const void *vi_new_data; // 0 always but paste mode - void *vi_uarea; // item specific area -}; - -struct virtual_node { - char *vn_free_ptr; /* this is a pointer to the free space in the buffer */ - unsigned short vn_nr_item; /* number of items in virtual node */ - short vn_size; /* size of node , that node would have if it has unlimited size and no balancing is performed */ - short vn_mode; /* mode of balancing (paste, insert, delete, cut) */ - short vn_affected_item_num; - short vn_pos_in_item; - struct item_head *vn_ins_ih; /* item header of inserted item, 0 for other modes */ - const void *vn_data; - struct virtual_item *vn_vi; /* array of items (including a new one, excluding item to be deleted) */ -}; - -/* used by directory items when creating virtual nodes */ -struct direntry_uarea { - int flags; - __u16 entry_count; - __u16 entry_sizes[1]; -} __attribute__ ((__packed__)); - -/***************************************************************************/ -/* TREE BALANCE */ -/***************************************************************************/ - -/* This temporary structure is used in tree balance algorithms, and - constructed as we go to the extent that its various parts are - needed. It contains arrays of nodes that can potentially be - involved in the balancing of node S, and parameters that define how - each of the nodes must be balanced. Note that in these algorithms - for balancing the worst case is to need to balance the current node - S and the left and right neighbors and all of their parents plus - create a new node. We implement S1 balancing for the leaf nodes - and S0 balancing for the internal nodes (S1 and S0 are defined in - our papers.)*/ - -#define MAX_FREE_BLOCK 7 /* size of the array of buffers to free at end of do_balance */ - -/* maximum number of FEB blocknrs on a single level */ -#define MAX_AMOUNT_NEEDED 2 - -/* someday somebody will prefix every field in this struct with tb_ */ -struct tree_balance { - int tb_mode; - int need_balance_dirty; - struct super_block *tb_sb; - struct reiserfs_transaction_handle *transaction_handle; - struct treepath *tb_path; - struct buffer_head *L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */ - struct buffer_head *R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path */ - struct buffer_head *FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */ - struct buffer_head *FR[MAX_HEIGHT]; /* array of fathers of the right neighbors */ - struct buffer_head *CFL[MAX_HEIGHT]; /* array of common parents of center node and its left neighbor */ - struct buffer_head *CFR[MAX_HEIGHT]; /* array of common parents of center node and its right neighbor */ - - struct buffer_head *FEB[MAX_FEB_SIZE]; /* array of empty buffers. Number of buffers in array equals - cur_blknum. */ - struct buffer_head *used[MAX_FEB_SIZE]; - struct buffer_head *thrown[MAX_FEB_SIZE]; - int lnum[MAX_HEIGHT]; /* array of number of items which must be - shifted to the left in order to balance the - current node; for leaves includes item that - will be partially shifted; for internal - nodes, it is the number of child pointers - rather than items. It includes the new item - being created. The code sometimes subtracts - one to get the number of wholly shifted - items for other purposes. */ - int rnum[MAX_HEIGHT]; /* substitute right for left in comment above */ - int lkey[MAX_HEIGHT]; /* array indexed by height h mapping the key delimiting L[h] and - S[h] to its item number within the node CFL[h] */ - int rkey[MAX_HEIGHT]; /* substitute r for l in comment above */ - int insert_size[MAX_HEIGHT]; /* the number of bytes by we are trying to add or remove from - S[h]. A negative value means removing. */ - int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after - balancing on the level h of the tree. If 0 then S is - being deleted, if 1 then S is remaining and no new nodes - are being created, if 2 or 3 then 1 or 2 new nodes is - being created */ - - /* fields that are used only for balancing leaves of the tree */ - int cur_blknum; /* number of empty blocks having been already allocated */ - int s0num; /* number of items that fall into left most node when S[0] splits */ - int s1num; /* number of items that fall into first new node when S[0] splits */ - int s2num; /* number of items that fall into second new node when S[0] splits */ - int lbytes; /* number of bytes which can flow to the left neighbor from the left */ - /* most liquid item that cannot be shifted from S[0] entirely */ - /* if -1 then nothing will be partially shifted */ - int rbytes; /* number of bytes which will flow to the right neighbor from the right */ - /* most liquid item that cannot be shifted from S[0] entirely */ - /* if -1 then nothing will be partially shifted */ - int s1bytes; /* number of bytes which flow to the first new node when S[0] splits */ - /* note: if S[0] splits into 3 nodes, then items do not need to be cut */ - int s2bytes; - struct buffer_head *buf_to_free[MAX_FREE_BLOCK]; /* buffers which are to be freed after do_balance finishes by unfix_nodes */ - char *vn_buf; /* kmalloced memory. Used to create - virtual node and keep map of - dirtied bitmap blocks */ - int vn_buf_size; /* size of the vn_buf */ - struct virtual_node *tb_vn; /* VN starts after bitmap of bitmap blocks */ - - int fs_gen; /* saved value of `reiserfs_generation' counter - see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */ -#ifdef DISPLACE_NEW_PACKING_LOCALITIES - struct in_core_key key; /* key pointer, to pass to block allocator or - another low-level subsystem */ -#endif -}; - -/* These are modes of balancing */ - -/* When inserting an item. */ -#define M_INSERT 'i' -/* When inserting into (directories only) or appending onto an already - existent item. */ -#define M_PASTE 'p' -/* When deleting an item. */ -#define M_DELETE 'd' -/* When truncating an item or removing an entry from a (directory) item. */ -#define M_CUT 'c' - -/* used when balancing on leaf level skipped (in reiserfsck) */ -#define M_INTERNAL 'n' - -/* When further balancing is not needed, then do_balance does not need - to be called. */ -#define M_SKIP_BALANCING 's' -#define M_CONVERT 'v' - -/* modes of leaf_move_items */ -#define LEAF_FROM_S_TO_L 0 -#define LEAF_FROM_S_TO_R 1 -#define LEAF_FROM_R_TO_L 2 -#define LEAF_FROM_L_TO_R 3 -#define LEAF_FROM_S_TO_SNEW 4 - -#define FIRST_TO_LAST 0 -#define LAST_TO_FIRST 1 - -/* used in do_balance for passing parent of node information that has - been gotten from tb struct */ -struct buffer_info { - struct tree_balance *tb; - struct buffer_head *bi_bh; - struct buffer_head *bi_parent; - int bi_position; -}; - -static inline struct super_block *sb_from_tb(struct tree_balance *tb) -{ - return tb ? tb->tb_sb : NULL; -} - -static inline struct super_block *sb_from_bi(struct buffer_info *bi) -{ - return bi ? sb_from_tb(bi->tb) : NULL; -} - -/* there are 4 types of items: stat data, directory item, indirect, direct. -+-------------------+------------+--------------+------------+ -| | k_offset | k_uniqueness | mergeable? | -+-------------------+------------+--------------+------------+ -| stat data | 0 | 0 | no | -+-------------------+------------+--------------+------------+ -| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS| no | -| non 1st directory | hash value | | yes | -| item | | | | -+-------------------+------------+--------------+------------+ -| indirect item | offset + 1 |TYPE_INDIRECT | if this is not the first indirect item of the object -+-------------------+------------+--------------+------------+ -| direct item | offset + 1 |TYPE_DIRECT | if not this is not the first direct item of the object -+-------------------+------------+--------------+------------+ -*/ - -struct item_operations { - int (*bytes_number) (struct item_head * ih, int block_size); - void (*decrement_key) (struct cpu_key *); - int (*is_left_mergeable) (struct reiserfs_key * ih, - unsigned long bsize); - void (*print_item) (struct item_head *, char *item); - void (*check_item) (struct item_head *, char *item); - - int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi, - int is_affected, int insert_size); - int (*check_left) (struct virtual_item * vi, int free, - int start_skip, int end_skip); - int (*check_right) (struct virtual_item * vi, int free); - int (*part_size) (struct virtual_item * vi, int from, int to); - int (*unit_num) (struct virtual_item * vi); - void (*print_vi) (struct virtual_item * vi); -}; - -extern struct item_operations *item_ops[TYPE_ANY + 1]; - -#define op_bytes_number(ih,bsize) item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize) -#define op_is_left_mergeable(key,bsize) item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize) -#define op_print_item(ih,item) item_ops[le_ih_k_type (ih)]->print_item (ih, item) -#define op_check_item(ih,item) item_ops[le_ih_k_type (ih)]->check_item (ih, item) -#define op_create_vi(vn,vi,is_affected,insert_size) item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size) -#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip) -#define op_check_right(vi,free) item_ops[(vi)->vi_index]->check_right (vi, free) -#define op_part_size(vi,from,to) item_ops[(vi)->vi_index]->part_size (vi, from, to) -#define op_unit_num(vi) item_ops[(vi)->vi_index]->unit_num (vi) -#define op_print_vi(vi) item_ops[(vi)->vi_index]->print_vi (vi) - -#define COMP_SHORT_KEYS comp_short_keys - -/* number of blocks pointed to by the indirect item */ -#define I_UNFM_NUM(ih) (ih_item_len(ih) / UNFM_P_SIZE) - -/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */ -#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size)) - -/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */ - -/* get the item header */ -#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) ) - -/* get key */ -#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) ) - -/* get the key */ -#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) ) - -/* get item body */ -#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num)))) - -/* get the stat data by the buffer header and the item order */ -#define B_N_STAT_DATA(bh,nr) \ -( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) ) - - /* following defines use reiserfs buffer header and item header */ - -/* get stat-data */ -#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) ) - -// this is 3976 for size==4096 -#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE) - -/* indirect items consist of entries which contain blocknrs, pos - indicates which entry, and B_I_POS_UNFM_POINTER resolves to the - blocknr contained by the entry pos points to */ -#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos))) -#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0) - -struct reiserfs_iget_args { - __u32 objectid; - __u32 dirid; -}; - -/***************************************************************************/ -/* FUNCTION DECLARATIONS */ -/***************************************************************************/ - -#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12) - -#define journal_trans_half(blocksize) \ - ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32)) - -/* journal.c see journal.c for all the comments here */ - -/* first block written in a commit. */ -struct reiserfs_journal_desc { - __le32 j_trans_id; /* id of commit */ - __le32 j_len; /* length of commit. len +1 is the commit block */ - __le32 j_mount_id; /* mount id of this trans */ - __le32 j_realblock[1]; /* real locations for each block */ -}; - -#define get_desc_trans_id(d) le32_to_cpu((d)->j_trans_id) -#define get_desc_trans_len(d) le32_to_cpu((d)->j_len) -#define get_desc_mount_id(d) le32_to_cpu((d)->j_mount_id) - -#define set_desc_trans_id(d,val) do { (d)->j_trans_id = cpu_to_le32 (val); } while (0) -#define set_desc_trans_len(d,val) do { (d)->j_len = cpu_to_le32 (val); } while (0) -#define set_desc_mount_id(d,val) do { (d)->j_mount_id = cpu_to_le32 (val); } while (0) - -/* last block written in a commit */ -struct reiserfs_journal_commit { - __le32 j_trans_id; /* must match j_trans_id from the desc block */ - __le32 j_len; /* ditto */ - __le32 j_realblock[1]; /* real locations for each block */ -}; - -#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id) -#define get_commit_trans_len(c) le32_to_cpu((c)->j_len) -#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id) - -#define set_commit_trans_id(c,val) do { (c)->j_trans_id = cpu_to_le32 (val); } while (0) -#define set_commit_trans_len(c,val) do { (c)->j_len = cpu_to_le32 (val); } while (0) - -/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the -** last fully flushed transaction. fully flushed means all the log blocks and all the real blocks are on disk, -** and this transaction does not need to be replayed. -*/ -struct reiserfs_journal_header { - __le32 j_last_flush_trans_id; /* id of last fully flushed transaction */ - __le32 j_first_unflushed_offset; /* offset in the log of where to start replay after a crash */ - __le32 j_mount_id; - /* 12 */ struct journal_params jh_journal; -}; - -/* biggest tunable defines are right here */ -#define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */ -#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */ -#define JOURNAL_TRANS_MIN_DEFAULT 256 -#define JOURNAL_MAX_BATCH_DEFAULT 900 /* max blocks to batch into one transaction, don't make this any bigger than 900 */ -#define JOURNAL_MIN_RATIO 2 -#define JOURNAL_MAX_COMMIT_AGE 30 -#define JOURNAL_MAX_TRANS_AGE 30 -#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9) -#define JOURNAL_BLOCKS_PER_OBJECT(sb) (JOURNAL_PER_BALANCE_CNT * 3 + \ - 2 * (REISERFS_QUOTA_INIT_BLOCKS(sb) + \ - REISERFS_QUOTA_TRANS_BLOCKS(sb))) - -#ifdef CONFIG_QUOTA -#define REISERFS_QUOTA_OPTS ((1 << REISERFS_USRQUOTA) | (1 << REISERFS_GRPQUOTA)) -/* We need to update data and inode (atime) */ -#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? 2 : 0) -/* 1 balancing, 1 bitmap, 1 data per write + stat data update */ -#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \ -(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0) -/* same as with INIT */ -#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \ -(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0) -#else -#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0 -#define REISERFS_QUOTA_INIT_BLOCKS(s) 0 -#define REISERFS_QUOTA_DEL_BLOCKS(s) 0 -#endif - -/* both of these can be as low as 1, or as high as you want. The min is the -** number of 4k bitmap nodes preallocated on mount. New nodes are allocated -** as needed, and released when transactions are committed. On release, if -** the current number of nodes is > max, the node is freed, otherwise, -** it is put on a free list for faster use later. -*/ -#define REISERFS_MIN_BITMAP_NODES 10 -#define REISERFS_MAX_BITMAP_NODES 100 - -#define JBH_HASH_SHIFT 13 /* these are based on journal hash size of 8192 */ -#define JBH_HASH_MASK 8191 - -#define _jhashfn(sb,block) \ - (((unsigned long)sb>>L1_CACHE_SHIFT) ^ \ - (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12)))) -#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK]) - -// We need these to make journal.c code more readable -#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) -#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) -#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) - -enum reiserfs_bh_state_bits { - BH_JDirty = BH_PrivateStart, /* buffer is in current transaction */ - BH_JDirty_wait, - BH_JNew, /* disk block was taken off free list before - * being in a finished transaction, or - * written to disk. Can be reused immed. */ - BH_JPrepared, - BH_JRestore_dirty, - BH_JTest, // debugging only will go away -}; - -BUFFER_FNS(JDirty, journaled); -TAS_BUFFER_FNS(JDirty, journaled); -BUFFER_FNS(JDirty_wait, journal_dirty); -TAS_BUFFER_FNS(JDirty_wait, journal_dirty); -BUFFER_FNS(JNew, journal_new); -TAS_BUFFER_FNS(JNew, journal_new); -BUFFER_FNS(JPrepared, journal_prepared); -TAS_BUFFER_FNS(JPrepared, journal_prepared); -BUFFER_FNS(JRestore_dirty, journal_restore_dirty); -TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty); -BUFFER_FNS(JTest, journal_test); -TAS_BUFFER_FNS(JTest, journal_test); - -/* -** transaction handle which is passed around for all journal calls -*/ -struct reiserfs_transaction_handle { - struct super_block *t_super; /* super for this FS when journal_begin was - called. saves calls to reiserfs_get_super - also used by nested transactions to make - sure they are nesting on the right FS - _must_ be first in the handle - */ - int t_refcount; - int t_blocks_logged; /* number of blocks this writer has logged */ - int t_blocks_allocated; /* number of blocks this writer allocated */ - unsigned int t_trans_id; /* sanity check, equals the current trans id */ - void *t_handle_save; /* save existing current->journal_info */ - unsigned displace_new_blocks:1; /* if new block allocation occurres, that block - should be displaced from others */ - struct list_head t_list; -}; - -/* used to keep track of ordered and tail writes, attached to the buffer - * head through b_journal_head. - */ -struct reiserfs_jh { - struct reiserfs_journal_list *jl; - struct buffer_head *bh; - struct list_head list; -}; - -void reiserfs_free_jh(struct buffer_head *bh); -int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh); -int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh); -int journal_mark_dirty(struct reiserfs_transaction_handle *, - struct super_block *, struct buffer_head *bh); - -static inline int reiserfs_file_data_log(struct inode *inode) -{ - if (reiserfs_data_log(inode->i_sb) || - (REISERFS_I(inode)->i_flags & i_data_log)) - return 1; - return 0; -} - -static inline int reiserfs_transaction_running(struct super_block *s) -{ - struct reiserfs_transaction_handle *th = current->journal_info; - if (th && th->t_super == s) - return 1; - if (th && th->t_super == NULL) - BUG(); - return 0; -} - -static inline int reiserfs_transaction_free_space(struct reiserfs_transaction_handle *th) -{ - return th->t_blocks_allocated - th->t_blocks_logged; -} - -struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct - super_block - *, - int count); -int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *); -int reiserfs_commit_page(struct inode *inode, struct page *page, - unsigned from, unsigned to); -int reiserfs_flush_old_commits(struct super_block *); -int reiserfs_commit_for_inode(struct inode *); -int reiserfs_inode_needs_commit(struct inode *); -void reiserfs_update_inode_transaction(struct inode *); -void reiserfs_wait_on_write_block(struct super_block *s); -void reiserfs_block_writes(struct reiserfs_transaction_handle *th); -void reiserfs_allow_writes(struct super_block *s); -void reiserfs_check_lock_depth(struct super_block *s, char *caller); -int reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh, - int wait); -void reiserfs_restore_prepared_buffer(struct super_block *, - struct buffer_head *bh); -int journal_init(struct super_block *, const char *j_dev_name, int old_format, - unsigned int); -int journal_release(struct reiserfs_transaction_handle *, struct super_block *); -int journal_release_error(struct reiserfs_transaction_handle *, - struct super_block *); -int journal_end(struct reiserfs_transaction_handle *, struct super_block *, - unsigned long); -int journal_end_sync(struct reiserfs_transaction_handle *, struct super_block *, - unsigned long); -int journal_mark_freed(struct reiserfs_transaction_handle *, - struct super_block *, b_blocknr_t blocknr); -int journal_transaction_should_end(struct reiserfs_transaction_handle *, int); -int reiserfs_in_journal(struct super_block *sb, unsigned int bmap_nr, - int bit_nr, int searchall, b_blocknr_t *next); -int journal_begin(struct reiserfs_transaction_handle *, - struct super_block *sb, unsigned long); -int journal_join_abort(struct reiserfs_transaction_handle *, - struct super_block *sb, unsigned long); -void reiserfs_abort_journal(struct super_block *sb, int errno); -void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...); -int reiserfs_allocate_list_bitmaps(struct super_block *s, - struct reiserfs_list_bitmap *, unsigned int); - -void add_save_link(struct reiserfs_transaction_handle *th, - struct inode *inode, int truncate); -int remove_save_link(struct inode *inode, int truncate); - -/* objectid.c */ -__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th); -void reiserfs_release_objectid(struct reiserfs_transaction_handle *th, - __u32 objectid_to_release); -int reiserfs_convert_objectid_map_v1(struct super_block *); - -/* stree.c */ -int B_IS_IN_TREE(const struct buffer_head *); -extern void copy_item_head(struct item_head *to, - const struct item_head *from); - -// first key is in cpu form, second - le -extern int comp_short_keys(const struct reiserfs_key *le_key, - const struct cpu_key *cpu_key); -extern void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from); - -// both are in le form -extern int comp_le_keys(const struct reiserfs_key *, - const struct reiserfs_key *); -extern int comp_short_le_keys(const struct reiserfs_key *, - const struct reiserfs_key *); - -// -// get key version from on disk key - kludge -// -static inline int le_key_version(const struct reiserfs_key *key) -{ - int type; - - type = offset_v2_k_type(&(key->u.k_offset_v2)); - if (type != TYPE_DIRECT && type != TYPE_INDIRECT - && type != TYPE_DIRENTRY) - return KEY_FORMAT_3_5; - - return KEY_FORMAT_3_6; - -} - -static inline void copy_key(struct reiserfs_key *to, - const struct reiserfs_key *from) -{ - memcpy(to, from, KEY_SIZE); -} - -int comp_items(const struct item_head *stored_ih, const struct treepath *path); -const struct reiserfs_key *get_rkey(const struct treepath *chk_path, - const struct super_block *sb); -int search_by_key(struct super_block *, const struct cpu_key *, - struct treepath *, int); -#define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL) -int search_for_position_by_key(struct super_block *sb, - const struct cpu_key *cpu_key, - struct treepath *search_path); -extern void decrement_bcount(struct buffer_head *bh); -void decrement_counters_in_path(struct treepath *search_path); -void pathrelse(struct treepath *search_path); -int reiserfs_check_path(struct treepath *p); -void pathrelse_and_restore(struct super_block *s, struct treepath *search_path); - -int reiserfs_insert_item(struct reiserfs_transaction_handle *th, - struct treepath *path, - const struct cpu_key *key, - struct item_head *ih, - struct inode *inode, const char *body); - -int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, - struct treepath *path, - const struct cpu_key *key, - struct inode *inode, - const char *body, int paste_size); - -int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th, - struct treepath *path, - struct cpu_key *key, - struct inode *inode, - struct page *page, loff_t new_file_size); - -int reiserfs_delete_item(struct reiserfs_transaction_handle *th, - struct treepath *path, - const struct cpu_key *key, - struct inode *inode, struct buffer_head *un_bh); - -void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th, - struct inode *inode, struct reiserfs_key *key); -int reiserfs_delete_object(struct reiserfs_transaction_handle *th, - struct inode *inode); -int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, - struct inode *inode, struct page *, - int update_timestamps); - -#define i_block_size(inode) ((inode)->i_sb->s_blocksize) -#define file_size(inode) ((inode)->i_size) -#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1)) - -#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\ -!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 ) - -void padd_item(char *item, int total_length, int length); - -/* inode.c */ -/* args for the create parameter of reiserfs_get_block */ -#define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */ -#define GET_BLOCK_CREATE 1 /* add anything you need to find block */ -#define GET_BLOCK_NO_HOLE 2 /* return -ENOENT for file holes */ -#define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */ -#define GET_BLOCK_NO_IMUX 8 /* i_mutex is not held, don't preallocate */ -#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */ - -void reiserfs_read_locked_inode(struct inode *inode, - struct reiserfs_iget_args *args); -int reiserfs_find_actor(struct inode *inode, void *p); -int reiserfs_init_locked_inode(struct inode *inode, void *p); -void reiserfs_evict_inode(struct inode *inode); -int reiserfs_write_inode(struct inode *inode, struct writeback_control *wbc); -int reiserfs_get_block(struct inode *inode, sector_t block, - struct buffer_head *bh_result, int create); -struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type); -struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type); -int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp, - int connectable); - -int reiserfs_truncate_file(struct inode *, int update_timestamps); -void make_cpu_key(struct cpu_key *cpu_key, struct inode *inode, loff_t offset, - int type, int key_length); -void make_le_item_head(struct item_head *ih, const struct cpu_key *key, - int version, - loff_t offset, int type, int length, int entry_count); -struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key); - -struct reiserfs_security_handle; -int reiserfs_new_inode(struct reiserfs_transaction_handle *th, - struct inode *dir, umode_t mode, - const char *symname, loff_t i_size, - struct dentry *dentry, struct inode *inode, - struct reiserfs_security_handle *security); - -void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th, - struct inode *inode, loff_t size); - -static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th, - struct inode *inode) -{ - reiserfs_update_sd_size(th, inode, inode->i_size); -} - -void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode); -void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs); -int reiserfs_setattr(struct dentry *dentry, struct iattr *attr); - -int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len); - -/* namei.c */ -void set_de_name_and_namelen(struct reiserfs_dir_entry *de); -int search_by_entry_key(struct super_block *sb, const struct cpu_key *key, - struct treepath *path, struct reiserfs_dir_entry *de); -struct dentry *reiserfs_get_parent(struct dentry *); - -#ifdef CONFIG_REISERFS_PROC_INFO -int reiserfs_proc_info_init(struct super_block *sb); -int reiserfs_proc_info_done(struct super_block *sb); -int reiserfs_proc_info_global_init(void); -int reiserfs_proc_info_global_done(void); - -#define PROC_EXP( e ) e - -#define __PINFO( sb ) REISERFS_SB(sb) -> s_proc_info_data -#define PROC_INFO_MAX( sb, field, value ) \ - __PINFO( sb ).field = \ - max( REISERFS_SB( sb ) -> s_proc_info_data.field, value ) -#define PROC_INFO_INC( sb, field ) ( ++ ( __PINFO( sb ).field ) ) -#define PROC_INFO_ADD( sb, field, val ) ( __PINFO( sb ).field += ( val ) ) -#define PROC_INFO_BH_STAT( sb, bh, level ) \ - PROC_INFO_INC( sb, sbk_read_at[ ( level ) ] ); \ - PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) ); \ - PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) ) -#else -static inline int reiserfs_proc_info_init(struct super_block *sb) -{ - return 0; -} - -static inline int reiserfs_proc_info_done(struct super_block *sb) -{ - return 0; -} - -static inline int reiserfs_proc_info_global_init(void) -{ - return 0; -} - -static inline int reiserfs_proc_info_global_done(void) -{ - return 0; -} - -#define PROC_EXP( e ) -#define VOID_V ( ( void ) 0 ) -#define PROC_INFO_MAX( sb, field, value ) VOID_V -#define PROC_INFO_INC( sb, field ) VOID_V -#define PROC_INFO_ADD( sb, field, val ) VOID_V -#define PROC_INFO_BH_STAT(sb, bh, n_node_level) VOID_V -#endif - -/* dir.c */ -extern const struct inode_operations reiserfs_dir_inode_operations; -extern const struct inode_operations reiserfs_symlink_inode_operations; -extern const struct inode_operations reiserfs_special_inode_operations; -extern const struct file_operations reiserfs_dir_operations; -int reiserfs_readdir_dentry(struct dentry *, void *, filldir_t, loff_t *); - -/* tail_conversion.c */ -int direct2indirect(struct reiserfs_transaction_handle *, struct inode *, - struct treepath *, struct buffer_head *, loff_t); -int indirect2direct(struct reiserfs_transaction_handle *, struct inode *, - struct page *, struct treepath *, const struct cpu_key *, - loff_t, char *); -void reiserfs_unmap_buffer(struct buffer_head *); - -/* file.c */ -extern const struct inode_operations reiserfs_file_inode_operations; -extern const struct file_operations reiserfs_file_operations; -extern const struct address_space_operations reiserfs_address_space_operations; - -/* fix_nodes.c */ - -int fix_nodes(int n_op_mode, struct tree_balance *tb, - struct item_head *ins_ih, const void *); -void unfix_nodes(struct tree_balance *); - -/* prints.c */ -void __reiserfs_panic(struct super_block *s, const char *id, - const char *function, const char *fmt, ...) - __attribute__ ((noreturn)); -#define reiserfs_panic(s, id, fmt, args...) \ - __reiserfs_panic(s, id, __func__, fmt, ##args) -void __reiserfs_error(struct super_block *s, const char *id, - const char *function, const char *fmt, ...); -#define reiserfs_error(s, id, fmt, args...) \ - __reiserfs_error(s, id, __func__, fmt, ##args) -void reiserfs_info(struct super_block *s, const char *fmt, ...); -void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...); -void print_indirect_item(struct buffer_head *bh, int item_num); -void store_print_tb(struct tree_balance *tb); -void print_cur_tb(char *mes); -void print_de(struct reiserfs_dir_entry *de); -void print_bi(struct buffer_info *bi, char *mes); -#define PRINT_LEAF_ITEMS 1 /* print all items */ -#define PRINT_DIRECTORY_ITEMS 2 /* print directory items */ -#define PRINT_DIRECT_ITEMS 4 /* print contents of direct items */ -void print_block(struct buffer_head *bh, ...); -void print_bmap(struct super_block *s, int silent); -void print_bmap_block(int i, char *data, int size, int silent); -/*void print_super_block (struct super_block * s, char * mes);*/ -void print_objectid_map(struct super_block *s); -void print_block_head(struct buffer_head *bh, char *mes); -void check_leaf(struct buffer_head *bh); -void check_internal(struct buffer_head *bh); -void print_statistics(struct super_block *s); -char *reiserfs_hashname(int code); - -/* lbalance.c */ -int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num, - int mov_bytes, struct buffer_head *Snew); -int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes); -int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes); -void leaf_delete_items(struct buffer_info *cur_bi, int last_first, int first, - int del_num, int del_bytes); -void leaf_insert_into_buf(struct buffer_info *bi, int before, - struct item_head *inserted_item_ih, - const char *inserted_item_body, int zeros_number); -void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num, - int pos_in_item, int paste_size, const char *body, - int zeros_number); -void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num, - int pos_in_item, int cut_size); -void leaf_paste_entries(struct buffer_info *bi, int item_num, int before, - int new_entry_count, struct reiserfs_de_head *new_dehs, - const char *records, int paste_size); -/* ibalance.c */ -int balance_internal(struct tree_balance *, int, int, struct item_head *, - struct buffer_head **); - -/* do_balance.c */ -void do_balance_mark_leaf_dirty(struct tree_balance *tb, - struct buffer_head *bh, int flag); -#define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty -#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty - -void do_balance(struct tree_balance *tb, struct item_head *ih, - const char *body, int flag); -void reiserfs_invalidate_buffer(struct tree_balance *tb, - struct buffer_head *bh); - -int get_left_neighbor_position(struct tree_balance *tb, int h); -int get_right_neighbor_position(struct tree_balance *tb, int h); -void replace_key(struct tree_balance *tb, struct buffer_head *, int, - struct buffer_head *, int); -void make_empty_node(struct buffer_info *); -struct buffer_head *get_FEB(struct tree_balance *); - -/* bitmap.c */ - -/* structure contains hints for block allocator, and it is a container for - * arguments, such as node, search path, transaction_handle, etc. */ -struct __reiserfs_blocknr_hint { - struct inode *inode; /* inode passed to allocator, if we allocate unf. nodes */ - sector_t block; /* file offset, in blocks */ - struct in_core_key key; - struct treepath *path; /* search path, used by allocator to deternine search_start by - * various ways */ - struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and - * bitmap blocks changes */ - b_blocknr_t beg, end; - b_blocknr_t search_start; /* a field used to transfer search start value (block number) - * between different block allocator procedures - * (determine_search_start() and others) */ - int prealloc_size; /* is set in determine_prealloc_size() function, used by underlayed - * function that do actual allocation */ - - unsigned formatted_node:1; /* the allocator uses different polices for getting disk space for - * formatted/unformatted blocks with/without preallocation */ - unsigned preallocate:1; -}; - -typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t; - -int reiserfs_parse_alloc_options(struct super_block *, char *); -void reiserfs_init_alloc_options(struct super_block *s); - -/* - * given a directory, this will tell you what packing locality - * to use for a new object underneat it. The locality is returned - * in disk byte order (le). - */ -__le32 reiserfs_choose_packing(struct inode *dir); - -int reiserfs_init_bitmap_cache(struct super_block *sb); -void reiserfs_free_bitmap_cache(struct super_block *sb); -void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info); -struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap); -int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value); -void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *, - b_blocknr_t, int for_unformatted); -int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t *, int, - int); -static inline int reiserfs_new_form_blocknrs(struct tree_balance *tb, - b_blocknr_t * new_blocknrs, - int amount_needed) -{ - reiserfs_blocknr_hint_t hint = { - .th = tb->transaction_handle, - .path = tb->tb_path, - .inode = NULL, - .key = tb->key, - .block = 0, - .formatted_node = 1 - }; - return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed, - 0); -} - -static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle - *th, struct inode *inode, - b_blocknr_t * new_blocknrs, - struct treepath *path, - sector_t block) -{ - reiserfs_blocknr_hint_t hint = { - .th = th, - .path = path, - .inode = inode, - .block = block, - .formatted_node = 0, - .preallocate = 0 - }; - return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0); -} - -#ifdef REISERFS_PREALLOCATE -static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle - *th, struct inode *inode, - b_blocknr_t * new_blocknrs, - struct treepath *path, - sector_t block) -{ - reiserfs_blocknr_hint_t hint = { - .th = th, - .path = path, - .inode = inode, - .block = block, - .formatted_node = 0, - .preallocate = 1 - }; - return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0); -} - -void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th, - struct inode *inode); -void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th); -#endif - -/* hashes.c */ -__u32 keyed_hash(const signed char *msg, int len); -__u32 yura_hash(const signed char *msg, int len); -__u32 r5_hash(const signed char *msg, int len); - -#define reiserfs_set_le_bit __set_bit_le -#define reiserfs_test_and_set_le_bit __test_and_set_bit_le -#define reiserfs_clear_le_bit __clear_bit_le -#define reiserfs_test_and_clear_le_bit __test_and_clear_bit_le -#define reiserfs_test_le_bit test_bit_le -#define reiserfs_find_next_zero_le_bit find_next_zero_bit_le - -/* sometimes reiserfs_truncate may require to allocate few new blocks - to perform indirect2direct conversion. People probably used to - think, that truncate should work without problems on a filesystem - without free disk space. They may complain that they can not - truncate due to lack of free disk space. This spare space allows us - to not worry about it. 500 is probably too much, but it should be - absolutely safe */ -#define SPARE_SPACE 500 - -/* prototypes from ioctl.c */ -long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -long reiserfs_compat_ioctl(struct file *filp, - unsigned int cmd, unsigned long arg); -int reiserfs_unpack(struct inode *inode, struct file *filp); diff --git a/trunk/fs/reiserfs/resize.c b/trunk/fs/reiserfs/resize.c index 9a17f63c3fd7..7483279b482d 100644 --- a/trunk/fs/reiserfs/resize.c +++ b/trunk/fs/reiserfs/resize.c @@ -13,7 +13,8 @@ #include #include #include -#include "reiserfs.h" +#include +#include #include int reiserfs_resize(struct super_block *s, unsigned long block_count_new) diff --git a/trunk/fs/reiserfs/stree.c b/trunk/fs/reiserfs/stree.c index f8afa4b162b8..77df82f9e70a 100644 --- a/trunk/fs/reiserfs/stree.c +++ b/trunk/fs/reiserfs/stree.c @@ -51,7 +51,7 @@ #include #include #include -#include "reiserfs.h" +#include #include #include diff --git a/trunk/fs/reiserfs/super.c b/trunk/fs/reiserfs/super.c index 8b7616ef06d8..e12d8b97cd4d 100644 --- a/trunk/fs/reiserfs/super.c +++ b/trunk/fs/reiserfs/super.c @@ -16,9 +16,9 @@ #include #include #include -#include "reiserfs.h" -#include "acl.h" -#include "xattr.h" +#include +#include +#include #include #include #include @@ -1874,9 +1874,11 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) unlock_new_inode(root_inode); } - s->s_root = d_make_root(root_inode); - if (!s->s_root) + s->s_root = d_alloc_root(root_inode); + if (!s->s_root) { + iput(root_inode); goto error; + } // define and initialize hash function sbi->s_hash_function = hash_function(s); if (sbi->s_hash_function == NULL) { diff --git a/trunk/fs/reiserfs/tail_conversion.c b/trunk/fs/reiserfs/tail_conversion.c index 5e2624d12f70..8f546bd473b8 100644 --- a/trunk/fs/reiserfs/tail_conversion.c +++ b/trunk/fs/reiserfs/tail_conversion.c @@ -5,7 +5,7 @@ #include #include #include -#include "reiserfs.h" +#include /* access to tail : when one is going to read tail it must make sure, that is not running. direct2indirect and indirect2direct can not run concurrently */ diff --git a/trunk/fs/reiserfs/xattr.c b/trunk/fs/reiserfs/xattr.c index 46fc1c20a6b1..c24deda8a8bc 100644 --- a/trunk/fs/reiserfs/xattr.c +++ b/trunk/fs/reiserfs/xattr.c @@ -33,7 +33,7 @@ * The xattrs themselves are protected by the xattr_sem. */ -#include "reiserfs.h" +#include #include #include #include @@ -43,8 +43,8 @@ #include #include #include -#include "xattr.h" -#include "acl.h" +#include +#include #include #include #include diff --git a/trunk/fs/reiserfs/xattr.h b/trunk/fs/reiserfs/xattr.h deleted file mode 100644 index f59626c5d33b..000000000000 --- a/trunk/fs/reiserfs/xattr.h +++ /dev/null @@ -1,122 +0,0 @@ -#include -#include -#include -#include - -struct inode; -struct dentry; -struct iattr; -struct super_block; -struct nameidata; - -int reiserfs_xattr_register_handlers(void) __init; -void reiserfs_xattr_unregister_handlers(void); -int reiserfs_xattr_init(struct super_block *sb, int mount_flags); -int reiserfs_lookup_privroot(struct super_block *sb); -int reiserfs_delete_xattrs(struct inode *inode); -int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); -int reiserfs_permission(struct inode *inode, int mask); - -#ifdef CONFIG_REISERFS_FS_XATTR -#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) -ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name, - void *buffer, size_t size); -int reiserfs_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); -ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size); -int reiserfs_removexattr(struct dentry *dentry, const char *name); - -int reiserfs_xattr_get(struct inode *, const char *, void *, size_t); -int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int); -int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *, - struct inode *, const char *, const void *, - size_t, int); - -extern const struct xattr_handler reiserfs_xattr_user_handler; -extern const struct xattr_handler reiserfs_xattr_trusted_handler; -extern const struct xattr_handler reiserfs_xattr_security_handler; -#ifdef CONFIG_REISERFS_FS_SECURITY -int reiserfs_security_init(struct inode *dir, struct inode *inode, - const struct qstr *qstr, - struct reiserfs_security_handle *sec); -int reiserfs_security_write(struct reiserfs_transaction_handle *th, - struct inode *inode, - struct reiserfs_security_handle *sec); -void reiserfs_security_free(struct reiserfs_security_handle *sec); -#endif - -static inline int reiserfs_xattrs_initialized(struct super_block *sb) -{ - return REISERFS_SB(sb)->priv_root != NULL; -} - -#define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header)) -static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size) -{ - loff_t ret = 0; - if (reiserfs_file_data_log(inode)) { - ret = _ROUND_UP(xattr_size(size), inode->i_sb->s_blocksize); - ret >>= inode->i_sb->s_blocksize_bits; - } - return ret; -} - -/* We may have to create up to 3 objects: xattr root, xattr dir, xattr file. - * Let's try to be smart about it. - * xattr root: We cache it. If it's not cached, we may need to create it. - * xattr dir: If anything has been loaded for this inode, we can set a flag - * saying so. - * xattr file: Since we don't cache xattrs, we can't tell. We always include - * blocks for it. - * - * However, since root and dir can be created between calls - YOU MUST SAVE - * THIS VALUE. - */ -static inline size_t reiserfs_xattr_jcreate_nblocks(struct inode *inode) -{ - size_t nblocks = JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); - - if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) { - nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); - if (!REISERFS_SB(inode->i_sb)->xattr_root->d_inode) - nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); - } - - return nblocks; -} - -static inline void reiserfs_init_xattr_rwsem(struct inode *inode) -{ - init_rwsem(&REISERFS_I(inode)->i_xattr_sem); -} - -#else - -#define reiserfs_getxattr NULL -#define reiserfs_setxattr NULL -#define reiserfs_listxattr NULL -#define reiserfs_removexattr NULL - -static inline void reiserfs_init_xattr_rwsem(struct inode *inode) -{ -} -#endif /* CONFIG_REISERFS_FS_XATTR */ - -#ifndef CONFIG_REISERFS_FS_SECURITY -static inline int reiserfs_security_init(struct inode *dir, - struct inode *inode, - const struct qstr *qstr, - struct reiserfs_security_handle *sec) -{ - return 0; -} -static inline int -reiserfs_security_write(struct reiserfs_transaction_handle *th, - struct inode *inode, - struct reiserfs_security_handle *sec) -{ - return 0; -} -static inline void reiserfs_security_free(struct reiserfs_security_handle *sec) -{} -#endif diff --git a/trunk/fs/reiserfs/xattr_acl.c b/trunk/fs/reiserfs/xattr_acl.c index 44474f9b990d..6da0396e5052 100644 --- a/trunk/fs/reiserfs/xattr_acl.c +++ b/trunk/fs/reiserfs/xattr_acl.c @@ -1,14 +1,14 @@ #include #include #include -#include "reiserfs.h" +#include #include #include #include #include #include -#include "xattr.h" -#include "acl.h" +#include +#include #include static int reiserfs_set_acl(struct reiserfs_transaction_handle *th, diff --git a/trunk/fs/reiserfs/xattr_security.c b/trunk/fs/reiserfs/xattr_security.c index 800a3cef6f62..534668fa41be 100644 --- a/trunk/fs/reiserfs/xattr_security.c +++ b/trunk/fs/reiserfs/xattr_security.c @@ -1,10 +1,10 @@ -#include "reiserfs.h" +#include #include #include #include #include #include -#include "xattr.h" +#include #include #include diff --git a/trunk/fs/reiserfs/xattr_trusted.c b/trunk/fs/reiserfs/xattr_trusted.c index a0035719f66b..9883736ce3ec 100644 --- a/trunk/fs/reiserfs/xattr_trusted.c +++ b/trunk/fs/reiserfs/xattr_trusted.c @@ -1,10 +1,10 @@ -#include "reiserfs.h" +#include #include #include #include #include #include -#include "xattr.h" +#include #include static int diff --git a/trunk/fs/reiserfs/xattr_user.c b/trunk/fs/reiserfs/xattr_user.c index 8667491ae7c3..45ae1a00013a 100644 --- a/trunk/fs/reiserfs/xattr_user.c +++ b/trunk/fs/reiserfs/xattr_user.c @@ -1,9 +1,9 @@ -#include "reiserfs.h" +#include #include #include #include #include -#include "xattr.h" +#include #include static int diff --git a/trunk/fs/romfs/super.c b/trunk/fs/romfs/super.c index e64f6b5f7ae5..bb36ab74eb45 100644 --- a/trunk/fs/romfs/super.c +++ b/trunk/fs/romfs/super.c @@ -538,12 +538,14 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent) if (IS_ERR(root)) goto error; - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) - goto error; + goto error_i; return 0; +error_i: + iput(root); error: return -EINVAL; error_rsb_inval: diff --git a/trunk/fs/squashfs/super.c b/trunk/fs/squashfs/super.c index 970b1167e7cb..ecaa2f7bdb8f 100644 --- a/trunk/fs/squashfs/super.c +++ b/trunk/fs/squashfs/super.c @@ -316,10 +316,11 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) } insert_inode_hash(root); - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (sb->s_root == NULL) { ERROR("Root inode create failed\n"); err = -ENOMEM; + iput(root); goto failed_mount; } diff --git a/trunk/fs/stat.c b/trunk/fs/stat.c index 86f13563a463..8806b8997d2e 100644 --- a/trunk/fs/stat.c +++ b/trunk/fs/stat.c @@ -307,7 +307,7 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, if (inode->i_op->readlink) { error = security_inode_readlink(path.dentry); if (!error) { - touch_atime(&path); + touch_atime(path.mnt, path.dentry); error = inode->i_op->readlink(path.dentry, buf, bufsiz); } diff --git a/trunk/fs/super.c b/trunk/fs/super.c index d90e900a8a0e..6277ec6cb60a 100644 --- a/trunk/fs/super.c +++ b/trunk/fs/super.c @@ -32,7 +32,6 @@ #include #include #include -#include #include "internal.h" diff --git a/trunk/fs/sysfs/mount.c b/trunk/fs/sysfs/mount.c index 52c3bdb66a84..140f26a34288 100644 --- a/trunk/fs/sysfs/mount.c +++ b/trunk/fs/sysfs/mount.c @@ -61,9 +61,10 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) } /* instantiate and link root dentry */ - root = d_make_root(inode); + root = d_alloc_root(inode); if (!root) { pr_debug("%s: could not get root dentry!\n",__func__); + iput(inode); return -ENOMEM; } root->d_fsdata = &sysfs_root; diff --git a/trunk/fs/sysv/namei.c b/trunk/fs/sysv/namei.c index d7466e293614..b217797e621b 100644 --- a/trunk/fs/sysv/namei.c +++ b/trunk/fs/sysv/namei.c @@ -121,6 +121,9 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, { struct inode *inode = old_dentry->d_inode; + if (inode->i_nlink >= SYSV_SB(inode->i_sb)->s_link_max) + return -EMLINK; + inode->i_ctime = CURRENT_TIME_SEC; inode_inc_link_count(inode); ihold(inode); @@ -131,8 +134,10 @@ static int sysv_link(struct dentry * old_dentry, struct inode * dir, static int sysv_mkdir(struct inode * dir, struct dentry *dentry, umode_t mode) { struct inode * inode; - int err; + int err = -EMLINK; + if (dir->i_nlink >= SYSV_SB(dir->i_sb)->s_link_max) + goto out; inode_inc_link_count(dir); inode = sysv_new_inode(dir, S_IFDIR|mode); @@ -246,6 +251,11 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { + if (dir_de) { + err = -EMLINK; + if (new_dir->i_nlink >= SYSV_SB(new_dir->i_sb)->s_link_max) + goto out_dir; + } err = sysv_add_link(new_dentry, old_inode); if (err) goto out_dir; diff --git a/trunk/fs/sysv/super.c b/trunk/fs/sysv/super.c index 7491c33b6468..f60c196913ea 100644 --- a/trunk/fs/sysv/super.c +++ b/trunk/fs/sysv/super.c @@ -44,7 +44,7 @@ enum { JAN_1_1980 = (10*365 + 2) * 24 * 60 * 60 }; -static void detected_xenix(struct sysv_sb_info *sbi, unsigned *max_links) +static void detected_xenix(struct sysv_sb_info *sbi) { struct buffer_head *bh1 = sbi->s_bh1; struct buffer_head *bh2 = sbi->s_bh2; @@ -59,7 +59,7 @@ static void detected_xenix(struct sysv_sb_info *sbi, unsigned *max_links) sbd2 = (struct xenix_super_block *) (bh2->b_data - 512); } - *max_links = XENIX_LINK_MAX; + sbi->s_link_max = XENIX_LINK_MAX; sbi->s_fic_size = XENIX_NICINOD; sbi->s_flc_size = XENIX_NICFREE; sbi->s_sbd1 = (char *)sbd1; @@ -75,7 +75,7 @@ static void detected_xenix(struct sysv_sb_info *sbi, unsigned *max_links) sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize); } -static void detected_sysv4(struct sysv_sb_info *sbi, unsigned *max_links) +static void detected_sysv4(struct sysv_sb_info *sbi) { struct sysv4_super_block * sbd; struct buffer_head *bh1 = sbi->s_bh1; @@ -86,7 +86,7 @@ static void detected_sysv4(struct sysv_sb_info *sbi, unsigned *max_links) else sbd = (struct sysv4_super_block *) bh2->b_data; - *max_links = SYSV_LINK_MAX; + sbi->s_link_max = SYSV_LINK_MAX; sbi->s_fic_size = SYSV_NICINOD; sbi->s_flc_size = SYSV_NICFREE; sbi->s_sbd1 = (char *)sbd; @@ -103,7 +103,7 @@ static void detected_sysv4(struct sysv_sb_info *sbi, unsigned *max_links) sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); } -static void detected_sysv2(struct sysv_sb_info *sbi, unsigned *max_links) +static void detected_sysv2(struct sysv_sb_info *sbi) { struct sysv2_super_block *sbd; struct buffer_head *bh1 = sbi->s_bh1; @@ -114,7 +114,7 @@ static void detected_sysv2(struct sysv_sb_info *sbi, unsigned *max_links) else sbd = (struct sysv2_super_block *) bh2->b_data; - *max_links = SYSV_LINK_MAX; + sbi->s_link_max = SYSV_LINK_MAX; sbi->s_fic_size = SYSV_NICINOD; sbi->s_flc_size = SYSV_NICFREE; sbi->s_sbd1 = (char *)sbd; @@ -131,14 +131,14 @@ static void detected_sysv2(struct sysv_sb_info *sbi, unsigned *max_links) sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); } -static void detected_coherent(struct sysv_sb_info *sbi, unsigned *max_links) +static void detected_coherent(struct sysv_sb_info *sbi) { struct coh_super_block * sbd; struct buffer_head *bh1 = sbi->s_bh1; sbd = (struct coh_super_block *) bh1->b_data; - *max_links = COH_LINK_MAX; + sbi->s_link_max = COH_LINK_MAX; sbi->s_fic_size = COH_NICINOD; sbi->s_flc_size = COH_NICFREE; sbi->s_sbd1 = (char *)sbd; @@ -154,12 +154,12 @@ static void detected_coherent(struct sysv_sb_info *sbi, unsigned *max_links) sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); } -static void detected_v7(struct sysv_sb_info *sbi, unsigned *max_links) +static void detected_v7(struct sysv_sb_info *sbi) { struct buffer_head *bh2 = sbi->s_bh2; struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data; - *max_links = V7_LINK_MAX; + sbi->s_link_max = V7_LINK_MAX; sbi->s_fic_size = V7_NICINOD; sbi->s_flc_size = V7_NICFREE; sbi->s_sbd1 = (char *)sbd; @@ -290,7 +290,7 @@ static char *flavour_names[] = { [FSTYPE_AFS] = "AFS", }; -static void (*flavour_setup[])(struct sysv_sb_info *, unsigned *) = { +static void (*flavour_setup[])(struct sysv_sb_info *) = { [FSTYPE_XENIX] = detected_xenix, [FSTYPE_SYSV4] = detected_sysv4, [FSTYPE_SYSV2] = detected_sysv2, @@ -310,7 +310,7 @@ static int complete_read_super(struct super_block *sb, int silent, int size) sbi->s_firstinodezone = 2; - flavour_setup[sbi->s_type](sbi, &sb->s_max_links); + flavour_setup[sbi->s_type](sbi); sbi->s_truncate = 1; sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone; @@ -341,8 +341,9 @@ static int complete_read_super(struct super_block *sb, int silent, int size) printk("SysV FS: get root inode failed\n"); return 0; } - sb->s_root = d_make_root(root_inode); + sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) { + iput(root_inode); printk("SysV FS: get root dentry failed\n"); return 0; } diff --git a/trunk/fs/sysv/sysv.h b/trunk/fs/sysv/sysv.h index 11b07672f6c5..0e4b821c5691 100644 --- a/trunk/fs/sysv/sysv.h +++ b/trunk/fs/sysv/sysv.h @@ -24,6 +24,7 @@ struct sysv_sb_info { char s_bytesex; /* bytesex (le/be/pdp) */ char s_truncate; /* if 1: names > SYSV_NAMELEN chars are truncated */ /* if 0: they are disallowed (ENAMETOOLONG) */ + nlink_t s_link_max; /* max number of hard links to a file */ unsigned int s_inodes_per_block; /* number of inodes per block */ unsigned int s_inodes_per_block_1; /* inodes_per_block - 1 */ unsigned int s_inodes_per_block_bits; /* log2(inodes_per_block) */ diff --git a/trunk/fs/ubifs/super.c b/trunk/fs/ubifs/super.c index 76e4e0566ad6..63765d58445b 100644 --- a/trunk/fs/ubifs/super.c +++ b/trunk/fs/ubifs/super.c @@ -2076,13 +2076,15 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) goto out_umount; } - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) - goto out_umount; + goto out_iput; mutex_unlock(&c->umount_mutex); return 0; +out_iput: + iput(root); out_umount: ubifs_umount(c); out_unlock: diff --git a/trunk/fs/udf/namei.c b/trunk/fs/udf/namei.c index 38de8f234b94..08bf46edf9c4 100644 --- a/trunk/fs/udf/namei.c +++ b/trunk/fs/udf/namei.c @@ -32,6 +32,8 @@ #include #include +enum { UDF_MAX_LINKS = 0xffff }; + static inline int udf_match(int len1, const unsigned char *name1, int len2, const unsigned char *name2) { @@ -647,6 +649,10 @@ static int udf_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) struct udf_inode_info *dinfo = UDF_I(dir); struct udf_inode_info *iinfo; + err = -EMLINK; + if (dir->i_nlink >= UDF_MAX_LINKS) + goto out; + err = -EIO; inode = udf_new_inode(dir, S_IFDIR | mode, &err); if (!inode) @@ -1026,6 +1032,9 @@ static int udf_link(struct dentry *old_dentry, struct inode *dir, struct fileIdentDesc cfi, *fi; int err; + if (inode->i_nlink >= UDF_MAX_LINKS) + return -EMLINK; + fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err); if (!fi) { return err; @@ -1117,6 +1126,10 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry, if (udf_get_lb_pblock(old_inode->i_sb, &tloc, 0) != old_dir->i_ino) goto end_rename; + + retval = -EMLINK; + if (!new_inode && new_dir->i_nlink >= UDF_MAX_LINKS) + goto end_rename; } if (!nfi) { nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, diff --git a/trunk/fs/udf/super.c b/trunk/fs/udf/super.c index 85067b4c7e14..c09a84daaf50 100644 --- a/trunk/fs/udf/super.c +++ b/trunk/fs/udf/super.c @@ -75,8 +75,6 @@ #define UDF_DEFAULT_BLOCKSIZE 2048 -enum { UDF_MAX_LINKS = 0xffff }; - /* These are the "meat" - everything else is stuffing */ static int udf_fill_super(struct super_block *, void *, int); static void udf_put_super(struct super_block *); @@ -2037,13 +2035,13 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) } /* Allocate a dentry for the root inode */ - sb->s_root = d_make_root(inode); + sb->s_root = d_alloc_root(inode); if (!sb->s_root) { udf_err(sb, "Couldn't allocate root dentry\n"); + iput(inode); goto error_out; } sb->s_maxbytes = MAX_LFS_FILESIZE; - sb->s_max_links = UDF_MAX_LINKS; return 0; error_out: diff --git a/trunk/fs/ufs/namei.c b/trunk/fs/ufs/namei.c index a2281cadefa1..38cac199edff 100644 --- a/trunk/fs/ufs/namei.c +++ b/trunk/fs/ufs/namei.c @@ -166,6 +166,10 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir, int error; lock_ufs(dir->i_sb); + if (inode->i_nlink >= UFS_LINK_MAX) { + unlock_ufs(dir->i_sb); + return -EMLINK; + } inode->i_ctime = CURRENT_TIME_SEC; inode_inc_link_count(inode); @@ -179,7 +183,10 @@ static int ufs_link (struct dentry * old_dentry, struct inode * dir, static int ufs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) { struct inode * inode; - int err; + int err = -EMLINK; + + if (dir->i_nlink >= UFS_LINK_MAX) + goto out; lock_ufs(dir->i_sb); inode_inc_link_count(dir); @@ -298,6 +305,11 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry, drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { + if (dir_de) { + err = -EMLINK; + if (new_dir->i_nlink >= UFS_LINK_MAX) + goto out_dir; + } err = ufs_add_link(new_dentry, old_inode); if (err) goto out_dir; diff --git a/trunk/fs/ufs/super.c b/trunk/fs/ufs/super.c index f636f6b460d0..5246ee3e5607 100644 --- a/trunk/fs/ufs/super.c +++ b/trunk/fs/ufs/super.c @@ -1157,17 +1157,16 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) "fast symlink size (%u)\n", uspi->s_maxsymlinklen); uspi->s_maxsymlinklen = maxsymlen; } - sb->s_max_links = UFS_LINK_MAX; inode = ufs_iget(sb, UFS_ROOTINO); if (IS_ERR(inode)) { ret = PTR_ERR(inode); goto failed; } - sb->s_root = d_make_root(inode); + sb->s_root = d_alloc_root(inode); if (!sb->s_root) { ret = -ENOMEM; - goto failed; + goto dalloc_failed; } ufs_setup_cstotal(sb); @@ -1181,6 +1180,8 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) UFSD("EXIT\n"); return 0; +dalloc_failed: + iput(inode); failed: if (ubh) ubh_brelse_uspi (uspi); diff --git a/trunk/fs/xfs/xfs_rename.c b/trunk/fs/xfs/xfs_rename.c index e44ef7ee8ce8..866de277079a 100644 --- a/trunk/fs/xfs/xfs_rename.c +++ b/trunk/fs/xfs/xfs_rename.c @@ -118,6 +118,17 @@ xfs_rename( new_parent = (src_dp != target_dp); src_is_directory = S_ISDIR(src_ip->i_d.di_mode); + if (src_is_directory) { + /* + * Check for link count overflow on target_dp + */ + if (target_ip == NULL && new_parent && + target_dp->i_d.di_nlink >= XFS_MAXLINK) { + error = XFS_ERROR(EMLINK); + goto std_return; + } + } + xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, inodes, &num_inodes); diff --git a/trunk/fs/xfs/xfs_super.c b/trunk/fs/xfs/xfs_super.c index baf40e378d35..ee5b695c99a7 100644 --- a/trunk/fs/xfs/xfs_super.c +++ b/trunk/fs/xfs/xfs_super.c @@ -1341,7 +1341,6 @@ xfs_fs_fill_super( sb->s_blocksize = mp->m_sb.sb_blocksize; sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); - sb->s_max_links = XFS_MAXLINK; sb->s_time_gran = 1; set_posix_acl_flag(sb); @@ -1362,10 +1361,10 @@ xfs_fs_fill_super( error = EINVAL; goto out_syncd_stop; } - sb->s_root = d_make_root(root); + sb->s_root = d_alloc_root(root); if (!sb->s_root) { error = ENOMEM; - goto out_syncd_stop; + goto out_iput; } return 0; @@ -1384,6 +1383,8 @@ xfs_fs_fill_super( out: return -error; + out_iput: + iput(root); out_syncd_stop: xfs_syncd_stop(mp); out_unmount: diff --git a/trunk/fs/xfs/xfs_utils.c b/trunk/fs/xfs/xfs_utils.c index 79c05ac85bfe..89dbb4a50872 100644 --- a/trunk/fs/xfs/xfs_utils.c +++ b/trunk/fs/xfs/xfs_utils.c @@ -296,6 +296,8 @@ xfs_bumplink( xfs_trans_t *tp, xfs_inode_t *ip) { + if (ip->i_d.di_nlink >= XFS_MAXLINK) + return XFS_ERROR(EMLINK); xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); ASSERT(ip->i_d.di_nlink > 0); diff --git a/trunk/fs/xfs/xfs_vnodeops.c b/trunk/fs/xfs/xfs_vnodeops.c index 64981d7e7375..ebdb88840a47 100644 --- a/trunk/fs/xfs/xfs_vnodeops.c +++ b/trunk/fs/xfs/xfs_vnodeops.c @@ -917,6 +917,14 @@ xfs_create( xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT); unlock_dp_on_error = B_TRUE; + /* + * Check for directory link count overflow. + */ + if (is_dir && dp->i_d.di_nlink >= XFS_MAXLINK) { + error = XFS_ERROR(EMLINK); + goto out_trans_cancel; + } + xfs_bmap_init(&free_list, &first_block); /* @@ -1420,6 +1428,14 @@ xfs_link( xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL); + /* + * If the source has too many links, we can't make any more to it. + */ + if (sip->i_d.di_nlink >= XFS_MAXLINK) { + error = XFS_ERROR(EMLINK); + goto error_return; + } + /* * If we are using project inheritance, we only allow hard link * creation in our tree when the project IDs are the same; else diff --git a/trunk/include/asm-generic/pgtable.h b/trunk/include/asm-generic/pgtable.h index 76bff2bff15e..a03c098b0cce 100644 --- a/trunk/include/asm-generic/pgtable.h +++ b/trunk/include/asm-generic/pgtable.h @@ -425,6 +425,8 @@ extern void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn, unsigned long size); #endif +#ifdef CONFIG_MMU + #ifndef CONFIG_TRANSPARENT_HUGEPAGE static inline int pmd_trans_huge(pmd_t pmd) { @@ -441,7 +443,66 @@ static inline int pmd_write(pmd_t pmd) return 0; } #endif /* __HAVE_ARCH_PMD_WRITE */ +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +/* + * This function is meant to be used by sites walking pagetables with + * the mmap_sem hold in read mode to protect against MADV_DONTNEED and + * transhuge page faults. MADV_DONTNEED can convert a transhuge pmd + * into a null pmd and the transhuge page fault can convert a null pmd + * into an hugepmd or into a regular pmd (if the hugepage allocation + * fails). While holding the mmap_sem in read mode the pmd becomes + * stable and stops changing under us only if it's not null and not a + * transhuge pmd. When those races occurs and this function makes a + * difference vs the standard pmd_none_or_clear_bad, the result is + * undefined so behaving like if the pmd was none is safe (because it + * can return none anyway). The compiler level barrier() is critically + * important to compute the two checks atomically on the same pmdval. + */ +static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd) +{ + /* depend on compiler for an atomic pmd read */ + pmd_t pmdval = *pmd; + /* + * The barrier will stabilize the pmdval in a register or on + * the stack so that it will stop changing under the code. + */ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + barrier(); +#endif + if (pmd_none(pmdval)) + return 1; + if (unlikely(pmd_bad(pmdval))) { + if (!pmd_trans_huge(pmdval)) + pmd_clear_bad(pmd); + return 1; + } + return 0; +} + +/* + * This is a noop if Transparent Hugepage Support is not built into + * the kernel. Otherwise it is equivalent to + * pmd_none_or_trans_huge_or_clear_bad(), and shall only be called in + * places that already verified the pmd is not none and they want to + * walk ptes while holding the mmap sem in read mode (write mode don't + * need this). If THP is not enabled, the pmd can't go away under the + * code even if MADV_DONTNEED runs, but if THP is enabled we need to + * run a pmd_trans_unstable before walking the ptes after + * split_huge_page_pmd returns (because it may have run when the pmd + * become null, but then a page fault can map in a THP and not a + * regular page). + */ +static inline int pmd_trans_unstable(pmd_t *pmd) +{ +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + return pmd_none_or_trans_huge_or_clear_bad(pmd); +#else + return 0; #endif +} + +#endif /* CONFIG_MMU */ #endif /* !__ASSEMBLY__ */ diff --git a/trunk/include/linux/atomic.h b/trunk/include/linux/atomic.h index 70cfcb2d63c4..42b77b5446d2 100644 --- a/trunk/include/linux/atomic.h +++ b/trunk/include/linux/atomic.h @@ -24,9 +24,7 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) * Atomically increments @v by 1, so long as @v is non-zero. * Returns non-zero if @v was non-zero, and zero otherwise. */ -#ifndef atomic_inc_not_zero #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) -#endif /** * atomic_inc_not_zero_hint - increment if not null diff --git a/trunk/include/linux/audit.h b/trunk/include/linux/audit.h index ed3ef1972496..9ff7a2c48b50 100644 --- a/trunk/include/linux/audit.h +++ b/trunk/include/linux/audit.h @@ -684,7 +684,7 @@ extern void audit_log_untrustedstring(struct audit_buffer *ab, const char *string); extern void audit_log_d_path(struct audit_buffer *ab, const char *prefix, - const struct path *path); + struct path *path); extern void audit_log_key(struct audit_buffer *ab, char *key); extern void audit_log_lost(const char *message); diff --git a/trunk/include/linux/binfmts.h b/trunk/include/linux/binfmts.h index 366422bc1633..0092102db2de 100644 --- a/trunk/include/linux/binfmts.h +++ b/trunk/include/linux/binfmts.h @@ -92,17 +92,17 @@ struct linux_binfmt { unsigned long min_coredump; /* minimal dump size */ }; -extern void __register_binfmt(struct linux_binfmt *fmt, int insert); +extern int __register_binfmt(struct linux_binfmt *fmt, int insert); /* Registration of default binfmt handlers */ -static inline void register_binfmt(struct linux_binfmt *fmt) +static inline int register_binfmt(struct linux_binfmt *fmt) { - __register_binfmt(fmt, 0); + return __register_binfmt(fmt, 0); } /* Same as above, but adds a new binfmt at the top of the list */ -static inline void insert_binfmt(struct linux_binfmt *fmt) +static inline int insert_binfmt(struct linux_binfmt *fmt) { - __register_binfmt(fmt, 1); + return __register_binfmt(fmt, 1); } extern void unregister_binfmt(struct linux_binfmt *); diff --git a/trunk/include/linux/crypto.h b/trunk/include/linux/crypto.h index 48ce5479386c..8a94217b298e 100644 --- a/trunk/include/linux/crypto.h +++ b/trunk/include/linux/crypto.h @@ -75,11 +75,6 @@ */ #define CRYPTO_ALG_INSTANCE 0x00000800 -/* Set this bit if the algorithm provided is hardware accelerated but - * not available to userspace via instruction set or so. - */ -#define CRYPTO_ALG_KERN_DRIVER_ONLY 0x00001000 - /* * Transform masks and values (for crt_flags). */ @@ -314,8 +309,6 @@ struct crypto_alg { */ int crypto_register_alg(struct crypto_alg *alg); int crypto_unregister_alg(struct crypto_alg *alg); -int crypto_register_algs(struct crypto_alg *algs, int count); -int crypto_unregister_algs(struct crypto_alg *algs, int count); /* * Algorithm query interface. diff --git a/trunk/include/linux/dcache.h b/trunk/include/linux/dcache.h index 7e11f1418203..ff5f5256d175 100644 --- a/trunk/include/linux/dcache.h +++ b/trunk/include/linux/dcache.h @@ -222,6 +222,7 @@ extern void shrink_dcache_for_umount(struct super_block *); extern int d_invalidate(struct dentry *); /* only used at mount-time */ +extern struct dentry * d_alloc_root(struct inode *); extern struct dentry * d_make_root(struct inode *); /* - the ramfs-type tree */ diff --git a/trunk/include/linux/debugfs.h b/trunk/include/linux/debugfs.h index ae36b72c22f3..6169c26fd8c8 100644 --- a/trunk/include/linux/debugfs.h +++ b/trunk/include/linux/debugfs.h @@ -86,7 +86,7 @@ struct dentry *debugfs_create_blob(const char *name, umode_t mode, struct dentry *parent, struct debugfs_blob_wrapper *blob); -struct dentry *debugfs_create_regset32(const char *name, umode_t mode, +struct dentry *debugfs_create_regset32(const char *name, mode_t mode, struct dentry *parent, struct debugfs_regset32 *regset); @@ -208,7 +208,7 @@ static inline struct dentry *debugfs_create_blob(const char *name, umode_t mode, } static inline struct dentry *debugfs_create_regset32(const char *name, - umode_t mode, struct dentry *parent, + mode_t mode, struct dentry *parent, struct debugfs_regset32 *regset) { return ERR_PTR(-ENODEV); diff --git a/trunk/include/linux/device.h b/trunk/include/linux/device.h index 5ad17cccdd71..7c46bc32fcbf 100644 --- a/trunk/include/linux/device.h +++ b/trunk/include/linux/device.h @@ -262,6 +262,10 @@ extern int __must_check driver_create_file(struct device_driver *driver, extern void driver_remove_file(struct device_driver *driver, const struct driver_attribute *attr); +extern int __must_check driver_add_kobj(struct device_driver *drv, + struct kobject *kobj, + const char *fmt, ...); + extern int __must_check driver_for_each_device(struct device_driver *drv, struct device *start, void *data, diff --git a/trunk/include/linux/file.h b/trunk/include/linux/file.h index 58bf158c53d9..21a79958541c 100644 --- a/trunk/include/linux/file.h +++ b/trunk/include/linux/file.h @@ -12,6 +12,7 @@ struct file; extern void fput(struct file *); +extern void drop_file_write_access(struct file *file); struct file_operations; struct vfsmount; diff --git a/trunk/include/linux/fs.h b/trunk/include/linux/fs.h index 9bbe1a9ac432..69cd5bb640f5 100644 --- a/trunk/include/linux/fs.h +++ b/trunk/include/linux/fs.h @@ -1459,7 +1459,6 @@ struct super_block { u8 s_uuid[16]; /* UUID */ void *s_fs_info; /* Filesystem private info */ - unsigned int s_max_links; fmode_t s_mode; /* Granularity of c/m/atime in ns. @@ -1812,11 +1811,11 @@ static inline void inode_inc_iversion(struct inode *inode) spin_unlock(&inode->i_lock); } -extern void touch_atime(struct path *); +extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry); static inline void file_accessed(struct file *file) { if (!(file->f_flags & O_NOATIME)) - touch_atime(&file->f_path); + touch_atime(file->f_path.mnt, file->f_path.dentry); } int sync_inode(struct inode *inode, struct writeback_control *wbc); @@ -2305,10 +2304,7 @@ extern struct inode * igrab(struct inode *); extern ino_t iunique(struct super_block *, ino_t); extern int inode_needs_sync(struct inode *inode); extern int generic_delete_inode(struct inode *inode); -static inline int generic_drop_inode(struct inode *inode) -{ - return !inode->i_nlink || inode_unhashed(inode); -} +extern int generic_drop_inode(struct inode *inode); extern struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), diff --git a/trunk/include/linux/gfs2_ondisk.h b/trunk/include/linux/gfs2_ondisk.h index fa98bdb073b9..b148087f49a6 100644 --- a/trunk/include/linux/gfs2_ondisk.h +++ b/trunk/include/linux/gfs2_ondisk.h @@ -168,7 +168,6 @@ struct gfs2_rindex { #define GFS2_RGF_METAONLY 0x00000002 #define GFS2_RGF_DATAONLY 0x00000004 #define GFS2_RGF_NOALLOC 0x00000008 -#define GFS2_RGF_TRIMMED 0x00000010 struct gfs2_rgrp { struct gfs2_meta_header rg_header; diff --git a/trunk/include/linux/key.h b/trunk/include/linux/key.h index 1600ebf717a7..5253471cd2ea 100644 --- a/trunk/include/linux/key.h +++ b/trunk/include/linux/key.h @@ -155,7 +155,6 @@ struct key { #define KEY_FLAG_IN_QUOTA 3 /* set if key consumes quota */ #define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */ #define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ -#define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ /* the description string * - this is used to match a key against search criteria diff --git a/trunk/include/linux/magic.h b/trunk/include/linux/magic.h index b7ed4759dbb2..2d4beab0d5b7 100644 --- a/trunk/include/linux/magic.h +++ b/trunk/include/linux/magic.h @@ -42,7 +42,6 @@ #define OPENPROM_SUPER_MAGIC 0x9fa1 #define PROC_SUPER_MAGIC 0x9fa0 #define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */ -#define QNX6_SUPER_MAGIC 0x68191122 /* qnx6 fs detection */ #define REISERFS_SUPER_MAGIC 0x52654973 /* used by gcc */ /* used by file system utilities that diff --git a/trunk/include/linux/mm.h b/trunk/include/linux/mm.h index b5bb54d6d667..17b27cd269c4 100644 --- a/trunk/include/linux/mm.h +++ b/trunk/include/linux/mm.h @@ -893,9 +893,9 @@ struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, unsigned long size); -void zap_page_range(struct vm_area_struct *vma, unsigned long address, +unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size, struct zap_details *); -void unmap_vmas(struct mmu_gather *tlb, +unsigned long unmap_vmas(struct mmu_gather *tlb, struct vm_area_struct *start_vma, unsigned long start_addr, unsigned long end_addr, unsigned long *nr_accounted, struct zap_details *); diff --git a/trunk/include/linux/of.h b/trunk/include/linux/of.h index d46a18ffbebb..f02d8b2f799d 100644 --- a/trunk/include/linux/of.h +++ b/trunk/include/linux/of.h @@ -58,9 +58,6 @@ struct device_node { struct kref kref; unsigned long _flags; void *data; -#if defined(CONFIG_EEH) - struct eeh_dev *edev; -#endif #if defined(CONFIG_SPARC) char *path_component_name; unsigned int unique_id; @@ -75,13 +72,6 @@ struct of_phandle_args { uint32_t args[MAX_PHANDLE_ARGS]; }; -#if defined(CONFIG_EEH) -static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn) -{ - return dn->edev; -} -#endif - #ifdef CONFIG_OF_DYNAMIC extern struct device_node *of_node_get(struct device_node *node); extern void of_node_put(struct device_node *node); diff --git a/trunk/include/linux/padata.h b/trunk/include/linux/padata.h index 86292beebfe2..4633b2f726b6 100644 --- a/trunk/include/linux/padata.h +++ b/trunk/include/linux/padata.h @@ -46,6 +46,7 @@ struct padata_priv { struct list_head list; struct parallel_data *pd; int cb_cpu; + int seq_nr; int info; void (*parallel)(struct padata_priv *padata); void (*serial)(struct padata_priv *padata); @@ -115,6 +116,7 @@ struct padata_cpumask { * @pinst: padata instance. * @pqueue: percpu padata queues used for parallelization. * @squeue: percpu padata queues used for serialuzation. + * @seq_nr: The sequence number that will be attached to the next object. * @reorder_objects: Number of objects waiting in the reorder queues. * @refcnt: Number of objects holding a reference on this parallel_data. * @max_seq_nr: Maximal used sequence number. @@ -127,12 +129,12 @@ struct parallel_data { struct padata_instance *pinst; struct padata_parallel_queue __percpu *pqueue; struct padata_serial_queue __percpu *squeue; + atomic_t seq_nr; atomic_t reorder_objects; atomic_t refcnt; + unsigned int max_seq_nr; struct padata_cpumask cpumask; spinlock_t lock ____cacheline_aligned; - spinlock_t seq_lock; - unsigned int seq_nr; unsigned int processed; struct timer_list timer; }; diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index 27bf521bcebd..b843fe79583b 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -1660,13 +1660,6 @@ static inline void pci_set_bus_of_node(struct pci_bus *bus) { } static inline void pci_release_bus_of_node(struct pci_bus *bus) { } #endif /* CONFIG_OF */ -#ifdef CONFIG_EEH -static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev) -{ - return pdev->dev.archdata.edev; -} -#endif - /** * pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device * @pdev: the PCI device diff --git a/trunk/include/linux/prctl.h b/trunk/include/linux/prctl.h index a0413ac3abe8..7ddc7f1b480f 100644 --- a/trunk/include/linux/prctl.h +++ b/trunk/include/linux/prctl.h @@ -114,11 +114,4 @@ # define PR_SET_MM_START_BRK 6 # define PR_SET_MM_BRK 7 -/* - * Set specific pid that is allowed to ptrace the current task. - * A value of 0 mean "no process". - */ -#define PR_SET_PTRACER 0x59616d61 -# define PR_SET_PTRACER_ANY ((unsigned long)-1) - #endif /* _LINUX_PRCTL_H */ diff --git a/trunk/include/linux/qnx6_fs.h b/trunk/include/linux/qnx6_fs.h deleted file mode 100644 index 26049eab9010..000000000000 --- a/trunk/include/linux/qnx6_fs.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Name : qnx6_fs.h - * Author : Kai Bankett - * Function : qnx6 global filesystem definitions - * History : 17-01-2012 created - */ -#ifndef _LINUX_QNX6_FS_H -#define _LINUX_QNX6_FS_H - -#include -#include - -#define QNX6_ROOT_INO 1 - -/* for di_status */ -#define QNX6_FILE_DIRECTORY 0x01 -#define QNX6_FILE_DELETED 0x02 -#define QNX6_FILE_NORMAL 0x03 - -#define QNX6_SUPERBLOCK_SIZE 0x200 /* superblock always is 512 bytes */ -#define QNX6_SUPERBLOCK_AREA 0x1000 /* area reserved for superblock */ -#define QNX6_BOOTBLOCK_SIZE 0x2000 /* heading bootblock area */ -#define QNX6_DIR_ENTRY_SIZE 0x20 /* dir entry size of 32 bytes */ -#define QNX6_INODE_SIZE 0x80 /* each inode is 128 bytes */ -#define QNX6_INODE_SIZE_BITS 7 /* inode entry size shift */ - -#define QNX6_NO_DIRECT_POINTERS 16 /* 16 blockptrs in sbl/inode */ -#define QNX6_PTR_MAX_LEVELS 5 /* maximum indirect levels */ - -/* for filenames */ -#define QNX6_SHORT_NAME_MAX 27 -#define QNX6_LONG_NAME_MAX 510 - -/* list of mount options */ -#define QNX6_MOUNT_MMI_FS 0x010000 /* mount as Audi MMI 3G fs */ - -/* - * This is the original qnx6 inode layout on disk. - * Each inode is 128 byte long. - */ -struct qnx6_inode_entry { - __fs64 di_size; - __fs32 di_uid; - __fs32 di_gid; - __fs32 di_ftime; - __fs32 di_mtime; - __fs32 di_atime; - __fs32 di_ctime; - __fs16 di_mode; - __fs16 di_ext_mode; - __fs32 di_block_ptr[QNX6_NO_DIRECT_POINTERS]; - __u8 di_filelevels; - __u8 di_status; - __u8 di_unknown2[2]; - __fs32 di_zero2[6]; -}; - -/* - * Each directory entry is maximum 32 bytes long. - * If more characters or special characters required it is stored - * in the longfilenames structure. - */ -struct qnx6_dir_entry { - __fs32 de_inode; - __u8 de_size; - char de_fname[QNX6_SHORT_NAME_MAX]; -}; - -/* - * Longfilename direntries have a different structure - */ -struct qnx6_long_dir_entry { - __fs32 de_inode; - __u8 de_size; - __u8 de_unknown[3]; - __fs32 de_long_inode; - __fs32 de_checksum; -}; - -struct qnx6_long_filename { - __fs16 lf_size; - __u8 lf_fname[QNX6_LONG_NAME_MAX]; -}; - -struct qnx6_root_node { - __fs64 size; - __fs32 ptr[QNX6_NO_DIRECT_POINTERS]; - __u8 levels; - __u8 mode; - __u8 spare[6]; -}; - -struct qnx6_super_block { - __fs32 sb_magic; - __fs32 sb_checksum; - __fs64 sb_serial; - __fs32 sb_ctime; /* time the fs was created */ - __fs32 sb_atime; /* last access time */ - __fs32 sb_flags; - __fs16 sb_version1; /* filesystem version information */ - __fs16 sb_version2; /* filesystem version information */ - __u8 sb_volumeid[16]; - __fs32 sb_blocksize; - __fs32 sb_num_inodes; - __fs32 sb_free_inodes; - __fs32 sb_num_blocks; - __fs32 sb_free_blocks; - __fs32 sb_allocgroup; - struct qnx6_root_node Inode; - struct qnx6_root_node Bitmap; - struct qnx6_root_node Longfile; - struct qnx6_root_node Unknown; -}; - -/* Audi MMI 3G superblock layout is different to plain qnx6 */ -struct qnx6_mmi_super_block { - __fs32 sb_magic; - __fs32 sb_checksum; - __fs64 sb_serial; - __u8 sb_spare0[12]; - __u8 sb_id[12]; - __fs32 sb_blocksize; - __fs32 sb_num_inodes; - __fs32 sb_free_inodes; - __fs32 sb_num_blocks; - __fs32 sb_free_blocks; - __u8 sb_spare1[4]; - struct qnx6_root_node Inode; - struct qnx6_root_node Bitmap; - struct qnx6_root_node Longfile; - struct qnx6_root_node Unknown; -}; - -#endif diff --git a/trunk/fs/reiserfs/acl.h b/trunk/include/linux/reiserfs_acl.h similarity index 100% rename from trunk/fs/reiserfs/acl.h rename to trunk/include/linux/reiserfs_acl.h diff --git a/trunk/include/linux/reiserfs_fs.h b/trunk/include/linux/reiserfs_fs.h index ea3700cd7367..2213ddcce20c 100644 --- a/trunk/include/linux/reiserfs_fs.h +++ b/trunk/include/linux/reiserfs_fs.h @@ -1,12 +1,32 @@ /* * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details */ + + /* this file has an amazingly stupid + name, yura please fix it to be + reiserfs.h, and merge all the rest + of our .h files that are in this + directory into it. */ + #ifndef _LINUX_REISER_FS_H #define _LINUX_REISER_FS_H #include #include +#ifdef __KERNEL__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + /* * include/linux/reiser_fs.h * @@ -23,4 +43,2318 @@ #define REISERFS_IOC_GETVERSION FS_IOC_GETVERSION #define REISERFS_IOC_SETVERSION FS_IOC_SETVERSION +#ifdef __KERNEL__ +/* the 32 bit compat definitions with int argument */ +#define REISERFS_IOC32_UNPACK _IOW(0xCD, 1, int) +#define REISERFS_IOC32_GETFLAGS FS_IOC32_GETFLAGS +#define REISERFS_IOC32_SETFLAGS FS_IOC32_SETFLAGS +#define REISERFS_IOC32_GETVERSION FS_IOC32_GETVERSION +#define REISERFS_IOC32_SETVERSION FS_IOC32_SETVERSION + +/* + * Locking primitives. The write lock is a per superblock + * special mutex that has properties close to the Big Kernel Lock + * which was used in the previous locking scheme. + */ +void reiserfs_write_lock(struct super_block *s); +void reiserfs_write_unlock(struct super_block *s); +int reiserfs_write_lock_once(struct super_block *s); +void reiserfs_write_unlock_once(struct super_block *s, int lock_depth); + +#ifdef CONFIG_REISERFS_CHECK +void reiserfs_lock_check_recursive(struct super_block *s); +#else +static inline void reiserfs_lock_check_recursive(struct super_block *s) { } +#endif + +/* + * Several mutexes depend on the write lock. + * However sometimes we want to relax the write lock while we hold + * these mutexes, according to the release/reacquire on schedule() + * properties of the Bkl that were used. + * Reiserfs performances and locking were based on this scheme. + * Now that the write lock is a mutex and not the bkl anymore, doing so + * may result in a deadlock: + * + * A acquire write_lock + * A acquire j_commit_mutex + * A release write_lock and wait for something + * B acquire write_lock + * B can't acquire j_commit_mutex and sleep + * A can't acquire write lock anymore + * deadlock + * + * What we do here is avoiding such deadlock by playing the same game + * than the Bkl: if we can't acquire a mutex that depends on the write lock, + * we release the write lock, wait a bit and then retry. + * + * The mutexes concerned by this hack are: + * - The commit mutex of a journal list + * - The flush mutex + * - The journal lock + * - The inode mutex + */ +static inline void reiserfs_mutex_lock_safe(struct mutex *m, + struct super_block *s) +{ + reiserfs_lock_check_recursive(s); + reiserfs_write_unlock(s); + mutex_lock(m); + reiserfs_write_lock(s); +} + +static inline void +reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass, + struct super_block *s) +{ + reiserfs_lock_check_recursive(s); + reiserfs_write_unlock(s); + mutex_lock_nested(m, subclass); + reiserfs_write_lock(s); +} + +static inline void +reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s) +{ + reiserfs_lock_check_recursive(s); + reiserfs_write_unlock(s); + down_read(sem); + reiserfs_write_lock(s); +} + +/* + * When we schedule, we usually want to also release the write lock, + * according to the previous bkl based locking scheme of reiserfs. + */ +static inline void reiserfs_cond_resched(struct super_block *s) +{ + if (need_resched()) { + reiserfs_write_unlock(s); + schedule(); + reiserfs_write_lock(s); + } +} + +struct fid; + +/* in reading the #defines, it may help to understand that they employ + the following abbreviations: + + B = Buffer + I = Item header + H = Height within the tree (should be changed to LEV) + N = Number of the item in the node + STAT = stat data + DEH = Directory Entry Header + EC = Entry Count + E = Entry number + UL = Unsigned Long + BLKH = BLocK Header + UNFM = UNForMatted node + DC = Disk Child + P = Path + + These #defines are named by concatenating these abbreviations, + where first comes the arguments, and last comes the return value, + of the macro. + +*/ + +#define USE_INODE_GENERATION_COUNTER + +#define REISERFS_PREALLOCATE +#define DISPLACE_NEW_PACKING_LOCALITIES +#define PREALLOCATION_SIZE 9 + +/* n must be power of 2 */ +#define _ROUND_UP(x,n) (((x)+(n)-1u) & ~((n)-1u)) + +// to be ok for alpha and others we have to align structures to 8 byte +// boundary. +// FIXME: do not change 4 by anything else: there is code which relies on that +#define ROUND_UP(x) _ROUND_UP(x,8LL) + +/* debug levels. Right now, CONFIG_REISERFS_CHECK means print all debug +** messages. +*/ +#define REISERFS_DEBUG_CODE 5 /* extra messages to help find/debug errors */ + +void __reiserfs_warning(struct super_block *s, const char *id, + const char *func, const char *fmt, ...); +#define reiserfs_warning(s, id, fmt, args...) \ + __reiserfs_warning(s, id, __func__, fmt, ##args) +/* assertions handling */ + +/** always check a condition and panic if it's false. */ +#define __RASSERT(cond, scond, format, args...) \ +do { \ + if (!(cond)) \ + reiserfs_panic(NULL, "assertion failure", "(" #cond ") at " \ + __FILE__ ":%i:%s: " format "\n", \ + in_interrupt() ? -1 : task_pid_nr(current), \ + __LINE__, __func__ , ##args); \ +} while (0) + +#define RASSERT(cond, format, args...) __RASSERT(cond, #cond, format, ##args) + +#if defined( CONFIG_REISERFS_CHECK ) +#define RFALSE(cond, format, args...) __RASSERT(!(cond), "!(" #cond ")", format, ##args) +#else +#define RFALSE( cond, format, args... ) do {;} while( 0 ) +#endif + +#define CONSTF __attribute_const__ +/* + * Disk Data Structures + */ + +/***************************************************************************/ +/* SUPER BLOCK */ +/***************************************************************************/ + +/* + * Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs + * the version in RAM is part of a larger structure containing fields never written to disk. + */ +#define UNSET_HASH 0 // read_super will guess about, what hash names + // in directories were sorted with +#define TEA_HASH 1 +#define YURA_HASH 2 +#define R5_HASH 3 +#define DEFAULT_HASH R5_HASH + +struct journal_params { + __le32 jp_journal_1st_block; /* where does journal start from on its + * device */ + __le32 jp_journal_dev; /* journal device st_rdev */ + __le32 jp_journal_size; /* size of the journal */ + __le32 jp_journal_trans_max; /* max number of blocks in a transaction. */ + __le32 jp_journal_magic; /* random value made on fs creation (this + * was sb_journal_block_count) */ + __le32 jp_journal_max_batch; /* max number of blocks to batch into a + * trans */ + __le32 jp_journal_max_commit_age; /* in seconds, how old can an async + * commit be */ + __le32 jp_journal_max_trans_age; /* in seconds, how old can a transaction + * be */ +}; + +/* this is the super from 3.5.X, where X >= 10 */ +struct reiserfs_super_block_v1 { + __le32 s_block_count; /* blocks count */ + __le32 s_free_blocks; /* free blocks count */ + __le32 s_root_block; /* root block number */ + struct journal_params s_journal; + __le16 s_blocksize; /* block size */ + __le16 s_oid_maxsize; /* max size of object id array, see + * get_objectid() commentary */ + __le16 s_oid_cursize; /* current size of object id array */ + __le16 s_umount_state; /* this is set to 1 when filesystem was + * umounted, to 2 - when not */ + char s_magic[10]; /* reiserfs magic string indicates that + * file system is reiserfs: + * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */ + __le16 s_fs_state; /* it is set to used by fsck to mark which + * phase of rebuilding is done */ + __le32 s_hash_function_code; /* indicate, what hash function is being use + * to sort names in a directory*/ + __le16 s_tree_height; /* height of disk tree */ + __le16 s_bmap_nr; /* amount of bitmap blocks needed to address + * each block of file system */ + __le16 s_version; /* this field is only reliable on filesystem + * with non-standard journal */ + __le16 s_reserved_for_journal; /* size in blocks of journal area on main + * device, we need to keep after + * making fs with non-standard journal */ +} __attribute__ ((__packed__)); + +#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1)) + +/* this is the on disk super block */ +struct reiserfs_super_block { + struct reiserfs_super_block_v1 s_v1; + __le32 s_inode_generation; + __le32 s_flags; /* Right now used only by inode-attributes, if enabled */ + unsigned char s_uuid[16]; /* filesystem unique identifier */ + unsigned char s_label[16]; /* filesystem volume label */ + __le16 s_mnt_count; /* Count of mounts since last fsck */ + __le16 s_max_mnt_count; /* Maximum mounts before check */ + __le32 s_lastcheck; /* Timestamp of last fsck */ + __le32 s_check_interval; /* Interval between checks */ + char s_unused[76]; /* zero filled by mkreiserfs and + * reiserfs_convert_objectid_map_v1() + * so any additions must be updated + * there as well. */ +} __attribute__ ((__packed__)); + +#define SB_SIZE (sizeof(struct reiserfs_super_block)) + +#define REISERFS_VERSION_1 0 +#define REISERFS_VERSION_2 2 + +// on-disk super block fields converted to cpu form +#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs) +#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1)) +#define SB_BLOCKSIZE(s) \ + le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_blocksize)) +#define SB_BLOCK_COUNT(s) \ + le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_block_count)) +#define SB_FREE_BLOCKS(s) \ + le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks)) +#define SB_REISERFS_MAGIC(s) \ + (SB_V1_DISK_SUPER_BLOCK(s)->s_magic) +#define SB_ROOT_BLOCK(s) \ + le32_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_root_block)) +#define SB_TREE_HEIGHT(s) \ + le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height)) +#define SB_REISERFS_STATE(s) \ + le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state)) +#define SB_VERSION(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_version)) +#define SB_BMAP_NR(s) le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr)) + +#define PUT_SB_BLOCK_COUNT(s, val) \ + do { SB_V1_DISK_SUPER_BLOCK(s)->s_block_count = cpu_to_le32(val); } while (0) +#define PUT_SB_FREE_BLOCKS(s, val) \ + do { SB_V1_DISK_SUPER_BLOCK(s)->s_free_blocks = cpu_to_le32(val); } while (0) +#define PUT_SB_ROOT_BLOCK(s, val) \ + do { SB_V1_DISK_SUPER_BLOCK(s)->s_root_block = cpu_to_le32(val); } while (0) +#define PUT_SB_TREE_HEIGHT(s, val) \ + do { SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height = cpu_to_le16(val); } while (0) +#define PUT_SB_REISERFS_STATE(s, val) \ + do { SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state = cpu_to_le16(val); } while (0) +#define PUT_SB_VERSION(s, val) \ + do { SB_V1_DISK_SUPER_BLOCK(s)->s_version = cpu_to_le16(val); } while (0) +#define PUT_SB_BMAP_NR(s, val) \ + do { SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr = cpu_to_le16 (val); } while (0) + +#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal) +#define SB_ONDISK_JOURNAL_SIZE(s) \ + le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size)) +#define SB_ONDISK_JOURNAL_1st_BLOCK(s) \ + le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_1st_block)) +#define SB_ONDISK_JOURNAL_DEVICE(s) \ + le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_dev)) +#define SB_ONDISK_RESERVED_FOR_JOURNAL(s) \ + le16_to_cpu ((SB_V1_DISK_SUPER_BLOCK(s)->s_reserved_for_journal)) + +#define is_block_in_log_or_reserved_area(s, block) \ + block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \ + && block < SB_JOURNAL_1st_RESERVED_BLOCK(s) + \ + ((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \ + SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s))) + +int is_reiserfs_3_5(struct reiserfs_super_block *rs); +int is_reiserfs_3_6(struct reiserfs_super_block *rs); +int is_reiserfs_jr(struct reiserfs_super_block *rs); + +/* ReiserFS leaves the first 64k unused, so that partition labels have + enough space. If someone wants to write a fancy bootloader that + needs more than 64k, let us know, and this will be increased in size. + This number must be larger than than the largest block size on any + platform, or code will break. -Hans */ +#define REISERFS_DISK_OFFSET_IN_BYTES (64 * 1024) +#define REISERFS_FIRST_BLOCK unused_define +#define REISERFS_JOURNAL_OFFSET_IN_BYTES REISERFS_DISK_OFFSET_IN_BYTES + +/* the spot for the super in versions 3.5 - 3.5.10 (inclusive) */ +#define REISERFS_OLD_DISK_OFFSET_IN_BYTES (8 * 1024) + +/* reiserfs internal error code (used by search_by_key and fix_nodes)) */ +#define CARRY_ON 0 +#define REPEAT_SEARCH -1 +#define IO_ERROR -2 +#define NO_DISK_SPACE -3 +#define NO_BALANCING_NEEDED (-4) +#define NO_MORE_UNUSED_CONTIGUOUS_BLOCKS (-5) +#define QUOTA_EXCEEDED -6 + +typedef __u32 b_blocknr_t; +typedef __le32 unp_t; + +struct unfm_nodeinfo { + unp_t unfm_nodenum; + unsigned short unfm_freespace; +}; + +/* there are two formats of keys: 3.5 and 3.6 + */ +#define KEY_FORMAT_3_5 0 +#define KEY_FORMAT_3_6 1 + +/* there are two stat datas */ +#define STAT_DATA_V1 0 +#define STAT_DATA_V2 1 + +static inline struct reiserfs_inode_info *REISERFS_I(const struct inode *inode) +{ + return container_of(inode, struct reiserfs_inode_info, vfs_inode); +} + +static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb) +{ + return sb->s_fs_info; +} + +/* Don't trust REISERFS_SB(sb)->s_bmap_nr, it's a u16 + * which overflows on large file systems. */ +static inline __u32 reiserfs_bmap_count(struct super_block *sb) +{ + return (SB_BLOCK_COUNT(sb) - 1) / (sb->s_blocksize * 8) + 1; +} + +static inline int bmap_would_wrap(unsigned bmap_nr) +{ + return bmap_nr > ((1LL << 16) - 1); +} + +/** this says about version of key of all items (but stat data) the + object consists of */ +#define get_inode_item_key_version( inode ) \ + ((REISERFS_I(inode)->i_flags & i_item_key_version_mask) ? KEY_FORMAT_3_6 : KEY_FORMAT_3_5) + +#define set_inode_item_key_version( inode, version ) \ + ({ if((version)==KEY_FORMAT_3_6) \ + REISERFS_I(inode)->i_flags |= i_item_key_version_mask; \ + else \ + REISERFS_I(inode)->i_flags &= ~i_item_key_version_mask; }) + +#define get_inode_sd_version(inode) \ + ((REISERFS_I(inode)->i_flags & i_stat_data_version_mask) ? STAT_DATA_V2 : STAT_DATA_V1) + +#define set_inode_sd_version(inode, version) \ + ({ if((version)==STAT_DATA_V2) \ + REISERFS_I(inode)->i_flags |= i_stat_data_version_mask; \ + else \ + REISERFS_I(inode)->i_flags &= ~i_stat_data_version_mask; }) + +/* This is an aggressive tail suppression policy, I am hoping it + improves our benchmarks. The principle behind it is that percentage + space saving is what matters, not absolute space saving. This is + non-intuitive, but it helps to understand it if you consider that the + cost to access 4 blocks is not much more than the cost to access 1 + block, if you have to do a seek and rotate. A tail risks a + non-linear disk access that is significant as a percentage of total + time cost for a 4 block file and saves an amount of space that is + less significant as a percentage of space, or so goes the hypothesis. + -Hans */ +#define STORE_TAIL_IN_UNFM_S1(n_file_size,n_tail_size,n_block_size) \ +(\ + (!(n_tail_size)) || \ + (((n_tail_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) || \ + ( (n_file_size) >= (n_block_size) * 4 ) || \ + ( ( (n_file_size) >= (n_block_size) * 3 ) && \ + ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/4) ) || \ + ( ( (n_file_size) >= (n_block_size) * 2 ) && \ + ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size))/2) ) || \ + ( ( (n_file_size) >= (n_block_size) ) && \ + ( (n_tail_size) >= (MAX_DIRECT_ITEM_LEN(n_block_size) * 3)/4) ) ) \ +) + +/* Another strategy for tails, this one means only create a tail if all the + file would fit into one DIRECT item. + Primary intention for this one is to increase performance by decreasing + seeking. +*/ +#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \ +(\ + (!(n_tail_size)) || \ + (((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \ +) + +/* + * values for s_umount_state field + */ +#define REISERFS_VALID_FS 1 +#define REISERFS_ERROR_FS 2 + +// +// there are 5 item types currently +// +#define TYPE_STAT_DATA 0 +#define TYPE_INDIRECT 1 +#define TYPE_DIRECT 2 +#define TYPE_DIRENTRY 3 +#define TYPE_MAXTYPE 3 +#define TYPE_ANY 15 // FIXME: comment is required + +/***************************************************************************/ +/* KEY & ITEM HEAD */ +/***************************************************************************/ + +// +// directories use this key as well as old files +// +struct offset_v1 { + __le32 k_offset; + __le32 k_uniqueness; +} __attribute__ ((__packed__)); + +struct offset_v2 { + __le64 v; +} __attribute__ ((__packed__)); + +static inline __u16 offset_v2_k_type(const struct offset_v2 *v2) +{ + __u8 type = le64_to_cpu(v2->v) >> 60; + return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY; +} + +static inline void set_offset_v2_k_type(struct offset_v2 *v2, int type) +{ + v2->v = + (v2->v & cpu_to_le64(~0ULL >> 4)) | cpu_to_le64((__u64) type << 60); +} + +static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2) +{ + return le64_to_cpu(v2->v) & (~0ULL >> 4); +} + +static inline void set_offset_v2_k_offset(struct offset_v2 *v2, loff_t offset) +{ + offset &= (~0ULL >> 4); + v2->v = (v2->v & cpu_to_le64(15ULL << 60)) | cpu_to_le64(offset); +} + +/* Key of an item determines its location in the S+tree, and + is composed of 4 components */ +struct reiserfs_key { + __le32 k_dir_id; /* packing locality: by default parent + directory object id */ + __le32 k_objectid; /* object identifier */ + union { + struct offset_v1 k_offset_v1; + struct offset_v2 k_offset_v2; + } __attribute__ ((__packed__)) u; +} __attribute__ ((__packed__)); + +struct in_core_key { + __u32 k_dir_id; /* packing locality: by default parent + directory object id */ + __u32 k_objectid; /* object identifier */ + __u64 k_offset; + __u8 k_type; +}; + +struct cpu_key { + struct in_core_key on_disk_key; + int version; + int key_length; /* 3 in all cases but direct2indirect and + indirect2direct conversion */ +}; + +/* Our function for comparing keys can compare keys of different + lengths. It takes as a parameter the length of the keys it is to + compare. These defines are used in determining what is to be passed + to it as that parameter. */ +#define REISERFS_FULL_KEY_LEN 4 +#define REISERFS_SHORT_KEY_LEN 2 + +/* The result of the key compare */ +#define FIRST_GREATER 1 +#define SECOND_GREATER -1 +#define KEYS_IDENTICAL 0 +#define KEY_FOUND 1 +#define KEY_NOT_FOUND 0 + +#define KEY_SIZE (sizeof(struct reiserfs_key)) +#define SHORT_KEY_SIZE (sizeof (__u32) + sizeof (__u32)) + +/* return values for search_by_key and clones */ +#define ITEM_FOUND 1 +#define ITEM_NOT_FOUND 0 +#define ENTRY_FOUND 1 +#define ENTRY_NOT_FOUND 0 +#define DIRECTORY_NOT_FOUND -1 +#define REGULAR_FILE_FOUND -2 +#define DIRECTORY_FOUND -3 +#define BYTE_FOUND 1 +#define BYTE_NOT_FOUND 0 +#define FILE_NOT_FOUND -1 + +#define POSITION_FOUND 1 +#define POSITION_NOT_FOUND 0 + +// return values for reiserfs_find_entry and search_by_entry_key +#define NAME_FOUND 1 +#define NAME_NOT_FOUND 0 +#define GOTO_PREVIOUS_ITEM 2 +#define NAME_FOUND_INVISIBLE 3 + +/* Everything in the filesystem is stored as a set of items. The + item head contains the key of the item, its free space (for + indirect items) and specifies the location of the item itself + within the block. */ + +struct item_head { + /* Everything in the tree is found by searching for it based on + * its key.*/ + struct reiserfs_key ih_key; + union { + /* The free space in the last unformatted node of an + indirect item if this is an indirect item. This + equals 0xFFFF iff this is a direct item or stat data + item. Note that the key, not this field, is used to + determine the item type, and thus which field this + union contains. */ + __le16 ih_free_space_reserved; + /* Iff this is a directory item, this field equals the + number of directory entries in the directory item. */ + __le16 ih_entry_count; + } __attribute__ ((__packed__)) u; + __le16 ih_item_len; /* total size of the item body */ + __le16 ih_item_location; /* an offset to the item body + * within the block */ + __le16 ih_version; /* 0 for all old items, 2 for new + ones. Highest bit is set by fsck + temporary, cleaned after all + done */ +} __attribute__ ((__packed__)); +/* size of item header */ +#define IH_SIZE (sizeof(struct item_head)) + +#define ih_free_space(ih) le16_to_cpu((ih)->u.ih_free_space_reserved) +#define ih_version(ih) le16_to_cpu((ih)->ih_version) +#define ih_entry_count(ih) le16_to_cpu((ih)->u.ih_entry_count) +#define ih_location(ih) le16_to_cpu((ih)->ih_item_location) +#define ih_item_len(ih) le16_to_cpu((ih)->ih_item_len) + +#define put_ih_free_space(ih, val) do { (ih)->u.ih_free_space_reserved = cpu_to_le16(val); } while(0) +#define put_ih_version(ih, val) do { (ih)->ih_version = cpu_to_le16(val); } while (0) +#define put_ih_entry_count(ih, val) do { (ih)->u.ih_entry_count = cpu_to_le16(val); } while (0) +#define put_ih_location(ih, val) do { (ih)->ih_item_location = cpu_to_le16(val); } while (0) +#define put_ih_item_len(ih, val) do { (ih)->ih_item_len = cpu_to_le16(val); } while (0) + +#define unreachable_item(ih) (ih_version(ih) & (1 << 15)) + +#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih)) +#define set_ih_free_space(ih,val) put_ih_free_space((ih), ((ih_version(ih) == KEY_FORMAT_3_6) ? 0 : (val))) + +/* these operate on indirect items, where you've got an array of ints +** at a possibly unaligned location. These are a noop on ia32 +** +** p is the array of __u32, i is the index into the array, v is the value +** to store there. +*/ +#define get_block_num(p, i) get_unaligned_le32((p) + (i)) +#define put_block_num(p, i, v) put_unaligned_le32((v), (p) + (i)) + +// +// in old version uniqueness field shows key type +// +#define V1_SD_UNIQUENESS 0 +#define V1_INDIRECT_UNIQUENESS 0xfffffffe +#define V1_DIRECT_UNIQUENESS 0xffffffff +#define V1_DIRENTRY_UNIQUENESS 500 +#define V1_ANY_UNIQUENESS 555 // FIXME: comment is required + +// +// here are conversion routines +// +static inline int uniqueness2type(__u32 uniqueness) CONSTF; +static inline int uniqueness2type(__u32 uniqueness) +{ + switch ((int)uniqueness) { + case V1_SD_UNIQUENESS: + return TYPE_STAT_DATA; + case V1_INDIRECT_UNIQUENESS: + return TYPE_INDIRECT; + case V1_DIRECT_UNIQUENESS: + return TYPE_DIRECT; + case V1_DIRENTRY_UNIQUENESS: + return TYPE_DIRENTRY; + case V1_ANY_UNIQUENESS: + default: + return TYPE_ANY; + } +} + +static inline __u32 type2uniqueness(int type) CONSTF; +static inline __u32 type2uniqueness(int type) +{ + switch (type) { + case TYPE_STAT_DATA: + return V1_SD_UNIQUENESS; + case TYPE_INDIRECT: + return V1_INDIRECT_UNIQUENESS; + case TYPE_DIRECT: + return V1_DIRECT_UNIQUENESS; + case TYPE_DIRENTRY: + return V1_DIRENTRY_UNIQUENESS; + case TYPE_ANY: + default: + return V1_ANY_UNIQUENESS; + } +} + +// +// key is pointer to on disk key which is stored in le, result is cpu, +// there is no way to get version of object from key, so, provide +// version to these defines +// +static inline loff_t le_key_k_offset(int version, + const struct reiserfs_key *key) +{ + return (version == KEY_FORMAT_3_5) ? + le32_to_cpu(key->u.k_offset_v1.k_offset) : + offset_v2_k_offset(&(key->u.k_offset_v2)); +} + +static inline loff_t le_ih_k_offset(const struct item_head *ih) +{ + return le_key_k_offset(ih_version(ih), &(ih->ih_key)); +} + +static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key) +{ + return (version == KEY_FORMAT_3_5) ? + uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) : + offset_v2_k_type(&(key->u.k_offset_v2)); +} + +static inline loff_t le_ih_k_type(const struct item_head *ih) +{ + return le_key_k_type(ih_version(ih), &(ih->ih_key)); +} + +static inline void set_le_key_k_offset(int version, struct reiserfs_key *key, + loff_t offset) +{ + (version == KEY_FORMAT_3_5) ? (void)(key->u.k_offset_v1.k_offset = cpu_to_le32(offset)) : /* jdm check */ + (void)(set_offset_v2_k_offset(&(key->u.k_offset_v2), offset)); +} + +static inline void set_le_ih_k_offset(struct item_head *ih, loff_t offset) +{ + set_le_key_k_offset(ih_version(ih), &(ih->ih_key), offset); +} + +static inline void set_le_key_k_type(int version, struct reiserfs_key *key, + int type) +{ + (version == KEY_FORMAT_3_5) ? + (void)(key->u.k_offset_v1.k_uniqueness = + cpu_to_le32(type2uniqueness(type))) + : (void)(set_offset_v2_k_type(&(key->u.k_offset_v2), type)); +} + +static inline void set_le_ih_k_type(struct item_head *ih, int type) +{ + set_le_key_k_type(ih_version(ih), &(ih->ih_key), type); +} + +static inline int is_direntry_le_key(int version, struct reiserfs_key *key) +{ + return le_key_k_type(version, key) == TYPE_DIRENTRY; +} + +static inline int is_direct_le_key(int version, struct reiserfs_key *key) +{ + return le_key_k_type(version, key) == TYPE_DIRECT; +} + +static inline int is_indirect_le_key(int version, struct reiserfs_key *key) +{ + return le_key_k_type(version, key) == TYPE_INDIRECT; +} + +static inline int is_statdata_le_key(int version, struct reiserfs_key *key) +{ + return le_key_k_type(version, key) == TYPE_STAT_DATA; +} + +// +// item header has version. +// +static inline int is_direntry_le_ih(struct item_head *ih) +{ + return is_direntry_le_key(ih_version(ih), &ih->ih_key); +} + +static inline int is_direct_le_ih(struct item_head *ih) +{ + return is_direct_le_key(ih_version(ih), &ih->ih_key); +} + +static inline int is_indirect_le_ih(struct item_head *ih) +{ + return is_indirect_le_key(ih_version(ih), &ih->ih_key); +} + +static inline int is_statdata_le_ih(struct item_head *ih) +{ + return is_statdata_le_key(ih_version(ih), &ih->ih_key); +} + +// +// key is pointer to cpu key, result is cpu +// +static inline loff_t cpu_key_k_offset(const struct cpu_key *key) +{ + return key->on_disk_key.k_offset; +} + +static inline loff_t cpu_key_k_type(const struct cpu_key *key) +{ + return key->on_disk_key.k_type; +} + +static inline void set_cpu_key_k_offset(struct cpu_key *key, loff_t offset) +{ + key->on_disk_key.k_offset = offset; +} + +static inline void set_cpu_key_k_type(struct cpu_key *key, int type) +{ + key->on_disk_key.k_type = type; +} + +static inline void cpu_key_k_offset_dec(struct cpu_key *key) +{ + key->on_disk_key.k_offset--; +} + +#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY) +#define is_direct_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRECT) +#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT) +#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA) + +/* are these used ? */ +#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key))) +#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key))) +#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key))) +#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key))) + +#define I_K_KEY_IN_ITEM(ih, key, n_blocksize) \ + (!COMP_SHORT_KEYS(ih, key) && \ + I_OFF_BYTE_IN_ITEM(ih, k_offset(key), n_blocksize)) + +/* maximal length of item */ +#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE) +#define MIN_ITEM_LEN 1 + +/* object identifier for root dir */ +#define REISERFS_ROOT_OBJECTID 2 +#define REISERFS_ROOT_PARENT_OBJECTID 1 + +extern struct reiserfs_key root_key; + +/* + * Picture represents a leaf of the S+tree + * ______________________________________________________ + * | | Array of | | | + * |Block | Object-Item | F r e e | Objects- | + * | head | Headers | S p a c e | Items | + * |______|_______________|___________________|___________| + */ + +/* Header of a disk block. More precisely, header of a formatted leaf + or internal node, and not the header of an unformatted node. */ +struct block_head { + __le16 blk_level; /* Level of a block in the tree. */ + __le16 blk_nr_item; /* Number of keys/items in a block. */ + __le16 blk_free_space; /* Block free space in bytes. */ + __le16 blk_reserved; + /* dump this in v4/planA */ + struct reiserfs_key blk_right_delim_key; /* kept only for compatibility */ +}; + +#define BLKH_SIZE (sizeof(struct block_head)) +#define blkh_level(p_blkh) (le16_to_cpu((p_blkh)->blk_level)) +#define blkh_nr_item(p_blkh) (le16_to_cpu((p_blkh)->blk_nr_item)) +#define blkh_free_space(p_blkh) (le16_to_cpu((p_blkh)->blk_free_space)) +#define blkh_reserved(p_blkh) (le16_to_cpu((p_blkh)->blk_reserved)) +#define set_blkh_level(p_blkh,val) ((p_blkh)->blk_level = cpu_to_le16(val)) +#define set_blkh_nr_item(p_blkh,val) ((p_blkh)->blk_nr_item = cpu_to_le16(val)) +#define set_blkh_free_space(p_blkh,val) ((p_blkh)->blk_free_space = cpu_to_le16(val)) +#define set_blkh_reserved(p_blkh,val) ((p_blkh)->blk_reserved = cpu_to_le16(val)) +#define blkh_right_delim_key(p_blkh) ((p_blkh)->blk_right_delim_key) +#define set_blkh_right_delim_key(p_blkh,val) ((p_blkh)->blk_right_delim_key = val) + +/* + * values for blk_level field of the struct block_head + */ + +#define FREE_LEVEL 0 /* when node gets removed from the tree its + blk_level is set to FREE_LEVEL. It is then + used to see whether the node is still in the + tree */ + +#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */ + +/* Given the buffer head of a formatted node, resolve to the block head of that node. */ +#define B_BLK_HEAD(bh) ((struct block_head *)((bh)->b_data)) +/* Number of items that are in buffer. */ +#define B_NR_ITEMS(bh) (blkh_nr_item(B_BLK_HEAD(bh))) +#define B_LEVEL(bh) (blkh_level(B_BLK_HEAD(bh))) +#define B_FREE_SPACE(bh) (blkh_free_space(B_BLK_HEAD(bh))) + +#define PUT_B_NR_ITEMS(bh, val) do { set_blkh_nr_item(B_BLK_HEAD(bh), val); } while (0) +#define PUT_B_LEVEL(bh, val) do { set_blkh_level(B_BLK_HEAD(bh), val); } while (0) +#define PUT_B_FREE_SPACE(bh, val) do { set_blkh_free_space(B_BLK_HEAD(bh), val); } while (0) + +/* Get right delimiting key. -- little endian */ +#define B_PRIGHT_DELIM_KEY(bh) (&(blk_right_delim_key(B_BLK_HEAD(bh)))) + +/* Does the buffer contain a disk leaf. */ +#define B_IS_ITEMS_LEVEL(bh) (B_LEVEL(bh) == DISK_LEAF_NODE_LEVEL) + +/* Does the buffer contain a disk internal node */ +#define B_IS_KEYS_LEVEL(bh) (B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL \ + && B_LEVEL(bh) <= MAX_HEIGHT) + +/***************************************************************************/ +/* STAT DATA */ +/***************************************************************************/ + +// +// old stat data is 32 bytes long. We are going to distinguish new one by +// different size +// +struct stat_data_v1 { + __le16 sd_mode; /* file type, permissions */ + __le16 sd_nlink; /* number of hard links */ + __le16 sd_uid; /* owner */ + __le16 sd_gid; /* group */ + __le32 sd_size; /* file size */ + __le32 sd_atime; /* time of last access */ + __le32 sd_mtime; /* time file was last modified */ + __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ + union { + __le32 sd_rdev; + __le32 sd_blocks; /* number of blocks file uses */ + } __attribute__ ((__packed__)) u; + __le32 sd_first_direct_byte; /* first byte of file which is stored + in a direct item: except that if it + equals 1 it is a symlink and if it + equals ~(__u32)0 there is no + direct item. The existence of this + field really grates on me. Let's + replace it with a macro based on + sd_size and our tail suppression + policy. Someday. -Hans */ +} __attribute__ ((__packed__)); + +#define SD_V1_SIZE (sizeof(struct stat_data_v1)) +#define stat_data_v1(ih) (ih_version (ih) == KEY_FORMAT_3_5) +#define sd_v1_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) +#define set_sd_v1_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) +#define sd_v1_nlink(sdp) (le16_to_cpu((sdp)->sd_nlink)) +#define set_sd_v1_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le16(v)) +#define sd_v1_uid(sdp) (le16_to_cpu((sdp)->sd_uid)) +#define set_sd_v1_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le16(v)) +#define sd_v1_gid(sdp) (le16_to_cpu((sdp)->sd_gid)) +#define set_sd_v1_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le16(v)) +#define sd_v1_size(sdp) (le32_to_cpu((sdp)->sd_size)) +#define set_sd_v1_size(sdp,v) ((sdp)->sd_size = cpu_to_le32(v)) +#define sd_v1_atime(sdp) (le32_to_cpu((sdp)->sd_atime)) +#define set_sd_v1_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v)) +#define sd_v1_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime)) +#define set_sd_v1_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v)) +#define sd_v1_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime)) +#define set_sd_v1_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v)) +#define sd_v1_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev)) +#define set_sd_v1_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v)) +#define sd_v1_blocks(sdp) (le32_to_cpu((sdp)->u.sd_blocks)) +#define set_sd_v1_blocks(sdp,v) ((sdp)->u.sd_blocks = cpu_to_le32(v)) +#define sd_v1_first_direct_byte(sdp) \ + (le32_to_cpu((sdp)->sd_first_direct_byte)) +#define set_sd_v1_first_direct_byte(sdp,v) \ + ((sdp)->sd_first_direct_byte = cpu_to_le32(v)) + +/* inode flags stored in sd_attrs (nee sd_reserved) */ + +/* we want common flags to have the same values as in ext2, + so chattr(1) will work without problems */ +#define REISERFS_IMMUTABLE_FL FS_IMMUTABLE_FL +#define REISERFS_APPEND_FL FS_APPEND_FL +#define REISERFS_SYNC_FL FS_SYNC_FL +#define REISERFS_NOATIME_FL FS_NOATIME_FL +#define REISERFS_NODUMP_FL FS_NODUMP_FL +#define REISERFS_SECRM_FL FS_SECRM_FL +#define REISERFS_UNRM_FL FS_UNRM_FL +#define REISERFS_COMPR_FL FS_COMPR_FL +#define REISERFS_NOTAIL_FL FS_NOTAIL_FL + +/* persistent flags that file inherits from the parent directory */ +#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \ + REISERFS_SYNC_FL | \ + REISERFS_NOATIME_FL | \ + REISERFS_NODUMP_FL | \ + REISERFS_SECRM_FL | \ + REISERFS_COMPR_FL | \ + REISERFS_NOTAIL_FL ) + +/* Stat Data on disk (reiserfs version of UFS disk inode minus the + address blocks) */ +struct stat_data { + __le16 sd_mode; /* file type, permissions */ + __le16 sd_attrs; /* persistent inode flags */ + __le32 sd_nlink; /* number of hard links */ + __le64 sd_size; /* file size */ + __le32 sd_uid; /* owner */ + __le32 sd_gid; /* group */ + __le32 sd_atime; /* time of last access */ + __le32 sd_mtime; /* time file was last modified */ + __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */ + __le32 sd_blocks; + union { + __le32 sd_rdev; + __le32 sd_generation; + //__le32 sd_first_direct_byte; + /* first byte of file which is stored in a + direct item: except that if it equals 1 + it is a symlink and if it equals + ~(__u32)0 there is no direct item. The + existence of this field really grates + on me. Let's replace it with a macro + based on sd_size and our tail + suppression policy? */ + } __attribute__ ((__packed__)) u; +} __attribute__ ((__packed__)); +// +// this is 44 bytes long +// +#define SD_SIZE (sizeof(struct stat_data)) +#define SD_V2_SIZE SD_SIZE +#define stat_data_v2(ih) (ih_version (ih) == KEY_FORMAT_3_6) +#define sd_v2_mode(sdp) (le16_to_cpu((sdp)->sd_mode)) +#define set_sd_v2_mode(sdp,v) ((sdp)->sd_mode = cpu_to_le16(v)) +/* sd_reserved */ +/* set_sd_reserved */ +#define sd_v2_nlink(sdp) (le32_to_cpu((sdp)->sd_nlink)) +#define set_sd_v2_nlink(sdp,v) ((sdp)->sd_nlink = cpu_to_le32(v)) +#define sd_v2_size(sdp) (le64_to_cpu((sdp)->sd_size)) +#define set_sd_v2_size(sdp,v) ((sdp)->sd_size = cpu_to_le64(v)) +#define sd_v2_uid(sdp) (le32_to_cpu((sdp)->sd_uid)) +#define set_sd_v2_uid(sdp,v) ((sdp)->sd_uid = cpu_to_le32(v)) +#define sd_v2_gid(sdp) (le32_to_cpu((sdp)->sd_gid)) +#define set_sd_v2_gid(sdp,v) ((sdp)->sd_gid = cpu_to_le32(v)) +#define sd_v2_atime(sdp) (le32_to_cpu((sdp)->sd_atime)) +#define set_sd_v2_atime(sdp,v) ((sdp)->sd_atime = cpu_to_le32(v)) +#define sd_v2_mtime(sdp) (le32_to_cpu((sdp)->sd_mtime)) +#define set_sd_v2_mtime(sdp,v) ((sdp)->sd_mtime = cpu_to_le32(v)) +#define sd_v2_ctime(sdp) (le32_to_cpu((sdp)->sd_ctime)) +#define set_sd_v2_ctime(sdp,v) ((sdp)->sd_ctime = cpu_to_le32(v)) +#define sd_v2_blocks(sdp) (le32_to_cpu((sdp)->sd_blocks)) +#define set_sd_v2_blocks(sdp,v) ((sdp)->sd_blocks = cpu_to_le32(v)) +#define sd_v2_rdev(sdp) (le32_to_cpu((sdp)->u.sd_rdev)) +#define set_sd_v2_rdev(sdp,v) ((sdp)->u.sd_rdev = cpu_to_le32(v)) +#define sd_v2_generation(sdp) (le32_to_cpu((sdp)->u.sd_generation)) +#define set_sd_v2_generation(sdp,v) ((sdp)->u.sd_generation = cpu_to_le32(v)) +#define sd_v2_attrs(sdp) (le16_to_cpu((sdp)->sd_attrs)) +#define set_sd_v2_attrs(sdp,v) ((sdp)->sd_attrs = cpu_to_le16(v)) + +/***************************************************************************/ +/* DIRECTORY STRUCTURE */ +/***************************************************************************/ +/* + Picture represents the structure of directory items + ________________________________________________ + | Array of | | | | | | + | directory |N-1| N-2 | .... | 1st |0th| + | entry headers | | | | | | + |_______________|___|_____|________|_______|___| + <---- directory entries ------> + + First directory item has k_offset component 1. We store "." and ".." + in one item, always, we never split "." and ".." into differing + items. This makes, among other things, the code for removing + directories simpler. */ +#define SD_OFFSET 0 +#define SD_UNIQUENESS 0 +#define DOT_OFFSET 1 +#define DOT_DOT_OFFSET 2 +#define DIRENTRY_UNIQUENESS 500 + +/* */ +#define FIRST_ITEM_OFFSET 1 + +/* + Q: How to get key of object pointed to by entry from entry? + + A: Each directory entry has its header. This header has deh_dir_id and deh_objectid fields, those are key + of object, entry points to */ + +/* NOT IMPLEMENTED: + Directory will someday contain stat data of object */ + +struct reiserfs_de_head { + __le32 deh_offset; /* third component of the directory entry key */ + __le32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced + by directory entry */ + __le32 deh_objectid; /* objectid of the object, that is referenced by directory entry */ + __le16 deh_location; /* offset of name in the whole item */ + __le16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether + entry is hidden (unlinked) */ +} __attribute__ ((__packed__)); +#define DEH_SIZE sizeof(struct reiserfs_de_head) +#define deh_offset(p_deh) (le32_to_cpu((p_deh)->deh_offset)) +#define deh_dir_id(p_deh) (le32_to_cpu((p_deh)->deh_dir_id)) +#define deh_objectid(p_deh) (le32_to_cpu((p_deh)->deh_objectid)) +#define deh_location(p_deh) (le16_to_cpu((p_deh)->deh_location)) +#define deh_state(p_deh) (le16_to_cpu((p_deh)->deh_state)) + +#define put_deh_offset(p_deh,v) ((p_deh)->deh_offset = cpu_to_le32((v))) +#define put_deh_dir_id(p_deh,v) ((p_deh)->deh_dir_id = cpu_to_le32((v))) +#define put_deh_objectid(p_deh,v) ((p_deh)->deh_objectid = cpu_to_le32((v))) +#define put_deh_location(p_deh,v) ((p_deh)->deh_location = cpu_to_le16((v))) +#define put_deh_state(p_deh,v) ((p_deh)->deh_state = cpu_to_le16((v))) + +/* empty directory contains two entries "." and ".." and their headers */ +#define EMPTY_DIR_SIZE \ +(DEH_SIZE * 2 + ROUND_UP (strlen (".")) + ROUND_UP (strlen (".."))) + +/* old format directories have this size when empty */ +#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3) + +#define DEH_Statdata 0 /* not used now */ +#define DEH_Visible 2 + +/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */ +#if BITS_PER_LONG == 64 || defined(__s390__) || defined(__hppa__) +# define ADDR_UNALIGNED_BITS (3) +#endif + +/* These are only used to manipulate deh_state. + * Because of this, we'll use the ext2_ bit routines, + * since they are little endian */ +#ifdef ADDR_UNALIGNED_BITS + +# define aligned_address(addr) ((void *)((long)(addr) & ~((1UL << ADDR_UNALIGNED_BITS) - 1))) +# define unaligned_offset(addr) (((int)((long)(addr) & ((1 << ADDR_UNALIGNED_BITS) - 1))) << 3) + +# define set_bit_unaligned(nr, addr) \ + __test_and_set_bit_le((nr) + unaligned_offset(addr), aligned_address(addr)) +# define clear_bit_unaligned(nr, addr) \ + __test_and_clear_bit_le((nr) + unaligned_offset(addr), aligned_address(addr)) +# define test_bit_unaligned(nr, addr) \ + test_bit_le((nr) + unaligned_offset(addr), aligned_address(addr)) + +#else + +# define set_bit_unaligned(nr, addr) __test_and_set_bit_le(nr, addr) +# define clear_bit_unaligned(nr, addr) __test_and_clear_bit_le(nr, addr) +# define test_bit_unaligned(nr, addr) test_bit_le(nr, addr) + +#endif + +#define mark_de_with_sd(deh) set_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) +#define mark_de_without_sd(deh) clear_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) +#define mark_de_visible(deh) set_bit_unaligned (DEH_Visible, &((deh)->deh_state)) +#define mark_de_hidden(deh) clear_bit_unaligned (DEH_Visible, &((deh)->deh_state)) + +#define de_with_sd(deh) test_bit_unaligned (DEH_Statdata, &((deh)->deh_state)) +#define de_visible(deh) test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) +#define de_hidden(deh) !test_bit_unaligned (DEH_Visible, &((deh)->deh_state)) + +extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid, + __le32 par_dirid, __le32 par_objid); +extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid, + __le32 par_dirid, __le32 par_objid); + +/* array of the entry headers */ + /* get item body */ +#define B_I_PITEM(bh,ih) ( (bh)->b_data + ih_location(ih) ) +#define B_I_DEH(bh,ih) ((struct reiserfs_de_head *)(B_I_PITEM(bh,ih))) + +/* length of the directory entry in directory item. This define + calculates length of i-th directory entry using directory entry + locations from dir entry head. When it calculates length of 0-th + directory entry, it uses length of whole item in place of entry + location of the non-existent following entry in the calculation. + See picture above.*/ +/* +#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \ +((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh)))) +*/ +static inline int entry_length(const struct buffer_head *bh, + const struct item_head *ih, int pos_in_item) +{ + struct reiserfs_de_head *deh; + + deh = B_I_DEH(bh, ih) + pos_in_item; + if (pos_in_item) + return deh_location(deh - 1) - deh_location(deh); + + return ih_item_len(ih) - deh_location(deh); +} + +/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */ +#define I_ENTRY_COUNT(ih) (ih_entry_count((ih))) + +/* name by bh, ih and entry_num */ +#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num)))) + +// two entries per block (at least) +#define REISERFS_MAX_NAME(block_size) 255 + +/* this structure is used for operations on directory entries. It is + not a disk structure. */ +/* When reiserfs_find_entry or search_by_entry_key find directory + entry, they return filled reiserfs_dir_entry structure */ +struct reiserfs_dir_entry { + struct buffer_head *de_bh; + int de_item_num; + struct item_head *de_ih; + int de_entry_num; + struct reiserfs_de_head *de_deh; + int de_entrylen; + int de_namelen; + char *de_name; + unsigned long *de_gen_number_bit_string; + + __u32 de_dir_id; + __u32 de_objectid; + + struct cpu_key de_entry_key; +}; + +/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */ + +/* pointer to file name, stored in entry */ +#define B_I_DEH_ENTRY_FILE_NAME(bh,ih,deh) (B_I_PITEM (bh, ih) + deh_location(deh)) + +/* length of name */ +#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \ +(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0)) + +/* hash value occupies bits from 7 up to 30 */ +#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL) +/* generation number occupies 7 bits starting from 0 up to 6 */ +#define GET_GENERATION_NUMBER(offset) ((offset) & 0x7fLL) +#define MAX_GENERATION_NUMBER 127 + +#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number)) + +/* + * Picture represents an internal node of the reiserfs tree + * ______________________________________________________ + * | | Array of | Array of | Free | + * |block | keys | pointers | space | + * | head | N | N+1 | | + * |______|_______________|___________________|___________| + */ + +/***************************************************************************/ +/* DISK CHILD */ +/***************************************************************************/ +/* Disk child pointer: The pointer from an internal node of the tree + to a node that is on disk. */ +struct disk_child { + __le32 dc_block_number; /* Disk child's block number. */ + __le16 dc_size; /* Disk child's used space. */ + __le16 dc_reserved; +}; + +#define DC_SIZE (sizeof(struct disk_child)) +#define dc_block_number(dc_p) (le32_to_cpu((dc_p)->dc_block_number)) +#define dc_size(dc_p) (le16_to_cpu((dc_p)->dc_size)) +#define put_dc_block_number(dc_p, val) do { (dc_p)->dc_block_number = cpu_to_le32(val); } while(0) +#define put_dc_size(dc_p, val) do { (dc_p)->dc_size = cpu_to_le16(val); } while(0) + +/* Get disk child by buffer header and position in the tree node. */ +#define B_N_CHILD(bh, n_pos) ((struct disk_child *)\ +((bh)->b_data + BLKH_SIZE + B_NR_ITEMS(bh) * KEY_SIZE + DC_SIZE * (n_pos))) + +/* Get disk child number by buffer header and position in the tree node. */ +#define B_N_CHILD_NUM(bh, n_pos) (dc_block_number(B_N_CHILD(bh, n_pos))) +#define PUT_B_N_CHILD_NUM(bh, n_pos, val) \ + (put_dc_block_number(B_N_CHILD(bh, n_pos), val)) + + /* maximal value of field child_size in structure disk_child */ + /* child size is the combined size of all items and their headers */ +#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE )) + +/* amount of used space in buffer (not including block head) */ +#define B_CHILD_SIZE(cur) (MAX_CHILD_SIZE(cur)-(B_FREE_SPACE(cur))) + +/* max and min number of keys in internal node */ +#define MAX_NR_KEY(bh) ( (MAX_CHILD_SIZE(bh)-DC_SIZE)/(KEY_SIZE+DC_SIZE) ) +#define MIN_NR_KEY(bh) (MAX_NR_KEY(bh)/2) + +/***************************************************************************/ +/* PATH STRUCTURES AND DEFINES */ +/***************************************************************************/ + +/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the + key. It uses reiserfs_bread to try to find buffers in the cache given their block number. If it + does not find them in the cache it reads them from disk. For each node search_by_key finds using + reiserfs_bread it then uses bin_search to look through that node. bin_search will find the + position of the block_number of the next node if it is looking through an internal node. If it + is looking through a leaf node bin_search will find the position of the item which has key either + equal to given key, or which is the maximal key less than the given key. */ + +struct path_element { + struct buffer_head *pe_buffer; /* Pointer to the buffer at the path in the tree. */ + int pe_position; /* Position in the tree node which is placed in the */ + /* buffer above. */ +}; + +#define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */ +#define EXTENDED_MAX_HEIGHT 7 /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */ +#define FIRST_PATH_ELEMENT_OFFSET 2 /* Must be equal to at least 2. */ + +#define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */ +#define MAX_FEB_SIZE 6 /* this MUST be MAX_HEIGHT + 1. See about FEB below */ + +/* We need to keep track of who the ancestors of nodes are. When we + perform a search we record which nodes were visited while + descending the tree looking for the node we searched for. This list + of nodes is called the path. This information is used while + performing balancing. Note that this path information may become + invalid, and this means we must check it when using it to see if it + is still valid. You'll need to read search_by_key and the comments + in it, especially about decrement_counters_in_path(), to understand + this structure. + +Paths make the code so much harder to work with and debug.... An +enormous number of bugs are due to them, and trying to write or modify +code that uses them just makes my head hurt. They are based on an +excessive effort to avoid disturbing the precious VFS code.:-( The +gods only know how we are going to SMP the code that uses them. +znodes are the way! */ + +#define PATH_READA 0x1 /* do read ahead */ +#define PATH_READA_BACK 0x2 /* read backwards */ + +struct treepath { + int path_length; /* Length of the array above. */ + int reada; + struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */ + int pos_in_item; +}; + +#define pos_in_item(path) ((path)->pos_in_item) + +#define INITIALIZE_PATH(var) \ +struct treepath var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,} + +/* Get path element by path and path position. */ +#define PATH_OFFSET_PELEMENT(path, n_offset) ((path)->path_elements + (n_offset)) + +/* Get buffer header at the path by path and path position. */ +#define PATH_OFFSET_PBUFFER(path, n_offset) (PATH_OFFSET_PELEMENT(path, n_offset)->pe_buffer) + +/* Get position in the element at the path by path and path position. */ +#define PATH_OFFSET_POSITION(path, n_offset) (PATH_OFFSET_PELEMENT(path, n_offset)->pe_position) + +#define PATH_PLAST_BUFFER(path) (PATH_OFFSET_PBUFFER((path), (path)->path_length)) + /* you know, to the person who didn't + write this the macro name does not + at first suggest what it does. + Maybe POSITION_FROM_PATH_END? Or + maybe we should just focus on + dumping paths... -Hans */ +#define PATH_LAST_POSITION(path) (PATH_OFFSET_POSITION((path), (path)->path_length)) + +#define PATH_PITEM_HEAD(path) B_N_PITEM_HEAD(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION(path)) + +/* in do_balance leaf has h == 0 in contrast with path structure, + where root has level == 0. That is why we need these defines */ +#define PATH_H_PBUFFER(path, h) PATH_OFFSET_PBUFFER (path, path->path_length - (h)) /* tb->S[h] */ +#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */ +#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h)) +#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1) /* tb->S[h]->b_item_order */ + +#define PATH_H_PATH_OFFSET(path, n_h) ((path)->path_length - (n_h)) + +#define get_last_bh(path) PATH_PLAST_BUFFER(path) +#define get_ih(path) PATH_PITEM_HEAD(path) +#define get_item_pos(path) PATH_LAST_POSITION(path) +#define get_item(path) ((void *)B_N_PITEM(PATH_PLAST_BUFFER(path), PATH_LAST_POSITION (path))) +#define item_moved(ih,path) comp_items(ih, path) +#define path_changed(ih,path) comp_items (ih, path) + +/***************************************************************************/ +/* MISC */ +/***************************************************************************/ + +/* Size of pointer to the unformatted node. */ +#define UNFM_P_SIZE (sizeof(unp_t)) +#define UNFM_P_SHIFT 2 + +// in in-core inode key is stored on le form +#define INODE_PKEY(inode) ((struct reiserfs_key *)(REISERFS_I(inode)->i_key)) + +#define MAX_UL_INT 0xffffffff +#define MAX_INT 0x7ffffff +#define MAX_US_INT 0xffff + +// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset +#define U32_MAX (~(__u32)0) + +static inline loff_t max_reiserfs_offset(struct inode *inode) +{ + if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5) + return (loff_t) U32_MAX; + + return (loff_t) ((~(__u64) 0) >> 4); +} + +/*#define MAX_KEY_UNIQUENESS MAX_UL_INT*/ +#define MAX_KEY_OBJECTID MAX_UL_INT + +#define MAX_B_NUM MAX_UL_INT +#define MAX_FC_NUM MAX_US_INT + +/* the purpose is to detect overflow of an unsigned short */ +#define REISERFS_LINK_MAX (MAX_US_INT - 1000) + +/* The following defines are used in reiserfs_insert_item and reiserfs_append_item */ +#define REISERFS_KERNEL_MEM 0 /* reiserfs kernel memory mode */ +#define REISERFS_USER_MEM 1 /* reiserfs user memory mode */ + +#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter) +#define get_generation(s) atomic_read (&fs_generation(s)) +#define FILESYSTEM_CHANGED_TB(tb) (get_generation((tb)->tb_sb) != (tb)->fs_gen) +#define __fs_changed(gen,s) (gen != get_generation (s)) +#define fs_changed(gen,s) \ +({ \ + reiserfs_cond_resched(s); \ + __fs_changed(gen, s); \ +}) + +/***************************************************************************/ +/* FIXATE NODES */ +/***************************************************************************/ + +#define VI_TYPE_LEFT_MERGEABLE 1 +#define VI_TYPE_RIGHT_MERGEABLE 2 + +/* To make any changes in the tree we always first find node, that + contains item to be changed/deleted or place to insert a new + item. We call this node S. To do balancing we need to decide what + we will shift to left/right neighbor, or to a new node, where new + item will be etc. To make this analysis simpler we build virtual + node. Virtual node is an array of items, that will replace items of + node S. (For instance if we are going to delete an item, virtual + node does not contain it). Virtual node keeps information about + item sizes and types, mergeability of first and last items, sizes + of all entries in directory item. We use this array of items when + calculating what we can shift to neighbors and how many nodes we + have to have if we do not any shiftings, if we shift to left/right + neighbor or to both. */ +struct virtual_item { + int vi_index; // index in the array of item operations + unsigned short vi_type; // left/right mergeability + unsigned short vi_item_len; /* length of item that it will have after balancing */ + struct item_head *vi_ih; + const char *vi_item; // body of item (old or new) + const void *vi_new_data; // 0 always but paste mode + void *vi_uarea; // item specific area +}; + +struct virtual_node { + char *vn_free_ptr; /* this is a pointer to the free space in the buffer */ + unsigned short vn_nr_item; /* number of items in virtual node */ + short vn_size; /* size of node , that node would have if it has unlimited size and no balancing is performed */ + short vn_mode; /* mode of balancing (paste, insert, delete, cut) */ + short vn_affected_item_num; + short vn_pos_in_item; + struct item_head *vn_ins_ih; /* item header of inserted item, 0 for other modes */ + const void *vn_data; + struct virtual_item *vn_vi; /* array of items (including a new one, excluding item to be deleted) */ +}; + +/* used by directory items when creating virtual nodes */ +struct direntry_uarea { + int flags; + __u16 entry_count; + __u16 entry_sizes[1]; +} __attribute__ ((__packed__)); + +/***************************************************************************/ +/* TREE BALANCE */ +/***************************************************************************/ + +/* This temporary structure is used in tree balance algorithms, and + constructed as we go to the extent that its various parts are + needed. It contains arrays of nodes that can potentially be + involved in the balancing of node S, and parameters that define how + each of the nodes must be balanced. Note that in these algorithms + for balancing the worst case is to need to balance the current node + S and the left and right neighbors and all of their parents plus + create a new node. We implement S1 balancing for the leaf nodes + and S0 balancing for the internal nodes (S1 and S0 are defined in + our papers.)*/ + +#define MAX_FREE_BLOCK 7 /* size of the array of buffers to free at end of do_balance */ + +/* maximum number of FEB blocknrs on a single level */ +#define MAX_AMOUNT_NEEDED 2 + +/* someday somebody will prefix every field in this struct with tb_ */ +struct tree_balance { + int tb_mode; + int need_balance_dirty; + struct super_block *tb_sb; + struct reiserfs_transaction_handle *transaction_handle; + struct treepath *tb_path; + struct buffer_head *L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */ + struct buffer_head *R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path */ + struct buffer_head *FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */ + struct buffer_head *FR[MAX_HEIGHT]; /* array of fathers of the right neighbors */ + struct buffer_head *CFL[MAX_HEIGHT]; /* array of common parents of center node and its left neighbor */ + struct buffer_head *CFR[MAX_HEIGHT]; /* array of common parents of center node and its right neighbor */ + + struct buffer_head *FEB[MAX_FEB_SIZE]; /* array of empty buffers. Number of buffers in array equals + cur_blknum. */ + struct buffer_head *used[MAX_FEB_SIZE]; + struct buffer_head *thrown[MAX_FEB_SIZE]; + int lnum[MAX_HEIGHT]; /* array of number of items which must be + shifted to the left in order to balance the + current node; for leaves includes item that + will be partially shifted; for internal + nodes, it is the number of child pointers + rather than items. It includes the new item + being created. The code sometimes subtracts + one to get the number of wholly shifted + items for other purposes. */ + int rnum[MAX_HEIGHT]; /* substitute right for left in comment above */ + int lkey[MAX_HEIGHT]; /* array indexed by height h mapping the key delimiting L[h] and + S[h] to its item number within the node CFL[h] */ + int rkey[MAX_HEIGHT]; /* substitute r for l in comment above */ + int insert_size[MAX_HEIGHT]; /* the number of bytes by we are trying to add or remove from + S[h]. A negative value means removing. */ + int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after + balancing on the level h of the tree. If 0 then S is + being deleted, if 1 then S is remaining and no new nodes + are being created, if 2 or 3 then 1 or 2 new nodes is + being created */ + + /* fields that are used only for balancing leaves of the tree */ + int cur_blknum; /* number of empty blocks having been already allocated */ + int s0num; /* number of items that fall into left most node when S[0] splits */ + int s1num; /* number of items that fall into first new node when S[0] splits */ + int s2num; /* number of items that fall into second new node when S[0] splits */ + int lbytes; /* number of bytes which can flow to the left neighbor from the left */ + /* most liquid item that cannot be shifted from S[0] entirely */ + /* if -1 then nothing will be partially shifted */ + int rbytes; /* number of bytes which will flow to the right neighbor from the right */ + /* most liquid item that cannot be shifted from S[0] entirely */ + /* if -1 then nothing will be partially shifted */ + int s1bytes; /* number of bytes which flow to the first new node when S[0] splits */ + /* note: if S[0] splits into 3 nodes, then items do not need to be cut */ + int s2bytes; + struct buffer_head *buf_to_free[MAX_FREE_BLOCK]; /* buffers which are to be freed after do_balance finishes by unfix_nodes */ + char *vn_buf; /* kmalloced memory. Used to create + virtual node and keep map of + dirtied bitmap blocks */ + int vn_buf_size; /* size of the vn_buf */ + struct virtual_node *tb_vn; /* VN starts after bitmap of bitmap blocks */ + + int fs_gen; /* saved value of `reiserfs_generation' counter + see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */ +#ifdef DISPLACE_NEW_PACKING_LOCALITIES + struct in_core_key key; /* key pointer, to pass to block allocator or + another low-level subsystem */ +#endif +}; + +/* These are modes of balancing */ + +/* When inserting an item. */ +#define M_INSERT 'i' +/* When inserting into (directories only) or appending onto an already + existent item. */ +#define M_PASTE 'p' +/* When deleting an item. */ +#define M_DELETE 'd' +/* When truncating an item or removing an entry from a (directory) item. */ +#define M_CUT 'c' + +/* used when balancing on leaf level skipped (in reiserfsck) */ +#define M_INTERNAL 'n' + +/* When further balancing is not needed, then do_balance does not need + to be called. */ +#define M_SKIP_BALANCING 's' +#define M_CONVERT 'v' + +/* modes of leaf_move_items */ +#define LEAF_FROM_S_TO_L 0 +#define LEAF_FROM_S_TO_R 1 +#define LEAF_FROM_R_TO_L 2 +#define LEAF_FROM_L_TO_R 3 +#define LEAF_FROM_S_TO_SNEW 4 + +#define FIRST_TO_LAST 0 +#define LAST_TO_FIRST 1 + +/* used in do_balance for passing parent of node information that has + been gotten from tb struct */ +struct buffer_info { + struct tree_balance *tb; + struct buffer_head *bi_bh; + struct buffer_head *bi_parent; + int bi_position; +}; + +static inline struct super_block *sb_from_tb(struct tree_balance *tb) +{ + return tb ? tb->tb_sb : NULL; +} + +static inline struct super_block *sb_from_bi(struct buffer_info *bi) +{ + return bi ? sb_from_tb(bi->tb) : NULL; +} + +/* there are 4 types of items: stat data, directory item, indirect, direct. ++-------------------+------------+--------------+------------+ +| | k_offset | k_uniqueness | mergeable? | ++-------------------+------------+--------------+------------+ +| stat data | 0 | 0 | no | ++-------------------+------------+--------------+------------+ +| 1st directory item| DOT_OFFSET |DIRENTRY_UNIQUENESS| no | +| non 1st directory | hash value | | yes | +| item | | | | ++-------------------+------------+--------------+------------+ +| indirect item | offset + 1 |TYPE_INDIRECT | if this is not the first indirect item of the object ++-------------------+------------+--------------+------------+ +| direct item | offset + 1 |TYPE_DIRECT | if not this is not the first direct item of the object ++-------------------+------------+--------------+------------+ +*/ + +struct item_operations { + int (*bytes_number) (struct item_head * ih, int block_size); + void (*decrement_key) (struct cpu_key *); + int (*is_left_mergeable) (struct reiserfs_key * ih, + unsigned long bsize); + void (*print_item) (struct item_head *, char *item); + void (*check_item) (struct item_head *, char *item); + + int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi, + int is_affected, int insert_size); + int (*check_left) (struct virtual_item * vi, int free, + int start_skip, int end_skip); + int (*check_right) (struct virtual_item * vi, int free); + int (*part_size) (struct virtual_item * vi, int from, int to); + int (*unit_num) (struct virtual_item * vi); + void (*print_vi) (struct virtual_item * vi); +}; + +extern struct item_operations *item_ops[TYPE_ANY + 1]; + +#define op_bytes_number(ih,bsize) item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize) +#define op_is_left_mergeable(key,bsize) item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize) +#define op_print_item(ih,item) item_ops[le_ih_k_type (ih)]->print_item (ih, item) +#define op_check_item(ih,item) item_ops[le_ih_k_type (ih)]->check_item (ih, item) +#define op_create_vi(vn,vi,is_affected,insert_size) item_ops[le_ih_k_type ((vi)->vi_ih)]->create_vi (vn,vi,is_affected,insert_size) +#define op_check_left(vi,free,start_skip,end_skip) item_ops[(vi)->vi_index]->check_left (vi, free, start_skip, end_skip) +#define op_check_right(vi,free) item_ops[(vi)->vi_index]->check_right (vi, free) +#define op_part_size(vi,from,to) item_ops[(vi)->vi_index]->part_size (vi, from, to) +#define op_unit_num(vi) item_ops[(vi)->vi_index]->unit_num (vi) +#define op_print_vi(vi) item_ops[(vi)->vi_index]->print_vi (vi) + +#define COMP_SHORT_KEYS comp_short_keys + +/* number of blocks pointed to by the indirect item */ +#define I_UNFM_NUM(ih) (ih_item_len(ih) / UNFM_P_SIZE) + +/* the used space within the unformatted node corresponding to pos within the item pointed to by ih */ +#define I_POS_UNFM_SIZE(ih,pos,size) (((pos) == I_UNFM_NUM(ih) - 1 ) ? (size) - ih_free_space(ih) : (size)) + +/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */ + +/* get the item header */ +#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) ) + +/* get key */ +#define B_N_PDELIM_KEY(bh,item_num) ( (struct reiserfs_key * )((bh)->b_data + BLKH_SIZE) + (item_num) ) + +/* get the key */ +#define B_N_PKEY(bh,item_num) ( &(B_N_PITEM_HEAD(bh,item_num)->ih_key) ) + +/* get item body */ +#define B_N_PITEM(bh,item_num) ( (bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(item_num)))) + +/* get the stat data by the buffer header and the item order */ +#define B_N_STAT_DATA(bh,nr) \ +( (struct stat_data *)((bh)->b_data + ih_location(B_N_PITEM_HEAD((bh),(nr))) ) ) + + /* following defines use reiserfs buffer header and item header */ + +/* get stat-data */ +#define B_I_STAT_DATA(bh, ih) ( (struct stat_data * )((bh)->b_data + ih_location(ih)) ) + +// this is 3976 for size==4096 +#define MAX_DIRECT_ITEM_LEN(size) ((size) - BLKH_SIZE - 2*IH_SIZE - SD_SIZE - UNFM_P_SIZE) + +/* indirect items consist of entries which contain blocknrs, pos + indicates which entry, and B_I_POS_UNFM_POINTER resolves to the + blocknr contained by the entry pos points to */ +#define B_I_POS_UNFM_POINTER(bh,ih,pos) le32_to_cpu(*(((unp_t *)B_I_PITEM(bh,ih)) + (pos))) +#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0) + +struct reiserfs_iget_args { + __u32 objectid; + __u32 dirid; +}; + +/***************************************************************************/ +/* FUNCTION DECLARATIONS */ +/***************************************************************************/ + +#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12) + +#define journal_trans_half(blocksize) \ + ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32)) + +/* journal.c see journal.c for all the comments here */ + +/* first block written in a commit. */ +struct reiserfs_journal_desc { + __le32 j_trans_id; /* id of commit */ + __le32 j_len; /* length of commit. len +1 is the commit block */ + __le32 j_mount_id; /* mount id of this trans */ + __le32 j_realblock[1]; /* real locations for each block */ +}; + +#define get_desc_trans_id(d) le32_to_cpu((d)->j_trans_id) +#define get_desc_trans_len(d) le32_to_cpu((d)->j_len) +#define get_desc_mount_id(d) le32_to_cpu((d)->j_mount_id) + +#define set_desc_trans_id(d,val) do { (d)->j_trans_id = cpu_to_le32 (val); } while (0) +#define set_desc_trans_len(d,val) do { (d)->j_len = cpu_to_le32 (val); } while (0) +#define set_desc_mount_id(d,val) do { (d)->j_mount_id = cpu_to_le32 (val); } while (0) + +/* last block written in a commit */ +struct reiserfs_journal_commit { + __le32 j_trans_id; /* must match j_trans_id from the desc block */ + __le32 j_len; /* ditto */ + __le32 j_realblock[1]; /* real locations for each block */ +}; + +#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id) +#define get_commit_trans_len(c) le32_to_cpu((c)->j_len) +#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id) + +#define set_commit_trans_id(c,val) do { (c)->j_trans_id = cpu_to_le32 (val); } while (0) +#define set_commit_trans_len(c,val) do { (c)->j_len = cpu_to_le32 (val); } while (0) + +/* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the +** last fully flushed transaction. fully flushed means all the log blocks and all the real blocks are on disk, +** and this transaction does not need to be replayed. +*/ +struct reiserfs_journal_header { + __le32 j_last_flush_trans_id; /* id of last fully flushed transaction */ + __le32 j_first_unflushed_offset; /* offset in the log of where to start replay after a crash */ + __le32 j_mount_id; + /* 12 */ struct journal_params jh_journal; +}; + +/* biggest tunable defines are right here */ +#define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */ +#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */ +#define JOURNAL_TRANS_MIN_DEFAULT 256 +#define JOURNAL_MAX_BATCH_DEFAULT 900 /* max blocks to batch into one transaction, don't make this any bigger than 900 */ +#define JOURNAL_MIN_RATIO 2 +#define JOURNAL_MAX_COMMIT_AGE 30 +#define JOURNAL_MAX_TRANS_AGE 30 +#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9) +#define JOURNAL_BLOCKS_PER_OBJECT(sb) (JOURNAL_PER_BALANCE_CNT * 3 + \ + 2 * (REISERFS_QUOTA_INIT_BLOCKS(sb) + \ + REISERFS_QUOTA_TRANS_BLOCKS(sb))) + +#ifdef CONFIG_QUOTA +#define REISERFS_QUOTA_OPTS ((1 << REISERFS_USRQUOTA) | (1 << REISERFS_GRPQUOTA)) +/* We need to update data and inode (atime) */ +#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? 2 : 0) +/* 1 balancing, 1 bitmap, 1 data per write + stat data update */ +#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \ +(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0) +/* same as with INIT */ +#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & REISERFS_QUOTA_OPTS ? \ +(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0) +#else +#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0 +#define REISERFS_QUOTA_INIT_BLOCKS(s) 0 +#define REISERFS_QUOTA_DEL_BLOCKS(s) 0 +#endif + +/* both of these can be as low as 1, or as high as you want. The min is the +** number of 4k bitmap nodes preallocated on mount. New nodes are allocated +** as needed, and released when transactions are committed. On release, if +** the current number of nodes is > max, the node is freed, otherwise, +** it is put on a free list for faster use later. +*/ +#define REISERFS_MIN_BITMAP_NODES 10 +#define REISERFS_MAX_BITMAP_NODES 100 + +#define JBH_HASH_SHIFT 13 /* these are based on journal hash size of 8192 */ +#define JBH_HASH_MASK 8191 + +#define _jhashfn(sb,block) \ + (((unsigned long)sb>>L1_CACHE_SHIFT) ^ \ + (((block)<<(JBH_HASH_SHIFT - 6)) ^ ((block) >> 13) ^ ((block) << (JBH_HASH_SHIFT - 12)))) +#define journal_hash(t,sb,block) ((t)[_jhashfn((sb),(block)) & JBH_HASH_MASK]) + +// We need these to make journal.c code more readable +#define journal_find_get_block(s, block) __find_get_block(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) +#define journal_getblk(s, block) __getblk(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) +#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize) + +enum reiserfs_bh_state_bits { + BH_JDirty = BH_PrivateStart, /* buffer is in current transaction */ + BH_JDirty_wait, + BH_JNew, /* disk block was taken off free list before + * being in a finished transaction, or + * written to disk. Can be reused immed. */ + BH_JPrepared, + BH_JRestore_dirty, + BH_JTest, // debugging only will go away +}; + +BUFFER_FNS(JDirty, journaled); +TAS_BUFFER_FNS(JDirty, journaled); +BUFFER_FNS(JDirty_wait, journal_dirty); +TAS_BUFFER_FNS(JDirty_wait, journal_dirty); +BUFFER_FNS(JNew, journal_new); +TAS_BUFFER_FNS(JNew, journal_new); +BUFFER_FNS(JPrepared, journal_prepared); +TAS_BUFFER_FNS(JPrepared, journal_prepared); +BUFFER_FNS(JRestore_dirty, journal_restore_dirty); +TAS_BUFFER_FNS(JRestore_dirty, journal_restore_dirty); +BUFFER_FNS(JTest, journal_test); +TAS_BUFFER_FNS(JTest, journal_test); + +/* +** transaction handle which is passed around for all journal calls +*/ +struct reiserfs_transaction_handle { + struct super_block *t_super; /* super for this FS when journal_begin was + called. saves calls to reiserfs_get_super + also used by nested transactions to make + sure they are nesting on the right FS + _must_ be first in the handle + */ + int t_refcount; + int t_blocks_logged; /* number of blocks this writer has logged */ + int t_blocks_allocated; /* number of blocks this writer allocated */ + unsigned int t_trans_id; /* sanity check, equals the current trans id */ + void *t_handle_save; /* save existing current->journal_info */ + unsigned displace_new_blocks:1; /* if new block allocation occurres, that block + should be displaced from others */ + struct list_head t_list; +}; + +/* used to keep track of ordered and tail writes, attached to the buffer + * head through b_journal_head. + */ +struct reiserfs_jh { + struct reiserfs_journal_list *jl; + struct buffer_head *bh; + struct list_head list; +}; + +void reiserfs_free_jh(struct buffer_head *bh); +int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh); +int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh); +int journal_mark_dirty(struct reiserfs_transaction_handle *, + struct super_block *, struct buffer_head *bh); + +static inline int reiserfs_file_data_log(struct inode *inode) +{ + if (reiserfs_data_log(inode->i_sb) || + (REISERFS_I(inode)->i_flags & i_data_log)) + return 1; + return 0; +} + +static inline int reiserfs_transaction_running(struct super_block *s) +{ + struct reiserfs_transaction_handle *th = current->journal_info; + if (th && th->t_super == s) + return 1; + if (th && th->t_super == NULL) + BUG(); + return 0; +} + +static inline int reiserfs_transaction_free_space(struct reiserfs_transaction_handle *th) +{ + return th->t_blocks_allocated - th->t_blocks_logged; +} + +struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct + super_block + *, + int count); +int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *); +int reiserfs_commit_page(struct inode *inode, struct page *page, + unsigned from, unsigned to); +int reiserfs_flush_old_commits(struct super_block *); +int reiserfs_commit_for_inode(struct inode *); +int reiserfs_inode_needs_commit(struct inode *); +void reiserfs_update_inode_transaction(struct inode *); +void reiserfs_wait_on_write_block(struct super_block *s); +void reiserfs_block_writes(struct reiserfs_transaction_handle *th); +void reiserfs_allow_writes(struct super_block *s); +void reiserfs_check_lock_depth(struct super_block *s, char *caller); +int reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh, + int wait); +void reiserfs_restore_prepared_buffer(struct super_block *, + struct buffer_head *bh); +int journal_init(struct super_block *, const char *j_dev_name, int old_format, + unsigned int); +int journal_release(struct reiserfs_transaction_handle *, struct super_block *); +int journal_release_error(struct reiserfs_transaction_handle *, + struct super_block *); +int journal_end(struct reiserfs_transaction_handle *, struct super_block *, + unsigned long); +int journal_end_sync(struct reiserfs_transaction_handle *, struct super_block *, + unsigned long); +int journal_mark_freed(struct reiserfs_transaction_handle *, + struct super_block *, b_blocknr_t blocknr); +int journal_transaction_should_end(struct reiserfs_transaction_handle *, int); +int reiserfs_in_journal(struct super_block *sb, unsigned int bmap_nr, + int bit_nr, int searchall, b_blocknr_t *next); +int journal_begin(struct reiserfs_transaction_handle *, + struct super_block *sb, unsigned long); +int journal_join_abort(struct reiserfs_transaction_handle *, + struct super_block *sb, unsigned long); +void reiserfs_abort_journal(struct super_block *sb, int errno); +void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...); +int reiserfs_allocate_list_bitmaps(struct super_block *s, + struct reiserfs_list_bitmap *, unsigned int); + +void add_save_link(struct reiserfs_transaction_handle *th, + struct inode *inode, int truncate); +int remove_save_link(struct inode *inode, int truncate); + +/* objectid.c */ +__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th); +void reiserfs_release_objectid(struct reiserfs_transaction_handle *th, + __u32 objectid_to_release); +int reiserfs_convert_objectid_map_v1(struct super_block *); + +/* stree.c */ +int B_IS_IN_TREE(const struct buffer_head *); +extern void copy_item_head(struct item_head *to, + const struct item_head *from); + +// first key is in cpu form, second - le +extern int comp_short_keys(const struct reiserfs_key *le_key, + const struct cpu_key *cpu_key); +extern void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from); + +// both are in le form +extern int comp_le_keys(const struct reiserfs_key *, + const struct reiserfs_key *); +extern int comp_short_le_keys(const struct reiserfs_key *, + const struct reiserfs_key *); + +// +// get key version from on disk key - kludge +// +static inline int le_key_version(const struct reiserfs_key *key) +{ + int type; + + type = offset_v2_k_type(&(key->u.k_offset_v2)); + if (type != TYPE_DIRECT && type != TYPE_INDIRECT + && type != TYPE_DIRENTRY) + return KEY_FORMAT_3_5; + + return KEY_FORMAT_3_6; + +} + +static inline void copy_key(struct reiserfs_key *to, + const struct reiserfs_key *from) +{ + memcpy(to, from, KEY_SIZE); +} + +int comp_items(const struct item_head *stored_ih, const struct treepath *path); +const struct reiserfs_key *get_rkey(const struct treepath *chk_path, + const struct super_block *sb); +int search_by_key(struct super_block *, const struct cpu_key *, + struct treepath *, int); +#define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL) +int search_for_position_by_key(struct super_block *sb, + const struct cpu_key *cpu_key, + struct treepath *search_path); +extern void decrement_bcount(struct buffer_head *bh); +void decrement_counters_in_path(struct treepath *search_path); +void pathrelse(struct treepath *search_path); +int reiserfs_check_path(struct treepath *p); +void pathrelse_and_restore(struct super_block *s, struct treepath *search_path); + +int reiserfs_insert_item(struct reiserfs_transaction_handle *th, + struct treepath *path, + const struct cpu_key *key, + struct item_head *ih, + struct inode *inode, const char *body); + +int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, + struct treepath *path, + const struct cpu_key *key, + struct inode *inode, + const char *body, int paste_size); + +int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th, + struct treepath *path, + struct cpu_key *key, + struct inode *inode, + struct page *page, loff_t new_file_size); + +int reiserfs_delete_item(struct reiserfs_transaction_handle *th, + struct treepath *path, + const struct cpu_key *key, + struct inode *inode, struct buffer_head *un_bh); + +void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th, + struct inode *inode, struct reiserfs_key *key); +int reiserfs_delete_object(struct reiserfs_transaction_handle *th, + struct inode *inode); +int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, + struct inode *inode, struct page *, + int update_timestamps); + +#define i_block_size(inode) ((inode)->i_sb->s_blocksize) +#define file_size(inode) ((inode)->i_size) +#define tail_size(inode) (file_size (inode) & (i_block_size (inode) - 1)) + +#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\ +!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 ) + +void padd_item(char *item, int total_length, int length); + +/* inode.c */ +/* args for the create parameter of reiserfs_get_block */ +#define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */ +#define GET_BLOCK_CREATE 1 /* add anything you need to find block */ +#define GET_BLOCK_NO_HOLE 2 /* return -ENOENT for file holes */ +#define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */ +#define GET_BLOCK_NO_IMUX 8 /* i_mutex is not held, don't preallocate */ +#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */ + +void reiserfs_read_locked_inode(struct inode *inode, + struct reiserfs_iget_args *args); +int reiserfs_find_actor(struct inode *inode, void *p); +int reiserfs_init_locked_inode(struct inode *inode, void *p); +void reiserfs_evict_inode(struct inode *inode); +int reiserfs_write_inode(struct inode *inode, struct writeback_control *wbc); +int reiserfs_get_block(struct inode *inode, sector_t block, + struct buffer_head *bh_result, int create); +struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type); +struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid, + int fh_len, int fh_type); +int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp, + int connectable); + +int reiserfs_truncate_file(struct inode *, int update_timestamps); +void make_cpu_key(struct cpu_key *cpu_key, struct inode *inode, loff_t offset, + int type, int key_length); +void make_le_item_head(struct item_head *ih, const struct cpu_key *key, + int version, + loff_t offset, int type, int length, int entry_count); +struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key); + +struct reiserfs_security_handle; +int reiserfs_new_inode(struct reiserfs_transaction_handle *th, + struct inode *dir, umode_t mode, + const char *symname, loff_t i_size, + struct dentry *dentry, struct inode *inode, + struct reiserfs_security_handle *security); + +void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th, + struct inode *inode, loff_t size); + +static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th, + struct inode *inode) +{ + reiserfs_update_sd_size(th, inode, inode->i_size); +} + +void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode); +void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs); +int reiserfs_setattr(struct dentry *dentry, struct iattr *attr); + +int __reiserfs_write_begin(struct page *page, unsigned from, unsigned len); + +/* namei.c */ +void set_de_name_and_namelen(struct reiserfs_dir_entry *de); +int search_by_entry_key(struct super_block *sb, const struct cpu_key *key, + struct treepath *path, struct reiserfs_dir_entry *de); +struct dentry *reiserfs_get_parent(struct dentry *); + +#ifdef CONFIG_REISERFS_PROC_INFO +int reiserfs_proc_info_init(struct super_block *sb); +int reiserfs_proc_info_done(struct super_block *sb); +int reiserfs_proc_info_global_init(void); +int reiserfs_proc_info_global_done(void); + +#define PROC_EXP( e ) e + +#define __PINFO( sb ) REISERFS_SB(sb) -> s_proc_info_data +#define PROC_INFO_MAX( sb, field, value ) \ + __PINFO( sb ).field = \ + max( REISERFS_SB( sb ) -> s_proc_info_data.field, value ) +#define PROC_INFO_INC( sb, field ) ( ++ ( __PINFO( sb ).field ) ) +#define PROC_INFO_ADD( sb, field, val ) ( __PINFO( sb ).field += ( val ) ) +#define PROC_INFO_BH_STAT( sb, bh, level ) \ + PROC_INFO_INC( sb, sbk_read_at[ ( level ) ] ); \ + PROC_INFO_ADD( sb, free_at[ ( level ) ], B_FREE_SPACE( bh ) ); \ + PROC_INFO_ADD( sb, items_at[ ( level ) ], B_NR_ITEMS( bh ) ) +#else +static inline int reiserfs_proc_info_init(struct super_block *sb) +{ + return 0; +} + +static inline int reiserfs_proc_info_done(struct super_block *sb) +{ + return 0; +} + +static inline int reiserfs_proc_info_global_init(void) +{ + return 0; +} + +static inline int reiserfs_proc_info_global_done(void) +{ + return 0; +} + +#define PROC_EXP( e ) +#define VOID_V ( ( void ) 0 ) +#define PROC_INFO_MAX( sb, field, value ) VOID_V +#define PROC_INFO_INC( sb, field ) VOID_V +#define PROC_INFO_ADD( sb, field, val ) VOID_V +#define PROC_INFO_BH_STAT(sb, bh, n_node_level) VOID_V +#endif + +/* dir.c */ +extern const struct inode_operations reiserfs_dir_inode_operations; +extern const struct inode_operations reiserfs_symlink_inode_operations; +extern const struct inode_operations reiserfs_special_inode_operations; +extern const struct file_operations reiserfs_dir_operations; +int reiserfs_readdir_dentry(struct dentry *, void *, filldir_t, loff_t *); + +/* tail_conversion.c */ +int direct2indirect(struct reiserfs_transaction_handle *, struct inode *, + struct treepath *, struct buffer_head *, loff_t); +int indirect2direct(struct reiserfs_transaction_handle *, struct inode *, + struct page *, struct treepath *, const struct cpu_key *, + loff_t, char *); +void reiserfs_unmap_buffer(struct buffer_head *); + +/* file.c */ +extern const struct inode_operations reiserfs_file_inode_operations; +extern const struct file_operations reiserfs_file_operations; +extern const struct address_space_operations reiserfs_address_space_operations; + +/* fix_nodes.c */ + +int fix_nodes(int n_op_mode, struct tree_balance *tb, + struct item_head *ins_ih, const void *); +void unfix_nodes(struct tree_balance *); + +/* prints.c */ +void __reiserfs_panic(struct super_block *s, const char *id, + const char *function, const char *fmt, ...) + __attribute__ ((noreturn)); +#define reiserfs_panic(s, id, fmt, args...) \ + __reiserfs_panic(s, id, __func__, fmt, ##args) +void __reiserfs_error(struct super_block *s, const char *id, + const char *function, const char *fmt, ...); +#define reiserfs_error(s, id, fmt, args...) \ + __reiserfs_error(s, id, __func__, fmt, ##args) +void reiserfs_info(struct super_block *s, const char *fmt, ...); +void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...); +void print_indirect_item(struct buffer_head *bh, int item_num); +void store_print_tb(struct tree_balance *tb); +void print_cur_tb(char *mes); +void print_de(struct reiserfs_dir_entry *de); +void print_bi(struct buffer_info *bi, char *mes); +#define PRINT_LEAF_ITEMS 1 /* print all items */ +#define PRINT_DIRECTORY_ITEMS 2 /* print directory items */ +#define PRINT_DIRECT_ITEMS 4 /* print contents of direct items */ +void print_block(struct buffer_head *bh, ...); +void print_bmap(struct super_block *s, int silent); +void print_bmap_block(int i, char *data, int size, int silent); +/*void print_super_block (struct super_block * s, char * mes);*/ +void print_objectid_map(struct super_block *s); +void print_block_head(struct buffer_head *bh, char *mes); +void check_leaf(struct buffer_head *bh); +void check_internal(struct buffer_head *bh); +void print_statistics(struct super_block *s); +char *reiserfs_hashname(int code); + +/* lbalance.c */ +int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num, + int mov_bytes, struct buffer_head *Snew); +int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes); +int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes); +void leaf_delete_items(struct buffer_info *cur_bi, int last_first, int first, + int del_num, int del_bytes); +void leaf_insert_into_buf(struct buffer_info *bi, int before, + struct item_head *inserted_item_ih, + const char *inserted_item_body, int zeros_number); +void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num, + int pos_in_item, int paste_size, const char *body, + int zeros_number); +void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num, + int pos_in_item, int cut_size); +void leaf_paste_entries(struct buffer_info *bi, int item_num, int before, + int new_entry_count, struct reiserfs_de_head *new_dehs, + const char *records, int paste_size); +/* ibalance.c */ +int balance_internal(struct tree_balance *, int, int, struct item_head *, + struct buffer_head **); + +/* do_balance.c */ +void do_balance_mark_leaf_dirty(struct tree_balance *tb, + struct buffer_head *bh, int flag); +#define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty +#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty + +void do_balance(struct tree_balance *tb, struct item_head *ih, + const char *body, int flag); +void reiserfs_invalidate_buffer(struct tree_balance *tb, + struct buffer_head *bh); + +int get_left_neighbor_position(struct tree_balance *tb, int h); +int get_right_neighbor_position(struct tree_balance *tb, int h); +void replace_key(struct tree_balance *tb, struct buffer_head *, int, + struct buffer_head *, int); +void make_empty_node(struct buffer_info *); +struct buffer_head *get_FEB(struct tree_balance *); + +/* bitmap.c */ + +/* structure contains hints for block allocator, and it is a container for + * arguments, such as node, search path, transaction_handle, etc. */ +struct __reiserfs_blocknr_hint { + struct inode *inode; /* inode passed to allocator, if we allocate unf. nodes */ + sector_t block; /* file offset, in blocks */ + struct in_core_key key; + struct treepath *path; /* search path, used by allocator to deternine search_start by + * various ways */ + struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and + * bitmap blocks changes */ + b_blocknr_t beg, end; + b_blocknr_t search_start; /* a field used to transfer search start value (block number) + * between different block allocator procedures + * (determine_search_start() and others) */ + int prealloc_size; /* is set in determine_prealloc_size() function, used by underlayed + * function that do actual allocation */ + + unsigned formatted_node:1; /* the allocator uses different polices for getting disk space for + * formatted/unformatted blocks with/without preallocation */ + unsigned preallocate:1; +}; + +typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t; + +int reiserfs_parse_alloc_options(struct super_block *, char *); +void reiserfs_init_alloc_options(struct super_block *s); + +/* + * given a directory, this will tell you what packing locality + * to use for a new object underneat it. The locality is returned + * in disk byte order (le). + */ +__le32 reiserfs_choose_packing(struct inode *dir); + +int reiserfs_init_bitmap_cache(struct super_block *sb); +void reiserfs_free_bitmap_cache(struct super_block *sb); +void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info); +struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap); +int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value); +void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *, + b_blocknr_t, int for_unformatted); +int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t *, int, + int); +static inline int reiserfs_new_form_blocknrs(struct tree_balance *tb, + b_blocknr_t * new_blocknrs, + int amount_needed) +{ + reiserfs_blocknr_hint_t hint = { + .th = tb->transaction_handle, + .path = tb->tb_path, + .inode = NULL, + .key = tb->key, + .block = 0, + .formatted_node = 1 + }; + return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed, + 0); +} + +static inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle + *th, struct inode *inode, + b_blocknr_t * new_blocknrs, + struct treepath *path, + sector_t block) +{ + reiserfs_blocknr_hint_t hint = { + .th = th, + .path = path, + .inode = inode, + .block = block, + .formatted_node = 0, + .preallocate = 0 + }; + return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0); +} + +#ifdef REISERFS_PREALLOCATE +static inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle + *th, struct inode *inode, + b_blocknr_t * new_blocknrs, + struct treepath *path, + sector_t block) +{ + reiserfs_blocknr_hint_t hint = { + .th = th, + .path = path, + .inode = inode, + .block = block, + .formatted_node = 0, + .preallocate = 1 + }; + return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0); +} + +void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th, + struct inode *inode); +void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th); +#endif + +/* hashes.c */ +__u32 keyed_hash(const signed char *msg, int len); +__u32 yura_hash(const signed char *msg, int len); +__u32 r5_hash(const signed char *msg, int len); + +#define reiserfs_set_le_bit __set_bit_le +#define reiserfs_test_and_set_le_bit __test_and_set_bit_le +#define reiserfs_clear_le_bit __clear_bit_le +#define reiserfs_test_and_clear_le_bit __test_and_clear_bit_le +#define reiserfs_test_le_bit test_bit_le +#define reiserfs_find_next_zero_le_bit find_next_zero_bit_le + +/* sometimes reiserfs_truncate may require to allocate few new blocks + to perform indirect2direct conversion. People probably used to + think, that truncate should work without problems on a filesystem + without free disk space. They may complain that they can not + truncate due to lack of free disk space. This spare space allows us + to not worry about it. 500 is probably too much, but it should be + absolutely safe */ +#define SPARE_SPACE 500 + +/* prototypes from ioctl.c */ +long reiserfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); +long reiserfs_compat_ioctl(struct file *filp, + unsigned int cmd, unsigned long arg); +int reiserfs_unpack(struct inode *inode, struct file *filp); + +#endif /* __KERNEL__ */ + #endif /* _LINUX_REISER_FS_H */ diff --git a/trunk/include/linux/reiserfs_fs_i.h b/trunk/include/linux/reiserfs_fs_i.h new file mode 100644 index 000000000000..97959bdfe214 --- /dev/null +++ b/trunk/include/linux/reiserfs_fs_i.h @@ -0,0 +1,63 @@ +#ifndef _REISER_FS_I +#define _REISER_FS_I + +#include + +struct reiserfs_journal_list; + +/** bitmasks for i_flags field in reiserfs-specific part of inode */ +typedef enum { + /** this says what format of key do all items (but stat data) of + an object have. If this is set, that format is 3.6 otherwise + - 3.5 */ + i_item_key_version_mask = 0x0001, + /** If this is unset, object has 3.5 stat data, otherwise, it has + 3.6 stat data with 64bit size, 32bit nlink etc. */ + i_stat_data_version_mask = 0x0002, + /** file might need tail packing on close */ + i_pack_on_close_mask = 0x0004, + /** don't pack tail of file */ + i_nopack_mask = 0x0008, + /** If those is set, "safe link" was created for this file during + truncate or unlink. Safe link is used to avoid leakage of disk + space on crash with some files open, but unlinked. */ + i_link_saved_unlink_mask = 0x0010, + i_link_saved_truncate_mask = 0x0020, + i_has_xattr_dir = 0x0040, + i_data_log = 0x0080, +} reiserfs_inode_flags; + +struct reiserfs_inode_info { + __u32 i_key[4]; /* key is still 4 32 bit integers */ + /** transient inode flags that are never stored on disk. Bitmasks + for this field are defined above. */ + __u32 i_flags; + + __u32 i_first_direct_byte; // offset of first byte stored in direct item. + + /* copy of persistent inode flags read from sd_attrs. */ + __u32 i_attrs; + + int i_prealloc_block; /* first unused block of a sequence of unused blocks */ + int i_prealloc_count; /* length of that sequence */ + struct list_head i_prealloc_list; /* per-transaction list of inodes which + * have preallocated blocks */ + + unsigned new_packing_locality:1; /* new_packig_locality is created; new blocks + * for the contents of this directory should be + * displaced */ + + /* we use these for fsync or O_SYNC to decide which transaction + ** needs to be committed in order for this inode to be properly + ** flushed */ + unsigned int i_trans_id; + struct reiserfs_journal_list *i_jl; + atomic_t openers; + struct mutex tailpack; +#ifdef CONFIG_REISERFS_FS_XATTR + struct rw_semaphore i_xattr_sem; +#endif + struct inode vfs_inode; +}; + +#endif diff --git a/trunk/include/linux/reiserfs_fs_sb.h b/trunk/include/linux/reiserfs_fs_sb.h new file mode 100644 index 000000000000..8c9e85c64b46 --- /dev/null +++ b/trunk/include/linux/reiserfs_fs_sb.h @@ -0,0 +1,554 @@ +/* Copyright 1996-2000 Hans Reiser, see reiserfs/README for licensing + * and copyright details */ + +#ifndef _LINUX_REISER_FS_SB +#define _LINUX_REISER_FS_SB + +#ifdef __KERNEL__ +#include +#include +#include +#include +#endif + +typedef enum { + reiserfs_attrs_cleared = 0x00000001, +} reiserfs_super_block_flags; + +/* struct reiserfs_super_block accessors/mutators + * since this is a disk structure, it will always be in + * little endian format. */ +#define sb_block_count(sbp) (le32_to_cpu((sbp)->s_v1.s_block_count)) +#define set_sb_block_count(sbp,v) ((sbp)->s_v1.s_block_count = cpu_to_le32(v)) +#define sb_free_blocks(sbp) (le32_to_cpu((sbp)->s_v1.s_free_blocks)) +#define set_sb_free_blocks(sbp,v) ((sbp)->s_v1.s_free_blocks = cpu_to_le32(v)) +#define sb_root_block(sbp) (le32_to_cpu((sbp)->s_v1.s_root_block)) +#define set_sb_root_block(sbp,v) ((sbp)->s_v1.s_root_block = cpu_to_le32(v)) + +#define sb_jp_journal_1st_block(sbp) \ + (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_1st_block)) +#define set_sb_jp_journal_1st_block(sbp,v) \ + ((sbp)->s_v1.s_journal.jp_journal_1st_block = cpu_to_le32(v)) +#define sb_jp_journal_dev(sbp) \ + (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_dev)) +#define set_sb_jp_journal_dev(sbp,v) \ + ((sbp)->s_v1.s_journal.jp_journal_dev = cpu_to_le32(v)) +#define sb_jp_journal_size(sbp) \ + (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_size)) +#define set_sb_jp_journal_size(sbp,v) \ + ((sbp)->s_v1.s_journal.jp_journal_size = cpu_to_le32(v)) +#define sb_jp_journal_trans_max(sbp) \ + (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_trans_max)) +#define set_sb_jp_journal_trans_max(sbp,v) \ + ((sbp)->s_v1.s_journal.jp_journal_trans_max = cpu_to_le32(v)) +#define sb_jp_journal_magic(sbp) \ + (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_magic)) +#define set_sb_jp_journal_magic(sbp,v) \ + ((sbp)->s_v1.s_journal.jp_journal_magic = cpu_to_le32(v)) +#define sb_jp_journal_max_batch(sbp) \ + (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_batch)) +#define set_sb_jp_journal_max_batch(sbp,v) \ + ((sbp)->s_v1.s_journal.jp_journal_max_batch = cpu_to_le32(v)) +#define sb_jp_jourmal_max_commit_age(sbp) \ + (le32_to_cpu((sbp)->s_v1.s_journal.jp_journal_max_commit_age)) +#define set_sb_jp_journal_max_commit_age(sbp,v) \ + ((sbp)->s_v1.s_journal.jp_journal_max_commit_age = cpu_to_le32(v)) + +#define sb_blocksize(sbp) (le16_to_cpu((sbp)->s_v1.s_blocksize)) +#define set_sb_blocksize(sbp,v) ((sbp)->s_v1.s_blocksize = cpu_to_le16(v)) +#define sb_oid_maxsize(sbp) (le16_to_cpu((sbp)->s_v1.s_oid_maxsize)) +#define set_sb_oid_maxsize(sbp,v) ((sbp)->s_v1.s_oid_maxsize = cpu_to_le16(v)) +#define sb_oid_cursize(sbp) (le16_to_cpu((sbp)->s_v1.s_oid_cursize)) +#define set_sb_oid_cursize(sbp,v) ((sbp)->s_v1.s_oid_cursize = cpu_to_le16(v)) +#define sb_umount_state(sbp) (le16_to_cpu((sbp)->s_v1.s_umount_state)) +#define set_sb_umount_state(sbp,v) ((sbp)->s_v1.s_umount_state = cpu_to_le16(v)) +#define sb_fs_state(sbp) (le16_to_cpu((sbp)->s_v1.s_fs_state)) +#define set_sb_fs_state(sbp,v) ((sbp)->s_v1.s_fs_state = cpu_to_le16(v)) +#define sb_hash_function_code(sbp) \ + (le32_to_cpu((sbp)->s_v1.s_hash_function_code)) +#define set_sb_hash_function_code(sbp,v) \ + ((sbp)->s_v1.s_hash_function_code = cpu_to_le32(v)) +#define sb_tree_height(sbp) (le16_to_cpu((sbp)->s_v1.s_tree_height)) +#define set_sb_tree_height(sbp,v) ((sbp)->s_v1.s_tree_height = cpu_to_le16(v)) +#define sb_bmap_nr(sbp) (le16_to_cpu((sbp)->s_v1.s_bmap_nr)) +#define set_sb_bmap_nr(sbp,v) ((sbp)->s_v1.s_bmap_nr = cpu_to_le16(v)) +#define sb_version(sbp) (le16_to_cpu((sbp)->s_v1.s_version)) +#define set_sb_version(sbp,v) ((sbp)->s_v1.s_version = cpu_to_le16(v)) + +#define sb_mnt_count(sbp) (le16_to_cpu((sbp)->s_mnt_count)) +#define set_sb_mnt_count(sbp, v) ((sbp)->s_mnt_count = cpu_to_le16(v)) + +#define sb_reserved_for_journal(sbp) \ + (le16_to_cpu((sbp)->s_v1.s_reserved_for_journal)) +#define set_sb_reserved_for_journal(sbp,v) \ + ((sbp)->s_v1.s_reserved_for_journal = cpu_to_le16(v)) + +/* LOGGING -- */ + +/* These all interelate for performance. +** +** If the journal block count is smaller than n transactions, you lose speed. +** I don't know what n is yet, I'm guessing 8-16. +** +** typical transaction size depends on the application, how often fsync is +** called, and how many metadata blocks you dirty in a 30 second period. +** The more small files (<16k) you use, the larger your transactions will +** be. +** +** If your journal fills faster than dirty buffers get flushed to disk, it must flush them before allowing the journal +** to wrap, which slows things down. If you need high speed meta data updates, the journal should be big enough +** to prevent wrapping before dirty meta blocks get to disk. +** +** If the batch max is smaller than the transaction max, you'll waste space at the end of the journal +** because journal_end sets the next transaction to start at 0 if the next transaction has any chance of wrapping. +** +** The large the batch max age, the better the speed, and the more meta data changes you'll lose after a crash. +** +*/ + +/* don't mess with these for a while */ + /* we have a node size define somewhere in reiserfs_fs.h. -Hans */ +#define JOURNAL_BLOCK_SIZE 4096 /* BUG gotta get rid of this */ +#define JOURNAL_MAX_CNODE 1500 /* max cnodes to allocate. */ +#define JOURNAL_HASH_SIZE 8192 +#define JOURNAL_NUM_BITMAPS 5 /* number of copies of the bitmaps to have floating. Must be >= 2 */ + +/* One of these for every block in every transaction +** Each one is in two hash tables. First, a hash of the current transaction, and after journal_end, a +** hash of all the in memory transactions. +** next and prev are used by the current transaction (journal_hash). +** hnext and hprev are used by journal_list_hash. If a block is in more than one transaction, the journal_list_hash +** links it in multiple times. This allows flush_journal_list to remove just the cnode belonging +** to a given transaction. +*/ +struct reiserfs_journal_cnode { + struct buffer_head *bh; /* real buffer head */ + struct super_block *sb; /* dev of real buffer head */ + __u32 blocknr; /* block number of real buffer head, == 0 when buffer on disk */ + unsigned long state; + struct reiserfs_journal_list *jlist; /* journal list this cnode lives in */ + struct reiserfs_journal_cnode *next; /* next in transaction list */ + struct reiserfs_journal_cnode *prev; /* prev in transaction list */ + struct reiserfs_journal_cnode *hprev; /* prev in hash list */ + struct reiserfs_journal_cnode *hnext; /* next in hash list */ +}; + +struct reiserfs_bitmap_node { + int id; + char *data; + struct list_head list; +}; + +struct reiserfs_list_bitmap { + struct reiserfs_journal_list *journal_list; + struct reiserfs_bitmap_node **bitmaps; +}; + +/* +** one of these for each transaction. The most important part here is the j_realblock. +** this list of cnodes is used to hash all the blocks in all the commits, to mark all the +** real buffer heads dirty once all the commits hit the disk, +** and to make sure every real block in a transaction is on disk before allowing the log area +** to be overwritten */ +struct reiserfs_journal_list { + unsigned long j_start; + unsigned long j_state; + unsigned long j_len; + atomic_t j_nonzerolen; + atomic_t j_commit_left; + atomic_t j_older_commits_done; /* all commits older than this on disk */ + struct mutex j_commit_mutex; + unsigned int j_trans_id; + time_t j_timestamp; + struct reiserfs_list_bitmap *j_list_bitmap; + struct buffer_head *j_commit_bh; /* commit buffer head */ + struct reiserfs_journal_cnode *j_realblock; + struct reiserfs_journal_cnode *j_freedlist; /* list of buffers that were freed during this trans. free each of these on flush */ + /* time ordered list of all active transactions */ + struct list_head j_list; + + /* time ordered list of all transactions we haven't tried to flush yet */ + struct list_head j_working_list; + + /* list of tail conversion targets in need of flush before commit */ + struct list_head j_tail_bh_list; + /* list of data=ordered buffers in need of flush before commit */ + struct list_head j_bh_list; + int j_refcount; +}; + +struct reiserfs_journal { + struct buffer_head **j_ap_blocks; /* journal blocks on disk */ + struct reiserfs_journal_cnode *j_last; /* newest journal block */ + struct reiserfs_journal_cnode *j_first; /* oldest journal block. start here for traverse */ + + struct block_device *j_dev_bd; + fmode_t j_dev_mode; + int j_1st_reserved_block; /* first block on s_dev of reserved area journal */ + + unsigned long j_state; + unsigned int j_trans_id; + unsigned long j_mount_id; + unsigned long j_start; /* start of current waiting commit (index into j_ap_blocks) */ + unsigned long j_len; /* length of current waiting commit */ + unsigned long j_len_alloc; /* number of buffers requested by journal_begin() */ + atomic_t j_wcount; /* count of writers for current commit */ + unsigned long j_bcount; /* batch count. allows turning X transactions into 1 */ + unsigned long j_first_unflushed_offset; /* first unflushed transactions offset */ + unsigned j_last_flush_trans_id; /* last fully flushed journal timestamp */ + struct buffer_head *j_header_bh; + + time_t j_trans_start_time; /* time this transaction started */ + struct mutex j_mutex; + struct mutex j_flush_mutex; + wait_queue_head_t j_join_wait; /* wait for current transaction to finish before starting new one */ + atomic_t j_jlock; /* lock for j_join_wait */ + int j_list_bitmap_index; /* number of next list bitmap to use */ + int j_must_wait; /* no more journal begins allowed. MUST sleep on j_join_wait */ + int j_next_full_flush; /* next journal_end will flush all journal list */ + int j_next_async_flush; /* next journal_end will flush all async commits */ + + int j_cnode_used; /* number of cnodes on the used list */ + int j_cnode_free; /* number of cnodes on the free list */ + + unsigned int j_trans_max; /* max number of blocks in a transaction. */ + unsigned int j_max_batch; /* max number of blocks to batch into a trans */ + unsigned int j_max_commit_age; /* in seconds, how old can an async commit be */ + unsigned int j_max_trans_age; /* in seconds, how old can a transaction be */ + unsigned int j_default_max_commit_age; /* the default for the max commit age */ + + struct reiserfs_journal_cnode *j_cnode_free_list; + struct reiserfs_journal_cnode *j_cnode_free_orig; /* orig pointer returned from vmalloc */ + + struct reiserfs_journal_list *j_current_jl; + int j_free_bitmap_nodes; + int j_used_bitmap_nodes; + + int j_num_lists; /* total number of active transactions */ + int j_num_work_lists; /* number that need attention from kreiserfsd */ + + /* debugging to make sure things are flushed in order */ + unsigned int j_last_flush_id; + + /* debugging to make sure things are committed in order */ + unsigned int j_last_commit_id; + + struct list_head j_bitmap_nodes; + struct list_head j_dirty_buffers; + spinlock_t j_dirty_buffers_lock; /* protects j_dirty_buffers */ + + /* list of all active transactions */ + struct list_head j_journal_list; + /* lists that haven't been touched by writeback attempts */ + struct list_head j_working_list; + + struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS]; /* array of bitmaps to record the deleted blocks */ + struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE]; /* hash table for real buffer heads in current trans */ + struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE]; /* hash table for all the real buffer heads in all + the transactions */ + struct list_head j_prealloc_list; /* list of inodes which have preallocated blocks */ + int j_persistent_trans; + unsigned long j_max_trans_size; + unsigned long j_max_batch_size; + + int j_errno; + + /* when flushing ordered buffers, throttle new ordered writers */ + struct delayed_work j_work; + struct super_block *j_work_sb; + atomic_t j_async_throttle; +}; + +enum journal_state_bits { + J_WRITERS_BLOCKED = 1, /* set when new writers not allowed */ + J_WRITERS_QUEUED, /* set when log is full due to too many writers */ + J_ABORTED, /* set when log is aborted */ +}; + +#define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */ + +typedef __u32(*hashf_t) (const signed char *, int); + +struct reiserfs_bitmap_info { + __u32 free_count; +}; + +struct proc_dir_entry; + +#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO ) +typedef unsigned long int stat_cnt_t; +typedef struct reiserfs_proc_info_data { + spinlock_t lock; + int exiting; + int max_hash_collisions; + + stat_cnt_t breads; + stat_cnt_t bread_miss; + stat_cnt_t search_by_key; + stat_cnt_t search_by_key_fs_changed; + stat_cnt_t search_by_key_restarted; + + stat_cnt_t insert_item_restarted; + stat_cnt_t paste_into_item_restarted; + stat_cnt_t cut_from_item_restarted; + stat_cnt_t delete_solid_item_restarted; + stat_cnt_t delete_item_restarted; + + stat_cnt_t leaked_oid; + stat_cnt_t leaves_removable; + + /* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */ + stat_cnt_t balance_at[5]; /* XXX */ + /* sbk == search_by_key */ + stat_cnt_t sbk_read_at[5]; /* XXX */ + stat_cnt_t sbk_fs_changed[5]; + stat_cnt_t sbk_restarted[5]; + stat_cnt_t items_at[5]; /* XXX */ + stat_cnt_t free_at[5]; /* XXX */ + stat_cnt_t can_node_be_removed[5]; /* XXX */ + long int lnum[5]; /* XXX */ + long int rnum[5]; /* XXX */ + long int lbytes[5]; /* XXX */ + long int rbytes[5]; /* XXX */ + stat_cnt_t get_neighbors[5]; + stat_cnt_t get_neighbors_restart[5]; + stat_cnt_t need_l_neighbor[5]; + stat_cnt_t need_r_neighbor[5]; + + stat_cnt_t free_block; + struct __scan_bitmap_stats { + stat_cnt_t call; + stat_cnt_t wait; + stat_cnt_t bmap; + stat_cnt_t retry; + stat_cnt_t in_journal_hint; + stat_cnt_t in_journal_nohint; + stat_cnt_t stolen; + } scan_bitmap; + struct __journal_stats { + stat_cnt_t in_journal; + stat_cnt_t in_journal_bitmap; + stat_cnt_t in_journal_reusable; + stat_cnt_t lock_journal; + stat_cnt_t lock_journal_wait; + stat_cnt_t journal_being; + stat_cnt_t journal_relock_writers; + stat_cnt_t journal_relock_wcount; + stat_cnt_t mark_dirty; + stat_cnt_t mark_dirty_already; + stat_cnt_t mark_dirty_notjournal; + stat_cnt_t restore_prepared; + stat_cnt_t prepare; + stat_cnt_t prepare_retry; + } journal; +} reiserfs_proc_info_data_t; +#else +typedef struct reiserfs_proc_info_data { +} reiserfs_proc_info_data_t; +#endif + +/* reiserfs union of in-core super block data */ +struct reiserfs_sb_info { + struct buffer_head *s_sbh; /* Buffer containing the super block */ + /* both the comment and the choice of + name are unclear for s_rs -Hans */ + struct reiserfs_super_block *s_rs; /* Pointer to the super block in the buffer */ + struct reiserfs_bitmap_info *s_ap_bitmap; + struct reiserfs_journal *s_journal; /* pointer to journal information */ + unsigned short s_mount_state; /* reiserfs state (valid, invalid) */ + + /* Serialize writers access, replace the old bkl */ + struct mutex lock; + /* Owner of the lock (can be recursive) */ + struct task_struct *lock_owner; + /* Depth of the lock, start from -1 like the bkl */ + int lock_depth; + + /* Comment? -Hans */ + void (*end_io_handler) (struct buffer_head *, int); + hashf_t s_hash_function; /* pointer to function which is used + to sort names in directory. Set on + mount */ + unsigned long s_mount_opt; /* reiserfs's mount options are set + here (currently - NOTAIL, NOLOG, + REPLAYONLY) */ + + struct { /* This is a structure that describes block allocator options */ + unsigned long bits; /* Bitfield for enable/disable kind of options */ + unsigned long large_file_size; /* size started from which we consider file to be a large one(in blocks) */ + int border; /* percentage of disk, border takes */ + int preallocmin; /* Minimal file size (in blocks) starting from which we do preallocations */ + int preallocsize; /* Number of blocks we try to prealloc when file + reaches preallocmin size (in blocks) or + prealloc_list is empty. */ + } s_alloc_options; + + /* Comment? -Hans */ + wait_queue_head_t s_wait; + /* To be obsoleted soon by per buffer seals.. -Hans */ + atomic_t s_generation_counter; // increased by one every time the + // tree gets re-balanced + unsigned long s_properties; /* File system properties. Currently holds + on-disk FS format */ + + /* session statistics */ + int s_disk_reads; + int s_disk_writes; + int s_fix_nodes; + int s_do_balance; + int s_unneeded_left_neighbor; + int s_good_search_by_key_reada; + int s_bmaps; + int s_bmaps_without_search; + int s_direct2indirect; + int s_indirect2direct; + /* set up when it's ok for reiserfs_read_inode2() to read from + disk inode with nlink==0. Currently this is only used during + finish_unfinished() processing at mount time */ + int s_is_unlinked_ok; + reiserfs_proc_info_data_t s_proc_info_data; + struct proc_dir_entry *procdir; + int reserved_blocks; /* amount of blocks reserved for further allocations */ + spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */ + struct dentry *priv_root; /* root of /.reiserfs_priv */ + struct dentry *xattr_root; /* root of /.reiserfs_priv/xattrs */ + int j_errno; +#ifdef CONFIG_QUOTA + char *s_qf_names[MAXQUOTAS]; + int s_jquota_fmt; +#endif + char *s_jdev; /* Stored jdev for mount option showing */ +#ifdef CONFIG_REISERFS_CHECK + + struct tree_balance *cur_tb; /* + * Detects whether more than one + * copy of tb exists per superblock + * as a means of checking whether + * do_balance is executing concurrently + * against another tree reader/writer + * on a same mount point. + */ +#endif +}; + +/* Definitions of reiserfs on-disk properties: */ +#define REISERFS_3_5 0 +#define REISERFS_3_6 1 +#define REISERFS_OLD_FORMAT 2 + +enum reiserfs_mount_options { +/* Mount options */ + REISERFS_LARGETAIL, /* large tails will be created in a session */ + REISERFS_SMALLTAIL, /* small (for files less than block size) tails will be created in a session */ + REPLAYONLY, /* replay journal and return 0. Use by fsck */ + REISERFS_CONVERT, /* -o conv: causes conversion of old + format super block to the new + format. If not specified - old + partition will be dealt with in a + manner of 3.5.x */ + +/* -o hash={tea, rupasov, r5, detect} is meant for properly mounting +** reiserfs disks from 3.5.19 or earlier. 99% of the time, this option +** is not required. If the normal autodection code can't determine which +** hash to use (because both hashes had the same value for a file) +** use this option to force a specific hash. It won't allow you to override +** the existing hash on the FS, so if you have a tea hash disk, and mount +** with -o hash=rupasov, the mount will fail. +*/ + FORCE_TEA_HASH, /* try to force tea hash on mount */ + FORCE_RUPASOV_HASH, /* try to force rupasov hash on mount */ + FORCE_R5_HASH, /* try to force rupasov hash on mount */ + FORCE_HASH_DETECT, /* try to detect hash function on mount */ + + REISERFS_DATA_LOG, + REISERFS_DATA_ORDERED, + REISERFS_DATA_WRITEBACK, + +/* used for testing experimental features, makes benchmarking new + features with and without more convenient, should never be used by + users in any code shipped to users (ideally) */ + + REISERFS_NO_BORDER, + REISERFS_NO_UNHASHED_RELOCATION, + REISERFS_HASHED_RELOCATION, + REISERFS_ATTRS, + REISERFS_XATTRS_USER, + REISERFS_POSIXACL, + REISERFS_EXPOSE_PRIVROOT, + REISERFS_BARRIER_NONE, + REISERFS_BARRIER_FLUSH, + + /* Actions on error */ + REISERFS_ERROR_PANIC, + REISERFS_ERROR_RO, + REISERFS_ERROR_CONTINUE, + + REISERFS_USRQUOTA, /* User quota option specified */ + REISERFS_GRPQUOTA, /* Group quota option specified */ + + REISERFS_TEST1, + REISERFS_TEST2, + REISERFS_TEST3, + REISERFS_TEST4, + REISERFS_UNSUPPORTED_OPT, +}; + +#define reiserfs_r5_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_R5_HASH)) +#define reiserfs_rupasov_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_RUPASOV_HASH)) +#define reiserfs_tea_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_TEA_HASH)) +#define reiserfs_hash_detect(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_HASH_DETECT)) +#define reiserfs_no_border(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_BORDER)) +#define reiserfs_no_unhashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_NO_UNHASHED_RELOCATION)) +#define reiserfs_hashed_relocation(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_HASHED_RELOCATION)) +#define reiserfs_test4(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_TEST4)) + +#define have_large_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_LARGETAIL)) +#define have_small_tails(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_SMALLTAIL)) +#define replay_only(s) (REISERFS_SB(s)->s_mount_opt & (1 << REPLAYONLY)) +#define reiserfs_attrs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ATTRS)) +#define old_format_only(s) (REISERFS_SB(s)->s_properties & (1 << REISERFS_3_5)) +#define convert_reiserfs(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_CONVERT)) +#define reiserfs_data_log(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_LOG)) +#define reiserfs_data_ordered(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_ORDERED)) +#define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK)) +#define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER)) +#define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL)) +#define reiserfs_expose_privroot(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_EXPOSE_PRIVROOT)) +#define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s)) +#define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE)) +#define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH)) + +#define reiserfs_error_panic(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_PANIC)) +#define reiserfs_error_ro(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_RO)) + +void reiserfs_file_buffer(struct buffer_head *bh, int list); +extern struct file_system_type reiserfs_fs_type; +int reiserfs_resize(struct super_block *, unsigned long); + +#define CARRY_ON 0 +#define SCHEDULE_OCCURRED 1 + +#define SB_BUFFER_WITH_SB(s) (REISERFS_SB(s)->s_sbh) +#define SB_JOURNAL(s) (REISERFS_SB(s)->s_journal) +#define SB_JOURNAL_1st_RESERVED_BLOCK(s) (SB_JOURNAL(s)->j_1st_reserved_block) +#define SB_JOURNAL_LEN_FREE(s) (SB_JOURNAL(s)->j_journal_len_free) +#define SB_AP_BITMAP(s) (REISERFS_SB(s)->s_ap_bitmap) + +#define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->) + +/* A safe version of the "bdevname", which returns the "s_id" field of + * a superblock or else "Null superblock" if the super block is NULL. + */ +static inline char *reiserfs_bdevname(struct super_block *s) +{ + return (s == NULL) ? "Null superblock" : s->s_id; +} + +#define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal))) +static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal + *journal) +{ + return test_bit(J_ABORTED, &journal->j_state); +} + +#endif /* _LINUX_REISER_FS_SB */ diff --git a/trunk/include/linux/reiserfs_xattr.h b/trunk/include/linux/reiserfs_xattr.h index d8ce17c2459a..c2b71473266e 100644 --- a/trunk/include/linux/reiserfs_xattr.h +++ b/trunk/include/linux/reiserfs_xattr.h @@ -21,4 +21,132 @@ struct reiserfs_security_handle { size_t length; }; +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include + +struct inode; +struct dentry; +struct iattr; +struct super_block; +struct nameidata; + +int reiserfs_xattr_register_handlers(void) __init; +void reiserfs_xattr_unregister_handlers(void); +int reiserfs_xattr_init(struct super_block *sb, int mount_flags); +int reiserfs_lookup_privroot(struct super_block *sb); +int reiserfs_delete_xattrs(struct inode *inode); +int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs); +int reiserfs_permission(struct inode *inode, int mask); + +#ifdef CONFIG_REISERFS_FS_XATTR +#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir) +ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name, + void *buffer, size_t size); +int reiserfs_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags); +ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size); +int reiserfs_removexattr(struct dentry *dentry, const char *name); + +int reiserfs_xattr_get(struct inode *, const char *, void *, size_t); +int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int); +int reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *, + struct inode *, const char *, const void *, + size_t, int); + +extern const struct xattr_handler reiserfs_xattr_user_handler; +extern const struct xattr_handler reiserfs_xattr_trusted_handler; +extern const struct xattr_handler reiserfs_xattr_security_handler; +#ifdef CONFIG_REISERFS_FS_SECURITY +int reiserfs_security_init(struct inode *dir, struct inode *inode, + const struct qstr *qstr, + struct reiserfs_security_handle *sec); +int reiserfs_security_write(struct reiserfs_transaction_handle *th, + struct inode *inode, + struct reiserfs_security_handle *sec); +void reiserfs_security_free(struct reiserfs_security_handle *sec); +#endif + +static inline int reiserfs_xattrs_initialized(struct super_block *sb) +{ + return REISERFS_SB(sb)->priv_root != NULL; +} + +#define xattr_size(size) ((size) + sizeof(struct reiserfs_xattr_header)) +static inline loff_t reiserfs_xattr_nblocks(struct inode *inode, loff_t size) +{ + loff_t ret = 0; + if (reiserfs_file_data_log(inode)) { + ret = _ROUND_UP(xattr_size(size), inode->i_sb->s_blocksize); + ret >>= inode->i_sb->s_blocksize_bits; + } + return ret; +} + +/* We may have to create up to 3 objects: xattr root, xattr dir, xattr file. + * Let's try to be smart about it. + * xattr root: We cache it. If it's not cached, we may need to create it. + * xattr dir: If anything has been loaded for this inode, we can set a flag + * saying so. + * xattr file: Since we don't cache xattrs, we can't tell. We always include + * blocks for it. + * + * However, since root and dir can be created between calls - YOU MUST SAVE + * THIS VALUE. + */ +static inline size_t reiserfs_xattr_jcreate_nblocks(struct inode *inode) +{ + size_t nblocks = JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); + + if ((REISERFS_I(inode)->i_flags & i_has_xattr_dir) == 0) { + nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); + if (!REISERFS_SB(inode->i_sb)->xattr_root->d_inode) + nblocks += JOURNAL_BLOCKS_PER_OBJECT(inode->i_sb); + } + + return nblocks; +} + +static inline void reiserfs_init_xattr_rwsem(struct inode *inode) +{ + init_rwsem(&REISERFS_I(inode)->i_xattr_sem); +} + +#else + +#define reiserfs_getxattr NULL +#define reiserfs_setxattr NULL +#define reiserfs_listxattr NULL +#define reiserfs_removexattr NULL + +static inline void reiserfs_init_xattr_rwsem(struct inode *inode) +{ +} +#endif /* CONFIG_REISERFS_FS_XATTR */ + +#ifndef CONFIG_REISERFS_FS_SECURITY +static inline int reiserfs_security_init(struct inode *dir, + struct inode *inode, + const struct qstr *qstr, + struct reiserfs_security_handle *sec) +{ + return 0; +} +static inline int +reiserfs_security_write(struct reiserfs_transaction_handle *th, + struct inode *inode, + struct reiserfs_security_handle *sec) +{ + return 0; +} +static inline void reiserfs_security_free(struct reiserfs_security_handle *sec) +{} +#endif + +#endif /* __KERNEL__ */ + #endif /* _LINUX_REISERFS_XATTR_H */ diff --git a/trunk/include/linux/security.h b/trunk/include/linux/security.h index 673afbb8238a..c8949385e56e 100644 --- a/trunk/include/linux/security.h +++ b/trunk/include/linux/security.h @@ -22,36 +22,22 @@ #ifndef __LINUX_SECURITY_H #define __LINUX_SECURITY_H +#include +#include +#include +#include +#include +#include +#include +#include +#include /* PAGE_ALIGN */ +#include +#include #include -#include +#include #include -#include - -struct linux_binprm; -struct cred; -struct rlimit; -struct siginfo; -struct sem_array; -struct sembuf; -struct kern_ipc_perm; -struct audit_context; -struct super_block; -struct inode; -struct dentry; -struct file; -struct vfsmount; -struct path; -struct qstr; -struct nameidata; -struct iattr; -struct fown_struct; -struct file_operations; -struct shmid_kernel; -struct msg_msg; -struct msg_queue; -struct xattr; -struct xfrm_sec_ctx; -struct mm_struct; +#include +#include /* Maximum number of letters for an LSM name string */ #define SECURITY_NAME_MAX 10 @@ -63,7 +49,6 @@ struct mm_struct; struct ctl_table; struct audit_krule; struct user_namespace; -struct timezone; /* * These functions are in security/capability.c and are used @@ -146,6 +131,18 @@ struct request_sock; #define LSM_UNSAFE_PTRACE_CAP 4 #ifdef CONFIG_MMU +/* + * If a hint addr is less than mmap_min_addr change hint to be as + * low as possible but still greater than mmap_min_addr + */ +static inline unsigned long round_hint_to_min(unsigned long hint) +{ + hint &= PAGE_MASK; + if (((void *)hint != NULL) && + (hint < mmap_min_addr)) + return PAGE_ALIGN(mmap_min_addr); + return hint; +} extern int mmap_min_addr_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); #endif @@ -654,10 +651,6 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * manual page for definitions of the @clone_flags. * @clone_flags contains the flags indicating what should be shared. * Return 0 if permission is granted. - * @task_free: - * @task task being freed - * Handle release of task-related resources. (Note that this can be called - * from interrupt context.) * @cred_alloc_blank: * @cred points to the credentials. * @gfp indicates the atomicity of any memory allocations. @@ -1500,7 +1493,6 @@ struct security_operations { int (*dentry_open) (struct file *file, const struct cred *cred); int (*task_create) (unsigned long clone_flags); - void (*task_free) (struct task_struct *task); int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp); void (*cred_free) (struct cred *cred); int (*cred_prepare)(struct cred *new, const struct cred *old, @@ -1682,7 +1674,9 @@ int security_quotactl(int cmds, int type, int id, struct super_block *sb); int security_quota_on(struct dentry *dentry); int security_syslog(int type); int security_settime(const struct timespec *ts, const struct timezone *tz); +int security_vm_enough_memory(long pages); int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); +int security_vm_enough_memory_kern(long pages); int security_bprm_set_creds(struct linux_binprm *bprm); int security_bprm_check(struct linux_binprm *bprm); void security_bprm_committing_creds(struct linux_binprm *bprm); @@ -1758,7 +1752,6 @@ int security_file_send_sigiotask(struct task_struct *tsk, int security_file_receive(struct file *file); int security_dentry_open(struct file *file, const struct cred *cred); int security_task_create(unsigned long clone_flags); -void security_task_free(struct task_struct *task); int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); void security_cred_free(struct cred *cred); int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); @@ -1903,11 +1896,25 @@ static inline int security_settime(const struct timespec *ts, return cap_settime(ts, tz); } +static inline int security_vm_enough_memory(long pages) +{ + WARN_ON(current->mm == NULL); + return cap_vm_enough_memory(current->mm, pages); +} + static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) { + WARN_ON(mm == NULL); return cap_vm_enough_memory(mm, pages); } +static inline int security_vm_enough_memory_kern(long pages) +{ + /* If current->mm is a kernel thread then we will pass NULL, + for this specific case that is fine */ + return cap_vm_enough_memory(current->mm, pages); +} + static inline int security_bprm_set_creds(struct linux_binprm *bprm) { return cap_bprm_set_creds(bprm); @@ -2238,9 +2245,6 @@ static inline int security_task_create(unsigned long clone_flags) return 0; } -static inline void security_task_free(struct task_struct *task) -{ } - static inline int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) { return 0; diff --git a/trunk/include/linux/trace_seq.h b/trunk/include/linux/trace_seq.h index a32d86ec8bf2..7dadc3df0c77 100644 --- a/trunk/include/linux/trace_seq.h +++ b/trunk/include/linux/trace_seq.h @@ -44,7 +44,7 @@ extern int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len); extern int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, size_t len); extern void *trace_seq_reserve(struct trace_seq *s, size_t len); -extern int trace_seq_path(struct trace_seq *s, const struct path *path); +extern int trace_seq_path(struct trace_seq *s, struct path *path); #else /* CONFIG_TRACING */ static inline int trace_seq_printf(struct trace_seq *s, const char *fmt, ...) @@ -88,7 +88,7 @@ static inline void *trace_seq_reserve(struct trace_seq *s, size_t len) { return NULL; } -static inline int trace_seq_path(struct trace_seq *s, const struct path *path) +static inline int trace_seq_path(struct trace_seq *s, struct path *path) { return 0; } diff --git a/trunk/include/net/af_unix.h b/trunk/include/net/af_unix.h index ca68e2cef230..5a4e29b168c9 100644 --- a/trunk/include/net/af_unix.h +++ b/trunk/include/net/af_unix.h @@ -49,7 +49,8 @@ struct unix_sock { /* WARNING: sk has to be the first member */ struct sock sk; struct unix_address *addr; - struct path path; + struct dentry *dentry; + struct vfsmount *mnt; struct mutex readlock; struct sock *peer; struct sock *other; diff --git a/trunk/include/net/sock.h b/trunk/include/net/sock.h index 04bc0b30e9e9..f84be9ed6110 100644 --- a/trunk/include/net/sock.h +++ b/trunk/include/net/sock.h @@ -56,8 +56,6 @@ #include #include #include -#include -#include #include #include diff --git a/trunk/init/do_mounts_rd.c b/trunk/init/do_mounts_rd.c index 01f1306aa26e..887629e24c54 100644 --- a/trunk/init/do_mounts_rd.c +++ b/trunk/init/do_mounts_rd.c @@ -178,7 +178,7 @@ int __init rd_load_image(char *from) char *buf = NULL; unsigned short rotate = 0; decompress_fn decompressor = NULL; -#if !defined(CONFIG_S390) +#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES) char rotator[4] = { '|' , '/' , '-' , '\\' }; #endif @@ -264,7 +264,7 @@ int __init rd_load_image(char *from) } sys_read(in_fd, buf, BLOCK_SIZE); sys_write(out_fd, buf, BLOCK_SIZE); -#if !defined(CONFIG_S390) +#if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES) if (!(i % 16)) { printk("%c\b", rotator[rotate & 0x3]); rotate++; diff --git a/trunk/ipc/mqueue.c b/trunk/ipc/mqueue.c index 28bd64ddeda3..86ee272de210 100644 --- a/trunk/ipc/mqueue.c +++ b/trunk/ipc/mqueue.c @@ -188,20 +188,30 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; struct ipc_namespace *ns = data; + int error; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = MQUEUE_MAGIC; sb->s_op = &mqueue_super_ops; - inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL); - if (IS_ERR(inode)) - return PTR_ERR(inode); + inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, + NULL); + if (IS_ERR(inode)) { + error = PTR_ERR(inode); + goto out; + } - sb->s_root = d_make_root(inode); - if (!sb->s_root) - return -ENOMEM; - return 0; + sb->s_root = d_alloc_root(inode); + if (!sb->s_root) { + iput(inode); + error = -ENOMEM; + goto out; + } + error = 0; + +out: + return error; } static struct dentry *mqueue_mount(struct file_system_type *fs_type, diff --git a/trunk/ipc/msgutil.c b/trunk/ipc/msgutil.c index 26143d377c95..5652101cdac0 100644 --- a/trunk/ipc/msgutil.c +++ b/trunk/ipc/msgutil.c @@ -13,9 +13,7 @@ #include #include #include -#include #include -#include #include #include "util.h" diff --git a/trunk/kernel/audit.c b/trunk/kernel/audit.c index 1c7f2c61416b..bb0eb5bb9a0a 100644 --- a/trunk/kernel/audit.c +++ b/trunk/kernel/audit.c @@ -1418,7 +1418,7 @@ void audit_log_untrustedstring(struct audit_buffer *ab, const char *string) /* This is a helper-function to print the escaped d_path */ void audit_log_d_path(struct audit_buffer *ab, const char *prefix, - const struct path *path) + struct path *path) { char *p, *pathname; diff --git a/trunk/kernel/cgroup.c b/trunk/kernel/cgroup.c index 1ece8e20fdb5..c6877fe9a831 100644 --- a/trunk/kernel/cgroup.c +++ b/trunk/kernel/cgroup.c @@ -1472,6 +1472,7 @@ static int cgroup_get_rootdir(struct super_block *sb) struct inode *inode = cgroup_new_inode(S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, sb); + struct dentry *dentry; if (!inode) return -ENOMEM; @@ -1480,9 +1481,12 @@ static int cgroup_get_rootdir(struct super_block *sb) inode->i_op = &cgroup_dir_inode_operations; /* directories start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); - sb->s_root = d_make_root(inode); - if (!sb->s_root) + dentry = d_alloc_root(inode); + if (!dentry) { + iput(inode); return -ENOMEM; + } + sb->s_root = dentry; /* for everything else we want ->d_op set */ sb->s_d_op = &cgroup_dops; return 0; diff --git a/trunk/kernel/cred.c b/trunk/kernel/cred.c index 97b36eeca4c9..5791612a4045 100644 --- a/trunk/kernel/cred.c +++ b/trunk/kernel/cred.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #if 0 diff --git a/trunk/kernel/exit.c b/trunk/kernel/exit.c index 7ad335c3045a..0ed15fed579f 100644 --- a/trunk/kernel/exit.c +++ b/trunk/kernel/exit.c @@ -52,7 +52,6 @@ #include #include #include -#include #include #include diff --git a/trunk/kernel/fork.c b/trunk/kernel/fork.c index 26a7138bb849..c4f38a849436 100644 --- a/trunk/kernel/fork.c +++ b/trunk/kernel/fork.c @@ -193,7 +193,6 @@ void __put_task_struct(struct task_struct *tsk) WARN_ON(atomic_read(&tsk->usage)); WARN_ON(tsk == current); - security_task_free(tsk); exit_creds(tsk); delayacct_tsk_free(tsk); put_signal_struct(tsk->signal); @@ -356,7 +355,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) charge = 0; if (mpnt->vm_flags & VM_ACCOUNT) { unsigned int len = (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT; - if (security_vm_enough_memory_mm(oldmm, len)) /* sic */ + if (security_vm_enough_memory(len)) goto fail_nomem; charge = len; } diff --git a/trunk/kernel/padata.c b/trunk/kernel/padata.c index 6f10eb285ece..b45259931512 100644 --- a/trunk/kernel/padata.c +++ b/trunk/kernel/padata.c @@ -29,6 +29,7 @@ #include #include +#define MAX_SEQ_NR (INT_MAX - NR_CPUS) #define MAX_OBJ_NUM 1000 static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index) @@ -42,19 +43,18 @@ static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index) return target_cpu; } -static int padata_cpu_hash(struct parallel_data *pd) +static int padata_cpu_hash(struct padata_priv *padata) { int cpu_index; + struct parallel_data *pd; + + pd = padata->pd; /* * Hash the sequence numbers to the cpus by taking * seq_nr mod. number of cpus in use. */ - - spin_lock(&pd->seq_lock); - cpu_index = pd->seq_nr % cpumask_weight(pd->cpumask.pcpu); - pd->seq_nr++; - spin_unlock(&pd->seq_lock); + cpu_index = padata->seq_nr % cpumask_weight(pd->cpumask.pcpu); return padata_index_to_cpu(pd, cpu_index); } @@ -132,7 +132,12 @@ int padata_do_parallel(struct padata_instance *pinst, padata->pd = pd; padata->cb_cpu = cb_cpu; - target_cpu = padata_cpu_hash(pd); + if (unlikely(atomic_read(&pd->seq_nr) == pd->max_seq_nr)) + atomic_set(&pd->seq_nr, -1); + + padata->seq_nr = atomic_inc_return(&pd->seq_nr); + + target_cpu = padata_cpu_hash(padata); queue = per_cpu_ptr(pd->pqueue, target_cpu); spin_lock(&queue->parallel.lock); @@ -168,7 +173,7 @@ EXPORT_SYMBOL(padata_do_parallel); static struct padata_priv *padata_get_next(struct parallel_data *pd) { int cpu, num_cpus; - unsigned int next_nr, next_index; + int next_nr, next_index; struct padata_parallel_queue *queue, *next_queue; struct padata_priv *padata; struct padata_list *reorder; @@ -184,6 +189,14 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd) cpu = padata_index_to_cpu(pd, next_index); next_queue = per_cpu_ptr(pd->pqueue, cpu); + if (unlikely(next_nr > pd->max_seq_nr)) { + next_nr = next_nr - pd->max_seq_nr - 1; + next_index = next_nr % num_cpus; + cpu = padata_index_to_cpu(pd, next_index); + next_queue = per_cpu_ptr(pd->pqueue, cpu); + pd->processed = 0; + } + padata = NULL; reorder = &next_queue->reorder; @@ -192,6 +205,8 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd) padata = list_entry(reorder->list.next, struct padata_priv, list); + BUG_ON(next_nr != padata->seq_nr); + spin_lock(&reorder->lock); list_del_init(&padata->list); atomic_dec(&pd->reorder_objects); @@ -215,7 +230,6 @@ static struct padata_priv *padata_get_next(struct parallel_data *pd) static void padata_reorder(struct parallel_data *pd) { - int cb_cpu; struct padata_priv *padata; struct padata_serial_queue *squeue; struct padata_instance *pinst = pd->pinst; @@ -256,14 +270,13 @@ static void padata_reorder(struct parallel_data *pd) return; } - cb_cpu = padata->cb_cpu; - squeue = per_cpu_ptr(pd->squeue, cb_cpu); + squeue = per_cpu_ptr(pd->squeue, padata->cb_cpu); spin_lock(&squeue->serial.lock); list_add_tail(&padata->list, &squeue->serial.list); spin_unlock(&squeue->serial.lock); - queue_work_on(cb_cpu, pinst->wq, &squeue->work); + queue_work_on(padata->cb_cpu, pinst->wq, &squeue->work); } spin_unlock_bh(&pd->lock); @@ -387,7 +400,7 @@ static void padata_init_squeues(struct parallel_data *pd) /* Initialize all percpu queues used by parallel workers */ static void padata_init_pqueues(struct parallel_data *pd) { - int cpu_index, cpu; + int cpu_index, num_cpus, cpu; struct padata_parallel_queue *pqueue; cpu_index = 0; @@ -402,6 +415,9 @@ static void padata_init_pqueues(struct parallel_data *pd) INIT_WORK(&pqueue->work, padata_parallel_worker); atomic_set(&pqueue->num_obj, 0); } + + num_cpus = cpumask_weight(pd->cpumask.pcpu); + pd->max_seq_nr = num_cpus ? (MAX_SEQ_NR / num_cpus) * num_cpus - 1 : 0; } /* Allocate and initialize the internal cpumask dependend resources. */ @@ -428,7 +444,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst, padata_init_pqueues(pd); padata_init_squeues(pd); setup_timer(&pd->timer, padata_reorder_timer, (unsigned long)pd); - pd->seq_nr = 0; + atomic_set(&pd->seq_nr, -1); atomic_set(&pd->reorder_objects, 0); atomic_set(&pd->refcnt, 0); pd->pinst = pinst; diff --git a/trunk/kernel/sched/core.c b/trunk/kernel/sched/core.c index 503d6426126d..a35cb8dbd8c4 100644 --- a/trunk/kernel/sched/core.c +++ b/trunk/kernel/sched/core.c @@ -71,7 +71,6 @@ #include #include #include -#include #include #include diff --git a/trunk/kernel/sysctl.c b/trunk/kernel/sysctl.c index 11d53046b905..f487f257e05e 100644 --- a/trunk/kernel/sysctl.c +++ b/trunk/kernel/sysctl.c @@ -58,7 +58,6 @@ #include #include #include -#include #include #include diff --git a/trunk/kernel/trace/trace_output.c b/trunk/kernel/trace/trace_output.c index 859fae6b1825..c5a01873567d 100644 --- a/trunk/kernel/trace/trace_output.c +++ b/trunk/kernel/trace/trace_output.c @@ -264,7 +264,7 @@ void *trace_seq_reserve(struct trace_seq *s, size_t len) return ret; } -int trace_seq_path(struct trace_seq *s, const struct path *path) +int trace_seq_path(struct trace_seq *s, struct path *path) { unsigned char *p; diff --git a/trunk/mm/memcontrol.c b/trunk/mm/memcontrol.c index 26c6f4ec20f4..37281816ff67 100644 --- a/trunk/mm/memcontrol.c +++ b/trunk/mm/memcontrol.c @@ -5230,6 +5230,8 @@ static int mem_cgroup_count_precharge_pte_range(pmd_t *pmd, spinlock_t *ptl; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); for (; addr != end; pte++, addr += PAGE_SIZE) @@ -5390,6 +5392,8 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd, spinlock_t *ptl; split_huge_page_pmd(walk->mm, pmd); + if (pmd_trans_unstable(pmd)) + return 0; retry: pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); for (; addr != end; addr += PAGE_SIZE) { diff --git a/trunk/mm/memory.c b/trunk/mm/memory.c index 8438c157e4d9..e01abb908b6b 100644 --- a/trunk/mm/memory.c +++ b/trunk/mm/memory.c @@ -1247,16 +1247,24 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, do { next = pmd_addr_end(addr, end); if (pmd_trans_huge(*pmd)) { - if (next-addr != HPAGE_PMD_SIZE) { + if (next - addr != HPAGE_PMD_SIZE) { VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem)); split_huge_page_pmd(vma->vm_mm, pmd); } else if (zap_huge_pmd(tlb, vma, pmd, addr)) - continue; + goto next; /* fall through */ } - if (pmd_none_or_clear_bad(pmd)) - continue; + /* + * Here there can be other concurrent MADV_DONTNEED or + * trans huge page faults running, and if the pmd is + * none or trans huge it can change under us. This is + * because MADV_DONTNEED holds the mmap_sem in read + * mode. + */ + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) + goto next; next = zap_pte_range(tlb, vma, pmd, addr, next, details); +next: cond_resched(); } while (pmd++, addr = next, addr != end); @@ -1282,10 +1290,10 @@ static inline unsigned long zap_pud_range(struct mmu_gather *tlb, return addr; } -static void unmap_page_range(struct mmu_gather *tlb, - struct vm_area_struct *vma, - unsigned long addr, unsigned long end, - struct zap_details *details) +static unsigned long unmap_page_range(struct mmu_gather *tlb, + struct vm_area_struct *vma, + unsigned long addr, unsigned long end, + struct zap_details *details) { pgd_t *pgd; unsigned long next; @@ -1305,47 +1313,8 @@ static void unmap_page_range(struct mmu_gather *tlb, } while (pgd++, addr = next, addr != end); tlb_end_vma(tlb, vma); mem_cgroup_uncharge_end(); -} - - -static void unmap_single_vma(struct mmu_gather *tlb, - struct vm_area_struct *vma, unsigned long start_addr, - unsigned long end_addr, unsigned long *nr_accounted, - struct zap_details *details) -{ - unsigned long start = max(vma->vm_start, start_addr); - unsigned long end; - - if (start >= vma->vm_end) - return; - end = min(vma->vm_end, end_addr); - if (end <= vma->vm_start) - return; - - if (vma->vm_flags & VM_ACCOUNT) - *nr_accounted += (end - start) >> PAGE_SHIFT; - - if (unlikely(is_pfn_mapping(vma))) - untrack_pfn_vma(vma, 0, 0); - if (start != end) { - if (unlikely(is_vm_hugetlb_page(vma))) { - /* - * It is undesirable to test vma->vm_file as it - * should be non-null for valid hugetlb area. - * However, vm_file will be NULL in the error - * cleanup path of do_mmap_pgoff. When - * hugetlbfs ->mmap method fails, - * do_mmap_pgoff() nullifies vma->vm_file - * before calling this function to clean up. - * Since no pte has actually been setup, it is - * safe to do nothing in this case. - */ - if (vma->vm_file) - unmap_hugepage_range(vma, start, end, NULL); - } else - unmap_page_range(tlb, vma, start, end, details); - } + return addr; } /** @@ -1357,6 +1326,8 @@ static void unmap_single_vma(struct mmu_gather *tlb, * @nr_accounted: Place number of unmapped pages in vm-accountable vma's here * @details: details of nonlinear truncation or shared cache invalidation * + * Returns the end address of the unmapping (restart addr if interrupted). + * * Unmap all pages in the vma list. * * Only addresses between `start' and `end' will be unmapped. @@ -1368,54 +1339,65 @@ static void unmap_single_vma(struct mmu_gather *tlb, * ensure that any thus-far unmapped pages are flushed before unmap_vmas() * drops the lock and schedules. */ -void unmap_vmas(struct mmu_gather *tlb, +unsigned long unmap_vmas(struct mmu_gather *tlb, struct vm_area_struct *vma, unsigned long start_addr, unsigned long end_addr, unsigned long *nr_accounted, struct zap_details *details) { + unsigned long start = start_addr; struct mm_struct *mm = vma->vm_mm; mmu_notifier_invalidate_range_start(mm, start_addr, end_addr); - for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) - unmap_single_vma(tlb, vma, start_addr, end_addr, nr_accounted, - details); - mmu_notifier_invalidate_range_end(mm, start_addr, end_addr); -} + for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) { + unsigned long end; -/** - * zap_page_range - remove user pages in a given range - * @vma: vm_area_struct holding the applicable pages - * @address: starting address of pages to zap - * @size: number of bytes to zap - * @details: details of nonlinear truncation or shared cache invalidation - * - * Caller must protect the VMA list - */ -void zap_page_range(struct vm_area_struct *vma, unsigned long address, - unsigned long size, struct zap_details *details) -{ - struct mm_struct *mm = vma->vm_mm; - struct mmu_gather tlb; - unsigned long end = address + size; - unsigned long nr_accounted = 0; + start = max(vma->vm_start, start_addr); + if (start >= vma->vm_end) + continue; + end = min(vma->vm_end, end_addr); + if (end <= vma->vm_start) + continue; - lru_add_drain(); - tlb_gather_mmu(&tlb, mm, 0); - update_hiwater_rss(mm); - unmap_vmas(&tlb, vma, address, end, &nr_accounted, details); - tlb_finish_mmu(&tlb, address, end); + if (vma->vm_flags & VM_ACCOUNT) + *nr_accounted += (end - start) >> PAGE_SHIFT; + + if (unlikely(is_pfn_mapping(vma))) + untrack_pfn_vma(vma, 0, 0); + + while (start != end) { + if (unlikely(is_vm_hugetlb_page(vma))) { + /* + * It is undesirable to test vma->vm_file as it + * should be non-null for valid hugetlb area. + * However, vm_file will be NULL in the error + * cleanup path of do_mmap_pgoff. When + * hugetlbfs ->mmap method fails, + * do_mmap_pgoff() nullifies vma->vm_file + * before calling this function to clean up. + * Since no pte has actually been setup, it is + * safe to do nothing in this case. + */ + if (vma->vm_file) + unmap_hugepage_range(vma, start, end, NULL); + + start = end; + } else + start = unmap_page_range(tlb, vma, start, end, details); + } + } + + mmu_notifier_invalidate_range_end(mm, start_addr, end_addr); + return start; /* which is now the end (or restart) address */ } /** - * zap_page_range_single - remove user pages in a given range + * zap_page_range - remove user pages in a given range * @vma: vm_area_struct holding the applicable pages * @address: starting address of pages to zap * @size: number of bytes to zap * @details: details of nonlinear truncation or shared cache invalidation - * - * The range must fit into one VMA. */ -static void zap_page_range_single(struct vm_area_struct *vma, unsigned long address, +unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size, struct zap_details *details) { struct mm_struct *mm = vma->vm_mm; @@ -1426,10 +1408,9 @@ static void zap_page_range_single(struct vm_area_struct *vma, unsigned long addr lru_add_drain(); tlb_gather_mmu(&tlb, mm, 0); update_hiwater_rss(mm); - mmu_notifier_invalidate_range_start(mm, address, end); - unmap_single_vma(&tlb, vma, address, end, &nr_accounted, details); - mmu_notifier_invalidate_range_end(mm, address, end); + end = unmap_vmas(&tlb, vma, address, end, &nr_accounted, details); tlb_finish_mmu(&tlb, address, end); + return end; } /** @@ -1450,7 +1431,7 @@ int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, if (address < vma->vm_start || address + size > vma->vm_end || !(vma->vm_flags & VM_PFNMAP)) return -1; - zap_page_range_single(vma, address, size, NULL); + zap_page_range(vma, address, size, NULL); return 0; } EXPORT_SYMBOL_GPL(zap_vma_ptes); @@ -2797,7 +2778,7 @@ static void unmap_mapping_range_vma(struct vm_area_struct *vma, unsigned long start_addr, unsigned long end_addr, struct zap_details *details) { - zap_page_range_single(vma, start_addr, end_addr - start_addr, details); + zap_page_range(vma, start_addr, end_addr - start_addr, details); } static inline void unmap_mapping_range_tree(struct prio_tree_root *root, diff --git a/trunk/mm/mempolicy.c b/trunk/mm/mempolicy.c index 47296fee23db..0a3757067631 100644 --- a/trunk/mm/mempolicy.c +++ b/trunk/mm/mempolicy.c @@ -512,7 +512,7 @@ static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud, do { next = pmd_addr_end(addr, end); split_huge_page_pmd(vma->vm_mm, pmd); - if (pmd_none_or_clear_bad(pmd)) + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) continue; if (check_pte_range(vma, pmd, addr, next, nodes, flags, private)) diff --git a/trunk/mm/mincore.c b/trunk/mm/mincore.c index 636a86876ff2..936b4cee8cb1 100644 --- a/trunk/mm/mincore.c +++ b/trunk/mm/mincore.c @@ -164,7 +164,7 @@ static void mincore_pmd_range(struct vm_area_struct *vma, pud_t *pud, } /* fall through */ } - if (pmd_none_or_clear_bad(pmd)) + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) mincore_unmapped_range(vma, addr, next, vec); else mincore_pte_range(vma, pmd, addr, next, vec); diff --git a/trunk/mm/mmap.c b/trunk/mm/mmap.c index 6f3766b57803..da15a79b1441 100644 --- a/trunk/mm/mmap.c +++ b/trunk/mm/mmap.c @@ -935,19 +935,6 @@ void vm_stat_account(struct mm_struct *mm, unsigned long flags, } #endif /* CONFIG_PROC_FS */ -/* - * If a hint addr is less than mmap_min_addr change hint to be as - * low as possible but still greater than mmap_min_addr - */ -static inline unsigned long round_hint_to_min(unsigned long hint) -{ - hint &= PAGE_MASK; - if (((void *)hint != NULL) && - (hint < mmap_min_addr)) - return PAGE_ALIGN(mmap_min_addr); - return hint; -} - /* * The caller must hold down_write(¤t->mm->mmap_sem). */ @@ -1248,7 +1235,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr, */ if (accountable_mapping(file, vm_flags)) { charged = len >> PAGE_SHIFT; - if (security_vm_enough_memory_mm(mm, charged)) + if (security_vm_enough_memory(charged)) return -ENOMEM; vm_flags |= VM_ACCOUNT; } @@ -2193,7 +2180,7 @@ unsigned long do_brk(unsigned long addr, unsigned long len) if (mm->map_count > sysctl_max_map_count) return -ENOMEM; - if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT)) + if (security_vm_enough_memory(len >> PAGE_SHIFT)) return -ENOMEM; /* Can we just expand an old private anonymous mapping? */ @@ -2237,6 +2224,7 @@ void exit_mmap(struct mm_struct *mm) struct mmu_gather tlb; struct vm_area_struct *vma; unsigned long nr_accounted = 0; + unsigned long end; /* mm's last user has gone, and its about to be pulled down */ mmu_notifier_release(mm); @@ -2261,11 +2249,11 @@ void exit_mmap(struct mm_struct *mm) tlb_gather_mmu(&tlb, mm, 1); /* update_hiwater_rss(mm) here? but nobody should be looking */ /* Use -1 here to ensure all VMAs in the mm are unmapped */ - unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL); + end = unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL); vm_unacct_memory(nr_accounted); free_pgtables(&tlb, vma, FIRST_USER_ADDRESS, 0); - tlb_finish_mmu(&tlb, 0, -1); + tlb_finish_mmu(&tlb, 0, end); /* * Walk the list again, actually closing and freeing it, diff --git a/trunk/mm/mprotect.c b/trunk/mm/mprotect.c index 142ef4a1f480..f437d054c3bf 100644 --- a/trunk/mm/mprotect.c +++ b/trunk/mm/mprotect.c @@ -168,7 +168,7 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, if (!(oldflags & (VM_ACCOUNT|VM_WRITE|VM_HUGETLB| VM_SHARED|VM_NORESERVE))) { charged = nrpages; - if (security_vm_enough_memory_mm(mm, charged)) + if (security_vm_enough_memory(charged)) return -ENOMEM; newflags |= VM_ACCOUNT; } diff --git a/trunk/mm/mremap.c b/trunk/mm/mremap.c index db8d983b5a7d..87bb8393e7d2 100644 --- a/trunk/mm/mremap.c +++ b/trunk/mm/mremap.c @@ -329,7 +329,7 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr, if (vma->vm_flags & VM_ACCOUNT) { unsigned long charged = (new_len - old_len) >> PAGE_SHIFT; - if (security_vm_enough_memory_mm(mm, charged)) + if (security_vm_enough_memory(charged)) goto Efault; *p = charged; } diff --git a/trunk/mm/pagewalk.c b/trunk/mm/pagewalk.c index 2f5cf10ff660..aa9701e12714 100644 --- a/trunk/mm/pagewalk.c +++ b/trunk/mm/pagewalk.c @@ -59,7 +59,7 @@ static int walk_pmd_range(pud_t *pud, unsigned long addr, unsigned long end, continue; split_huge_page_pmd(walk->mm, pmd); - if (pmd_none_or_clear_bad(pmd)) + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) goto again; err = walk_pte_range(pmd, addr, next, walk); if (err) diff --git a/trunk/mm/shmem.c b/trunk/mm/shmem.c index 7a45ad004cfd..b7e195571862 100644 --- a/trunk/mm/shmem.c +++ b/trunk/mm/shmem.c @@ -127,7 +127,7 @@ static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb) static inline int shmem_acct_size(unsigned long flags, loff_t size) { return (flags & VM_NORESERVE) ? - 0 : security_vm_enough_memory_mm(current->mm, VM_ACCT(size)); + 0 : security_vm_enough_memory_kern(VM_ACCT(size)); } static inline void shmem_unacct_size(unsigned long flags, loff_t size) @@ -145,7 +145,7 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size) static inline int shmem_acct_block(unsigned long flags) { return (flags & VM_NORESERVE) ? - security_vm_enough_memory_mm(current->mm, VM_ACCT(PAGE_CACHE_SIZE)) : 0; + security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE)) : 0; } static inline void shmem_unacct_blocks(unsigned long flags, long pages) @@ -2175,6 +2175,7 @@ static void shmem_put_super(struct super_block *sb) int shmem_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; + struct dentry *root; struct shmem_sb_info *sbinfo; int err = -ENOMEM; @@ -2231,11 +2232,14 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) goto failed; inode->i_uid = sbinfo->uid; inode->i_gid = sbinfo->gid; - sb->s_root = d_make_root(inode); - if (!sb->s_root) - goto failed; + root = d_alloc_root(inode); + if (!root) + goto failed_iput; + sb->s_root = root; return 0; +failed_iput: + iput(inode); failed: shmem_put_super(sb); return err; diff --git a/trunk/mm/swapfile.c b/trunk/mm/swapfile.c index 6bf67ab6e469..44595a373e42 100644 --- a/trunk/mm/swapfile.c +++ b/trunk/mm/swapfile.c @@ -932,9 +932,7 @@ static inline int unuse_pmd_range(struct vm_area_struct *vma, pud_t *pud, pmd = pmd_offset(pud, addr); do { next = pmd_addr_end(addr, end); - if (unlikely(pmd_trans_huge(*pmd))) - continue; - if (pmd_none_or_clear_bad(pmd)) + if (pmd_none_or_trans_huge_or_clear_bad(pmd)) continue; ret = unuse_pte_range(vma, pmd, addr, next, entry, page); if (ret) @@ -1563,8 +1561,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - BUG_ON(!current->mm); - pathname = getname(specialfile); err = PTR_ERR(pathname); if (IS_ERR(pathname)) @@ -1592,7 +1588,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) spin_unlock(&swap_lock); goto out_dput; } - if (!security_vm_enough_memory_mm(current->mm, p->pages)) + if (!security_vm_enough_memory(p->pages)) vm_unacct_memory(p->pages); else { err = -ENOMEM; diff --git a/trunk/net/dns_resolver/dns_key.c b/trunk/net/dns_resolver/dns_key.c index c73bba326d70..fa000d26dc60 100644 --- a/trunk/net/dns_resolver/dns_key.c +++ b/trunk/net/dns_resolver/dns_key.c @@ -281,7 +281,6 @@ static int __init init_dns_resolver(void) /* instruct request_key() to use this special keyring as a cache for * the results it looks up */ - set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags); cred->thread_keyring = keyring; cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; dns_resolver_cache = cred; diff --git a/trunk/net/sunrpc/rpc_pipe.c b/trunk/net/sunrpc/rpc_pipe.c index 7d6dd6efbdbe..63a7a7add21e 100644 --- a/trunk/net/sunrpc/rpc_pipe.c +++ b/trunk/net/sunrpc/rpc_pipe.c @@ -1033,9 +1033,13 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran = 1; inode = rpc_get_inode(sb, S_IFDIR | 0755); - sb->s_root = root = d_make_root(inode); - if (!root) + if (!inode) + return -ENOMEM; + sb->s_root = root = d_alloc_root(inode); + if (!root) { + iput(inode); return -ENOMEM; + } if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) return -ENOMEM; return 0; diff --git a/trunk/net/unix/af_unix.c b/trunk/net/unix/af_unix.c index eb4277c33188..8ee85aa79fa7 100644 --- a/trunk/net/unix/af_unix.c +++ b/trunk/net/unix/af_unix.c @@ -293,7 +293,7 @@ static struct sock *unix_find_socket_byinode(struct inode *i) spin_lock(&unix_table_lock); sk_for_each(s, node, &unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]) { - struct dentry *dentry = unix_sk(s)->path.dentry; + struct dentry *dentry = unix_sk(s)->dentry; if (dentry && dentry->d_inode == i) { sock_hold(s); @@ -377,7 +377,8 @@ static void unix_sock_destructor(struct sock *sk) static int unix_release_sock(struct sock *sk, int embrion) { struct unix_sock *u = unix_sk(sk); - struct path path; + struct dentry *dentry; + struct vfsmount *mnt; struct sock *skpair; struct sk_buff *skb; int state; @@ -388,9 +389,10 @@ static int unix_release_sock(struct sock *sk, int embrion) unix_state_lock(sk); sock_orphan(sk); sk->sk_shutdown = SHUTDOWN_MASK; - path = u->path; - u->path.dentry = NULL; - u->path.mnt = NULL; + dentry = u->dentry; + u->dentry = NULL; + mnt = u->mnt; + u->mnt = NULL; state = sk->sk_state; sk->sk_state = TCP_CLOSE; unix_state_unlock(sk); @@ -423,8 +425,10 @@ static int unix_release_sock(struct sock *sk, int embrion) kfree_skb(skb); } - if (path.dentry) - path_put(&path); + if (dentry) { + dput(dentry); + mntput(mnt); + } sock_put(sk); @@ -637,8 +641,8 @@ static struct sock *unix_create1(struct net *net, struct socket *sock) sk->sk_max_ack_backlog = net->unx.sysctl_max_dgram_qlen; sk->sk_destruct = unix_sock_destructor; u = unix_sk(sk); - u->path.dentry = NULL; - u->path.mnt = NULL; + u->dentry = NULL; + u->mnt = NULL; spin_lock_init(&u->lock); atomic_long_set(&u->inflight, 0); INIT_LIST_HEAD(&u->link); @@ -784,7 +788,7 @@ static struct sock *unix_find_other(struct net *net, goto put_fail; if (u->sk_type == type) - touch_atime(&path); + touch_atime(path.mnt, path.dentry); path_put(&path); @@ -798,9 +802,9 @@ static struct sock *unix_find_other(struct net *net, u = unix_find_socket_byname(net, sunname, len, type, hash); if (u) { struct dentry *dentry; - dentry = unix_sk(u)->path.dentry; + dentry = unix_sk(u)->dentry; if (dentry) - touch_atime(&unix_sk(u)->path); + touch_atime(unix_sk(u)->mnt, dentry); } else goto fail; } @@ -906,7 +910,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) list = &unix_socket_table[addr->hash]; } else { list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; - u->path = path; + u->dentry = path.dentry; + u->mnt = path.mnt; } err = 0; @@ -1188,9 +1193,9 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, atomic_inc(&otheru->addr->refcnt); newu->addr = otheru->addr; } - if (otheru->path.dentry) { - path_get(&otheru->path); - newu->path = otheru->path; + if (otheru->dentry) { + newu->dentry = dget(otheru->dentry); + newu->mnt = mntget(otheru->mnt); } /* Set credentials */ diff --git a/trunk/net/unix/diag.c b/trunk/net/unix/diag.c index f0486ae9ebe6..4195555aea65 100644 --- a/trunk/net/unix/diag.c +++ b/trunk/net/unix/diag.c @@ -29,7 +29,7 @@ static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb) static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb) { - struct dentry *dentry = unix_sk(sk)->path.dentry; + struct dentry *dentry = unix_sk(sk)->dentry; struct unix_diag_vfs *uv; if (dentry) { diff --git a/trunk/security/Kconfig b/trunk/security/Kconfig index ccc61f8006b2..51bd5a0b69ae 100644 --- a/trunk/security/Kconfig +++ b/trunk/security/Kconfig @@ -187,7 +187,6 @@ source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig source security/apparmor/Kconfig -source security/yama/Kconfig source security/integrity/Kconfig @@ -197,7 +196,6 @@ choice default DEFAULT_SECURITY_SMACK if SECURITY_SMACK default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR - default DEFAULT_SECURITY_YAMA if SECURITY_YAMA default DEFAULT_SECURITY_DAC help @@ -216,9 +214,6 @@ choice config DEFAULT_SECURITY_APPARMOR bool "AppArmor" if SECURITY_APPARMOR=y - config DEFAULT_SECURITY_YAMA - bool "Yama" if SECURITY_YAMA=y - config DEFAULT_SECURITY_DAC bool "Unix Discretionary Access Controls" @@ -230,7 +225,6 @@ config DEFAULT_SECURITY default "smack" if DEFAULT_SECURITY_SMACK default "tomoyo" if DEFAULT_SECURITY_TOMOYO default "apparmor" if DEFAULT_SECURITY_APPARMOR - default "yama" if DEFAULT_SECURITY_YAMA default "" if DEFAULT_SECURITY_DAC endmenu diff --git a/trunk/security/Makefile b/trunk/security/Makefile index c26c81e92571..a5e502f8a05b 100644 --- a/trunk/security/Makefile +++ b/trunk/security/Makefile @@ -7,7 +7,6 @@ subdir-$(CONFIG_SECURITY_SELINUX) += selinux subdir-$(CONFIG_SECURITY_SMACK) += smack subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor -subdir-$(CONFIG_SECURITY_YAMA) += yama # always enable default capabilities obj-y += commoncap.o @@ -22,7 +21,6 @@ obj-$(CONFIG_SECURITY_SMACK) += smack/built-in.o obj-$(CONFIG_AUDIT) += lsm_audit.o obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/built-in.o obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/built-in.o -obj-$(CONFIG_SECURITY_YAMA) += yama/built-in.o obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o # Object integrity file lists diff --git a/trunk/security/apparmor/Makefile b/trunk/security/apparmor/Makefile index 806bd19af7f2..2dafe50a2e25 100644 --- a/trunk/security/apparmor/Makefile +++ b/trunk/security/apparmor/Makefile @@ -15,7 +15,7 @@ clean-files := capability_names.h rlim_names.h # to # [1] = "dac_override", quiet_cmd_make-caps = GEN $@ -cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\ +cmd_make-caps = echo "static const char *capability_names[] = {" > $@ ;\ sed $< >>$@ -r -n -e '/CAP_FS_MASK/d' \ -e 's/^\#define[ \t]+CAP_([A-Z0-9_]+)[ \t]+([0-9]+)/[\2] = "\L\1",/p';\ echo "};" >> $@ @@ -28,38 +28,25 @@ cmd_make-caps = echo "static const char *const capability_names[] = {" > $@ ;\ # [RLIMIT_STACK] = "stack", # # and build a second integer table (with the second sed cmd), that maps -# RLIMIT defines to the order defined in asm-generic/resource.h This is +# RLIMIT defines to the order defined in asm-generic/resource.h Thi is # required by policy load to map policy ordering of RLIMITs to internal # ordering for architectures that redefine an RLIMIT. # Transforms lines from # #define RLIMIT_STACK 3 /* max stack size */ # to # RLIMIT_STACK, -# -# and build the securityfs entries for the mapping. -# Transforms lines from -# #define RLIMIT_FSIZE 1 /* Maximum filesize */ -# #define RLIMIT_STACK 3 /* max stack size */ -# to -# #define AA_FS_RLIMIT_MASK "fsize stack" quiet_cmd_make-rlim = GEN $@ -cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ - > $@ ;\ +cmd_make-rlim = echo "static const char *rlim_names[] = {" > $@ ;\ sed $< >> $@ -r -n \ -e 's/^\# ?define[ \t]+(RLIMIT_([A-Z0-9_]+)).*/[\1] = "\L\2",/p';\ echo "};" >> $@ ;\ - echo "static const int rlim_map[RLIM_NLIMITS] = {" >> $@ ;\ + echo "static const int rlim_map[] = {" >> $@ ;\ sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\ - echo "};" >> $@ ; \ - echo -n '\#define AA_FS_RLIMIT_MASK "' >> $@ ;\ - sed -r -n 's/^\# ?define[ \t]+RLIMIT_([A-Z0-9_]+).*/\L\1/p' $< | \ - tr '\n' ' ' | sed -e 's/ $$/"\n/' >> $@ + echo "};" >> $@ $(obj)/capability.o : $(obj)/capability_names.h $(obj)/resource.o : $(obj)/rlim_names.h -$(obj)/capability_names.h : $(srctree)/include/linux/capability.h \ - $(src)/Makefile +$(obj)/capability_names.h : $(srctree)/include/linux/capability.h $(call cmd,make-caps) -$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \ - $(src)/Makefile +$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h $(call cmd,make-rlim) diff --git a/trunk/security/apparmor/apparmorfs.c b/trunk/security/apparmor/apparmorfs.c index 16c15ec6f670..e39df6d43779 100644 --- a/trunk/security/apparmor/apparmorfs.c +++ b/trunk/security/apparmor/apparmorfs.c @@ -18,14 +18,12 @@ #include #include #include -#include #include "include/apparmor.h" #include "include/apparmorfs.h" #include "include/audit.h" #include "include/context.h" #include "include/policy.h" -#include "include/resource.h" /** * aa_simple_write_to_buffer - common routine for getting policy from user @@ -144,166 +142,38 @@ static const struct file_operations aa_fs_profile_remove = { .llseek = default_llseek, }; -static int aa_fs_seq_show(struct seq_file *seq, void *v) -{ - struct aa_fs_entry *fs_file = seq->private; - - if (!fs_file) - return 0; - - switch (fs_file->v_type) { - case AA_FS_TYPE_BOOLEAN: - seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no"); - break; - case AA_FS_TYPE_STRING: - seq_printf(seq, "%s\n", fs_file->v.string); - break; - case AA_FS_TYPE_U64: - seq_printf(seq, "%#08lx\n", fs_file->v.u64); - break; - default: - /* Ignore unpritable entry types. */ - break; - } - - return 0; -} - -static int aa_fs_seq_open(struct inode *inode, struct file *file) -{ - return single_open(file, aa_fs_seq_show, inode->i_private); -} - -const struct file_operations aa_fs_seq_file_ops = { - .owner = THIS_MODULE, - .open = aa_fs_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - /** Base file system setup **/ -static struct aa_fs_entry aa_fs_entry_file[] = { - AA_FS_FILE_STRING("mask", "create read write exec append mmap_exec " \ - "link lock"), - { } -}; +static struct dentry *aa_fs_dentry __initdata; -static struct aa_fs_entry aa_fs_entry_domain[] = { - AA_FS_FILE_BOOLEAN("change_hat", 1), - AA_FS_FILE_BOOLEAN("change_hatv", 1), - AA_FS_FILE_BOOLEAN("change_onexec", 1), - AA_FS_FILE_BOOLEAN("change_profile", 1), - { } -}; - -static struct aa_fs_entry aa_fs_entry_features[] = { - AA_FS_DIR("domain", aa_fs_entry_domain), - AA_FS_DIR("file", aa_fs_entry_file), - AA_FS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), - AA_FS_DIR("rlimit", aa_fs_entry_rlimit), - { } -}; - -static struct aa_fs_entry aa_fs_entry_apparmor[] = { - AA_FS_FILE_FOPS(".load", 0640, &aa_fs_profile_load), - AA_FS_FILE_FOPS(".replace", 0640, &aa_fs_profile_replace), - AA_FS_FILE_FOPS(".remove", 0640, &aa_fs_profile_remove), - AA_FS_DIR("features", aa_fs_entry_features), - { } -}; - -static struct aa_fs_entry aa_fs_entry = - AA_FS_DIR("apparmor", aa_fs_entry_apparmor); - -/** - * aafs_create_file - create a file entry in the apparmor securityfs - * @fs_file: aa_fs_entry to build an entry for (NOT NULL) - * @parent: the parent dentry in the securityfs - * - * Use aafs_remove_file to remove entries created with this fn. - */ -static int __init aafs_create_file(struct aa_fs_entry *fs_file, - struct dentry *parent) +static void __init aafs_remove(const char *name) { - int error = 0; - - fs_file->dentry = securityfs_create_file(fs_file->name, - S_IFREG | fs_file->mode, - parent, fs_file, - fs_file->file_ops); - if (IS_ERR(fs_file->dentry)) { - error = PTR_ERR(fs_file->dentry); - fs_file->dentry = NULL; - } - return error; -} + struct dentry *dentry; -/** - * aafs_create_dir - recursively create a directory entry in the securityfs - * @fs_dir: aa_fs_entry (and all child entries) to build (NOT NULL) - * @parent: the parent dentry in the securityfs - * - * Use aafs_remove_dir to remove entries created with this fn. - */ -static int __init aafs_create_dir(struct aa_fs_entry *fs_dir, - struct dentry *parent) -{ - int error; - struct aa_fs_entry *fs_file; - - fs_dir->dentry = securityfs_create_dir(fs_dir->name, parent); - if (IS_ERR(fs_dir->dentry)) { - error = PTR_ERR(fs_dir->dentry); - fs_dir->dentry = NULL; - goto failed; - } - - for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) { - if (fs_file->v_type == AA_FS_TYPE_DIR) - error = aafs_create_dir(fs_file, fs_dir->dentry); - else - error = aafs_create_file(fs_file, fs_dir->dentry); - if (error) - goto failed; + dentry = lookup_one_len(name, aa_fs_dentry, strlen(name)); + if (!IS_ERR(dentry)) { + securityfs_remove(dentry); + dput(dentry); } - - return 0; - -failed: - return error; -} - -/** - * aafs_remove_file - drop a single file entry in the apparmor securityfs - * @fs_file: aa_fs_entry to detach from the securityfs (NOT NULL) - */ -static void __init aafs_remove_file(struct aa_fs_entry *fs_file) -{ - if (!fs_file->dentry) - return; - - securityfs_remove(fs_file->dentry); - fs_file->dentry = NULL; } /** - * aafs_remove_dir - recursively drop a directory entry from the securityfs - * @fs_dir: aa_fs_entry (and all child entries) to detach (NOT NULL) + * aafs_create - create an entry in the apparmor filesystem + * @name: name of the entry (NOT NULL) + * @mask: file permission mask of the file + * @fops: file operations for the file (NOT NULL) + * + * Used aafs_remove to remove entries created with this fn. */ -static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir) +static int __init aafs_create(const char *name, umode_t mask, + const struct file_operations *fops) { - struct aa_fs_entry *fs_file; + struct dentry *dentry; - for (fs_file = fs_dir->v.files; fs_file->name; ++fs_file) { - if (fs_file->v_type == AA_FS_TYPE_DIR) - aafs_remove_dir(fs_file); - else - aafs_remove_file(fs_file); - } + dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry, + NULL, fops); - aafs_remove_file(fs_dir); + return IS_ERR(dentry) ? PTR_ERR(dentry) : 0; } /** @@ -313,7 +183,14 @@ static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir) */ void __init aa_destroy_aafs(void) { - aafs_remove_dir(&aa_fs_entry); + if (aa_fs_dentry) { + aafs_remove(".remove"); + aafs_remove(".replace"); + aafs_remove(".load"); + + securityfs_remove(aa_fs_dentry); + aa_fs_dentry = NULL; + } } /** @@ -330,13 +207,25 @@ static int __init aa_create_aafs(void) if (!apparmor_initialized) return 0; - if (aa_fs_entry.dentry) { + if (aa_fs_dentry) { AA_ERROR("%s: AppArmor securityfs already exists\n", __func__); return -EEXIST; } - /* Populate fs tree. */ - error = aafs_create_dir(&aa_fs_entry, NULL); + aa_fs_dentry = securityfs_create_dir("apparmor", NULL); + if (IS_ERR(aa_fs_dentry)) { + error = PTR_ERR(aa_fs_dentry); + aa_fs_dentry = NULL; + goto error; + } + + error = aafs_create(".load", 0640, &aa_fs_profile_load); + if (error) + goto error; + error = aafs_create(".replace", 0640, &aa_fs_profile_replace); + if (error) + goto error; + error = aafs_create(".remove", 0640, &aa_fs_profile_remove); if (error) goto error; diff --git a/trunk/security/apparmor/audit.c b/trunk/security/apparmor/audit.c index 5ff67776a5ad..f3fafedd798a 100644 --- a/trunk/security/apparmor/audit.c +++ b/trunk/security/apparmor/audit.c @@ -19,7 +19,7 @@ #include "include/audit.h" #include "include/policy.h" -const char *const op_table[] = { +const char *op_table[] = { "null", "sysctl", @@ -73,7 +73,7 @@ const char *const op_table[] = { "profile_remove" }; -const char *const audit_mode_names[] = { +const char *audit_mode_names[] = { "normal", "quiet_denied", "quiet", @@ -81,7 +81,7 @@ const char *const audit_mode_names[] = { "all" }; -static const char *const aa_audit_type[] = { +static char *aa_audit_type[] = { "AUDIT", "ALLOWED", "DENIED", @@ -89,7 +89,6 @@ static const char *const aa_audit_type[] = { "STATUS", "ERROR", "KILLED" - "AUTO" }; /* diff --git a/trunk/security/apparmor/domain.c b/trunk/security/apparmor/domain.c index 7c69599a69e1..c1e18ba5bdc0 100644 --- a/trunk/security/apparmor/domain.c +++ b/trunk/security/apparmor/domain.c @@ -372,12 +372,13 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) state = profile->file.start; /* buffer freed below, name is pointer into buffer */ - error = aa_path_name(&bprm->file->f_path, profile->path_flags, &buffer, - &name, &info); + error = aa_get_name(&bprm->file->f_path, profile->path_flags, &buffer, + &name); if (error) { if (profile->flags & (PFLAG_IX_ON_NAME_ERROR | PFLAG_UNCONFINED)) error = 0; + info = "Exec failed name resolution"; name = bprm->filename; goto audit; } diff --git a/trunk/security/apparmor/file.c b/trunk/security/apparmor/file.c index 3022c0f4f0db..7312db741219 100644 --- a/trunk/security/apparmor/file.c +++ b/trunk/security/apparmor/file.c @@ -173,6 +173,8 @@ static u32 map_old_perms(u32 old) if (old & 0x40) /* AA_EXEC_MMAP */ new |= AA_EXEC_MMAP; + new |= AA_MAY_META_READ; + return new; } @@ -210,7 +212,6 @@ static struct file_perms compute_perms(struct aa_dfa *dfa, unsigned int state, perms.quiet = map_old_perms(dfa_other_quiet(dfa, state)); perms.xindex = dfa_other_xindex(dfa, state); } - perms.allow |= AA_MAY_META_READ; /* change_profile wasn't determined by ownership in old mapping */ if (ACCEPT_TABLE(dfa)[state] & 0x80000000) @@ -278,16 +279,22 @@ int aa_path_perm(int op, struct aa_profile *profile, struct path *path, int error; flags |= profile->path_flags | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 0); - error = aa_path_name(path, flags, &buffer, &name, &info); + error = aa_get_name(path, flags, &buffer, &name); if (error) { if (error == -ENOENT && is_deleted(path->dentry)) { /* Access to open files that are deleted are * give a pass (implicit delegation) */ error = 0; - info = NULL; perms.allow = request; - } + } else if (error == -ENOENT) + info = "Failed name lookup - deleted entry"; + else if (error == -ESTALE) + info = "Failed name lookup - disconnected path"; + else if (error == -ENAMETOOLONG) + info = "Failed name lookup - name too long"; + else + info = "Failed name lookup"; } else { aa_str_perms(profile->file.dfa, profile->file.start, name, cond, &perms); @@ -358,14 +365,12 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, lperms = nullperms; /* buffer freed below, lname is pointer in buffer */ - error = aa_path_name(&link, profile->path_flags, &buffer, &lname, - &info); + error = aa_get_name(&link, profile->path_flags, &buffer, &lname); if (error) goto audit; /* buffer2 freed below, tname is pointer in buffer2 */ - error = aa_path_name(&target, profile->path_flags, &buffer2, &tname, - &info); + error = aa_get_name(&target, profile->path_flags, &buffer2, &tname); if (error) goto audit; diff --git a/trunk/security/apparmor/include/apparmor.h b/trunk/security/apparmor/include/apparmor.h index 40aedd9f73ea..df3649560818 100644 --- a/trunk/security/apparmor/include/apparmor.h +++ b/trunk/security/apparmor/include/apparmor.h @@ -19,19 +19,6 @@ #include "match.h" -/* - * Class of mediation types in the AppArmor policy db - */ -#define AA_CLASS_ENTRY 0 -#define AA_CLASS_UNKNOWN 1 -#define AA_CLASS_FILE 2 -#define AA_CLASS_CAP 3 -#define AA_CLASS_NET 4 -#define AA_CLASS_RLIMITS 5 -#define AA_CLASS_DOMAIN 6 - -#define AA_CLASS_LAST AA_CLASS_DOMAIN - /* Control parameters settable through module/boot flags */ extern enum audit_mode aa_g_audit; extern bool aa_g_audit_header; @@ -94,7 +81,7 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, unsigned int start) { /* the null transition only needs the string's null terminator byte */ - return aa_dfa_next(dfa, start, 0); + return aa_dfa_match_len(dfa, start, "", 1); } static inline bool mediated_filesystem(struct inode *inode) diff --git a/trunk/security/apparmor/include/apparmorfs.h b/trunk/security/apparmor/include/apparmorfs.h index 7ea4769fab3f..cb1e93a114d7 100644 --- a/trunk/security/apparmor/include/apparmorfs.h +++ b/trunk/security/apparmor/include/apparmorfs.h @@ -15,50 +15,6 @@ #ifndef __AA_APPARMORFS_H #define __AA_APPARMORFS_H -enum aa_fs_type { - AA_FS_TYPE_BOOLEAN, - AA_FS_TYPE_STRING, - AA_FS_TYPE_U64, - AA_FS_TYPE_FOPS, - AA_FS_TYPE_DIR, -}; - -struct aa_fs_entry; - -struct aa_fs_entry { - const char *name; - struct dentry *dentry; - umode_t mode; - enum aa_fs_type v_type; - union { - bool boolean; - char *string; - unsigned long u64; - struct aa_fs_entry *files; - } v; - const struct file_operations *file_ops; -}; - -extern const struct file_operations aa_fs_seq_file_ops; - -#define AA_FS_FILE_BOOLEAN(_name, _value) \ - { .name = (_name), .mode = 0444, \ - .v_type = AA_FS_TYPE_BOOLEAN, .v.boolean = (_value), \ - .file_ops = &aa_fs_seq_file_ops } -#define AA_FS_FILE_STRING(_name, _value) \ - { .name = (_name), .mode = 0444, \ - .v_type = AA_FS_TYPE_STRING, .v.string = (_value), \ - .file_ops = &aa_fs_seq_file_ops } -#define AA_FS_FILE_U64(_name, _value) \ - { .name = (_name), .mode = 0444, \ - .v_type = AA_FS_TYPE_U64, .v.u64 = (_value), \ - .file_ops = &aa_fs_seq_file_ops } -#define AA_FS_FILE_FOPS(_name, _mode, _fops) \ - { .name = (_name), .v_type = AA_FS_TYPE_FOPS, \ - .mode = (_mode), .file_ops = (_fops) } -#define AA_FS_DIR(_name, _value) \ - { .name = (_name), .v_type = AA_FS_TYPE_DIR, .v.files = (_value) } - extern void __init aa_destroy_aafs(void); #endif /* __AA_APPARMORFS_H */ diff --git a/trunk/security/apparmor/include/audit.h b/trunk/security/apparmor/include/audit.h index 4ba78c203af1..1951786d32e9 100644 --- a/trunk/security/apparmor/include/audit.h +++ b/trunk/security/apparmor/include/audit.h @@ -25,9 +25,11 @@ struct aa_profile; -extern const char *const audit_mode_names[]; +extern const char *audit_mode_names[]; #define AUDIT_MAX_INDEX 5 +#define AUDIT_APPARMOR_AUTO 0 /* auto choose audit message type */ + enum audit_mode { AUDIT_NORMAL, /* follow normal auditing of accesses */ AUDIT_QUIET_DENIED, /* quiet all denied access messages */ @@ -43,11 +45,10 @@ enum audit_type { AUDIT_APPARMOR_HINT, AUDIT_APPARMOR_STATUS, AUDIT_APPARMOR_ERROR, - AUDIT_APPARMOR_KILL, - AUDIT_APPARMOR_AUTO + AUDIT_APPARMOR_KILL }; -extern const char *const op_table[]; +extern const char *op_table[]; enum aa_ops { OP_NULL, diff --git a/trunk/security/apparmor/include/file.h b/trunk/security/apparmor/include/file.h index f98fd4701d80..ab8c6d87f758 100644 --- a/trunk/security/apparmor/include/file.h +++ b/trunk/security/apparmor/include/file.h @@ -117,7 +117,7 @@ static inline u16 dfa_map_xindex(u16 mask) index |= AA_X_NAME; } else if (old_index == 3) { index |= AA_X_NAME | AA_X_CHILD; - } else if (old_index) { + } else { index |= AA_X_TABLE; index |= old_index - 4; } diff --git a/trunk/security/apparmor/include/match.h b/trunk/security/apparmor/include/match.h index 775843e7f984..a4a863997bd5 100644 --- a/trunk/security/apparmor/include/match.h +++ b/trunk/security/apparmor/include/match.h @@ -116,9 +116,6 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, const char *str, int len); unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, const char *str); -unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, - const char c); - void aa_dfa_free_kref(struct kref *kref); /** diff --git a/trunk/security/apparmor/include/path.h b/trunk/security/apparmor/include/path.h index 286ac75dc88b..27b327a7fae5 100644 --- a/trunk/security/apparmor/include/path.h +++ b/trunk/security/apparmor/include/path.h @@ -26,7 +26,6 @@ enum path_flags { PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */ }; -int aa_path_name(struct path *path, int flags, char **buffer, - const char **name, const char **info); +int aa_get_name(struct path *path, int flags, char **buffer, const char **name); #endif /* __AA_PATH_H */ diff --git a/trunk/security/apparmor/include/policy.h b/trunk/security/apparmor/include/policy.h index bda4569fdd83..aeda5cf56904 100644 --- a/trunk/security/apparmor/include/policy.h +++ b/trunk/security/apparmor/include/policy.h @@ -29,7 +29,7 @@ #include "file.h" #include "resource.h" -extern const char *const profile_mode_names[]; +extern const char *profile_mode_names[]; #define APPARMOR_NAMES_MAX_INDEX 3 #define COMPLAIN_MODE(_profile) \ @@ -129,17 +129,6 @@ struct aa_namespace { struct list_head sub_ns; }; -/* struct aa_policydb - match engine for a policy - * dfa: dfa pattern match - * start: set of start states for the different classes of data - */ -struct aa_policydb { - /* Generic policy DFA specific rule types will be subsections of it */ - struct aa_dfa *dfa; - unsigned int start[AA_CLASS_LAST + 1]; - -}; - /* struct aa_profile - basic confinement data * @base - base components of the profile (name, refcount, lists, lock ...) * @parent: parent of profile @@ -154,7 +143,6 @@ struct aa_policydb { * @flags: flags controlling profile behavior * @path_flags: flags controlling path generation behavior * @size: the memory consumed by this profiles rules - * @policy: general match rules governing policy * @file: The set of rules governing basic file access and domain transitions * @caps: capabilities for the profile * @rlimits: rlimits for the profile @@ -191,7 +179,6 @@ struct aa_profile { u32 path_flags; int size; - struct aa_policydb policy; struct aa_file_rules file; struct aa_caps caps; struct aa_rlimit rlimits; diff --git a/trunk/security/apparmor/include/resource.h b/trunk/security/apparmor/include/resource.h index d3f4cf027957..02baec732bb5 100644 --- a/trunk/security/apparmor/include/resource.h +++ b/trunk/security/apparmor/include/resource.h @@ -18,8 +18,6 @@ #include #include -#include "apparmorfs.h" - struct aa_profile; /* struct aa_rlimit - rlimit settings for the profile @@ -34,8 +32,6 @@ struct aa_rlimit { struct rlimit limits[RLIM_NLIMITS]; }; -extern struct aa_fs_entry aa_fs_entry_rlimit[]; - int aa_map_resource(int resource); int aa_task_setrlimit(struct aa_profile *profile, struct task_struct *, unsigned int resource, struct rlimit *new_rlim); diff --git a/trunk/security/apparmor/match.c b/trunk/security/apparmor/match.c index 90971a8c3789..94de6b4907c8 100644 --- a/trunk/security/apparmor/match.c +++ b/trunk/security/apparmor/match.c @@ -335,12 +335,12 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, } /** - * aa_dfa_match - traverse @dfa to find state @str stops at + * aa_dfa_next_state - traverse @dfa to find state @str stops at * @dfa: the dfa to match @str against (NOT NULL) * @start: the state of the dfa to start matching in * @str: the null terminated string of bytes to match against the dfa (NOT NULL) * - * aa_dfa_match will match @str against the dfa and return the state it + * aa_dfa_next_state will match @str against the dfa and return the state it * finished matching in. The final state can be used to look up the accepting * label, or as the start state of a continuing match. * @@ -349,79 +349,5 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, unsigned int aa_dfa_match(struct aa_dfa *dfa, unsigned int start, const char *str) { - u16 *def = DEFAULT_TABLE(dfa); - u32 *base = BASE_TABLE(dfa); - u16 *next = NEXT_TABLE(dfa); - u16 *check = CHECK_TABLE(dfa); - unsigned int state = start, pos; - - if (state == 0) - return 0; - - /* current state is , matching character *str */ - if (dfa->tables[YYTD_ID_EC]) { - /* Equivalence class table defined */ - u8 *equiv = EQUIV_TABLE(dfa); - /* default is direct to next state */ - while (*str) { - pos = base[state] + equiv[(u8) *str++]; - if (check[pos] == state) - state = next[pos]; - else - state = def[state]; - } - } else { - /* default is direct to next state */ - while (*str) { - pos = base[state] + (u8) *str++; - if (check[pos] == state) - state = next[pos]; - else - state = def[state]; - } - } - - return state; -} - -/** - * aa_dfa_next - step one character to the next state in the dfa - * @dfa: the dfa to tranverse (NOT NULL) - * @state: the state to start in - * @c: the input character to transition on - * - * aa_dfa_match will step through the dfa by one input character @c - * - * Returns: state reach after input @c - */ -unsigned int aa_dfa_next(struct aa_dfa *dfa, unsigned int state, - const char c) -{ - u16 *def = DEFAULT_TABLE(dfa); - u32 *base = BASE_TABLE(dfa); - u16 *next = NEXT_TABLE(dfa); - u16 *check = CHECK_TABLE(dfa); - unsigned int pos; - - /* current state is , matching character *str */ - if (dfa->tables[YYTD_ID_EC]) { - /* Equivalence class table defined */ - u8 *equiv = EQUIV_TABLE(dfa); - /* default is direct to next state */ - - pos = base[state] + equiv[(u8) c]; - if (check[pos] == state) - state = next[pos]; - else - state = def[state]; - } else { - /* default is direct to next state */ - pos = base[state] + (u8) c; - if (check[pos] == state) - state = next[pos]; - else - state = def[state]; - } - - return state; + return aa_dfa_match_len(dfa, start, str, strlen(str)); } diff --git a/trunk/security/apparmor/path.c b/trunk/security/apparmor/path.c index 2daeea4f9266..9d070a7c3ffc 100644 --- a/trunk/security/apparmor/path.c +++ b/trunk/security/apparmor/path.c @@ -83,29 +83,31 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, struct path root; get_fs_root(current->fs, &root); res = __d_path(path, &root, buf, buflen); + if (res && !IS_ERR(res)) { + /* everything's fine */ + *name = res; + path_put(&root); + goto ok; + } path_put(&root); - } else { - res = d_absolute_path(path, buf, buflen); - if (!our_mnt(path->mnt)) - connected = 0; + connected = 0; } + res = d_absolute_path(path, buf, buflen); + + *name = res; /* handle error conditions - and still allow a partial path to * be returned. */ - if (!res || IS_ERR(res)) { - connected = 0; - res = dentry_path_raw(path->dentry, buf, buflen); - if (IS_ERR(res)) { - error = PTR_ERR(res); - *name = buf; - goto out; - }; - } else if (!our_mnt(path->mnt)) + if (IS_ERR(res)) { + error = PTR_ERR(res); + *name = buf; + goto out; + } + if (!our_mnt(path->mnt)) connected = 0; - *name = res; - +ok: /* Handle two cases: * 1. A deleted dentry && profile is not allowing mediation of deleted * 2. On some filesystems, newly allocated dentries appear to the @@ -136,7 +138,7 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, /* disconnected path, don't return pathname starting * with '/' */ - error = -EACCES; + error = -ESTALE; if (*res == '/') *name = res + 1; } @@ -157,7 +159,7 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, * Returns: %0 else error on failure */ static int get_name_to_buffer(struct path *path, int flags, char *buffer, - int size, char **name, const char **info) + int size, char **name) { int adjust = (flags & PATH_IS_DIR) ? 1 : 0; int error = d_namespace_path(path, buffer, size - adjust, name, flags); @@ -169,27 +171,15 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer, */ strcpy(&buffer[size - 2], "/"); - if (info && error) { - if (error == -ENOENT) - *info = "Failed name lookup - deleted entry"; - else if (error == -ESTALE) - *info = "Failed name lookup - disconnected path"; - else if (error == -ENAMETOOLONG) - *info = "Failed name lookup - name too long"; - else - *info = "Failed name lookup"; - } - return error; } /** - * aa_path_name - compute the pathname of a file + * aa_get_name - compute the pathname of a file * @path: path the file (NOT NULL) * @flags: flags controlling path name generation * @buffer: buffer that aa_get_name() allocated (NOT NULL) * @name: Returns - the generated path name if !error (NOT NULL) - * @info: Returns - information on why the path lookup failed (MAYBE NULL) * * @name is a pointer to the beginning of the pathname (which usually differs * from the beginning of the buffer), or NULL. If there is an error @name @@ -202,8 +192,7 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer, * * Returns: %0 else error code if could retrieve name */ -int aa_path_name(struct path *path, int flags, char **buffer, const char **name, - const char **info) +int aa_get_name(struct path *path, int flags, char **buffer, const char **name) { char *buf, *str = NULL; int size = 256; @@ -217,7 +206,7 @@ int aa_path_name(struct path *path, int flags, char **buffer, const char **name, if (!buf) return -ENOMEM; - error = get_name_to_buffer(path, flags, buf, size, &str, info); + error = get_name_to_buffer(path, flags, buf, size, &str); if (error != -ENAMETOOLONG) break; @@ -225,7 +214,6 @@ int aa_path_name(struct path *path, int flags, char **buffer, const char **name, size <<= 1; if (size > aa_g_path_max) return -ENAMETOOLONG; - *info = NULL; } *buffer = buf; *name = str; diff --git a/trunk/security/apparmor/policy.c b/trunk/security/apparmor/policy.c index 906414383022..4f0eadee78b8 100644 --- a/trunk/security/apparmor/policy.c +++ b/trunk/security/apparmor/policy.c @@ -93,7 +93,7 @@ /* root profile namespace */ struct aa_namespace *root_ns; -const char *const profile_mode_names[] = { +const char *profile_mode_names[] = { "enforce", "complain", "kill", @@ -749,7 +749,6 @@ static void free_profile(struct aa_profile *profile) aa_free_sid(profile->sid); aa_put_dfa(profile->xmatch); - aa_put_dfa(profile->policy.dfa); aa_put_profile(profile->replacedby); diff --git a/trunk/security/apparmor/policy_unpack.c b/trunk/security/apparmor/policy_unpack.c index 25fd51edc8da..741dd13e089b 100644 --- a/trunk/security/apparmor/policy_unpack.c +++ b/trunk/security/apparmor/policy_unpack.c @@ -84,7 +84,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) * @new: profile if it has been allocated (MAYBE NULL) * @name: name of the profile being manipulated (MAYBE NULL) * @info: any extra info about the failure (MAYBE NULL) - * @e: buffer position info + * @e: buffer position info (NOT NULL) * @error: error code * * Returns: %0 or error @@ -95,8 +95,7 @@ static int audit_iface(struct aa_profile *new, const char *name, struct aa_profile *profile = __aa_current_profile(); struct common_audit_data sa; COMMON_AUDIT_DATA_INIT(&sa, NONE); - if (e) - sa.aad.iface.pos = e->pos - e->start; + sa.aad.iface.pos = e->pos - e->start; sa.aad.iface.target = new; sa.aad.name = name; sa.aad.info = info; @@ -469,7 +468,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) { struct aa_profile *profile = NULL; const char *name = NULL; - int i, error = -EPROTO; + int error = -EPROTO; kernel_cap_t tmpcap; u32 tmp; @@ -555,35 +554,11 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) goto fail; if (!unpack_u32(e, &(profile->caps.extended.cap[1]), NULL)) goto fail; - if (!unpack_nameX(e, AA_STRUCTEND, NULL)) - goto fail; } if (!unpack_rlimits(e, profile)) goto fail; - if (unpack_nameX(e, AA_STRUCT, "policydb")) { - /* generic policy dfa - optional and may be NULL */ - profile->policy.dfa = unpack_dfa(e); - if (IS_ERR(profile->policy.dfa)) { - error = PTR_ERR(profile->policy.dfa); - profile->policy.dfa = NULL; - goto fail; - } - if (!unpack_u32(e, &profile->policy.start[0], "start")) - /* default start state */ - profile->policy.start[0] = DFA_START; - /* setup class index */ - for (i = AA_CLASS_FILE; i <= AA_CLASS_LAST; i++) { - profile->policy.start[i] = - aa_dfa_next(profile->policy.dfa, - profile->policy.start[0], - i); - } - if (!unpack_nameX(e, AA_STRUCTEND, NULL)) - goto fail; - } - /* get file rules */ profile->file.dfa = unpack_dfa(e); if (IS_ERR(profile->file.dfa)) { diff --git a/trunk/security/apparmor/resource.c b/trunk/security/apparmor/resource.c index 72c25a4f2cfd..a4136c10b1c6 100644 --- a/trunk/security/apparmor/resource.c +++ b/trunk/security/apparmor/resource.c @@ -23,11 +23,6 @@ */ #include "rlim_names.h" -struct aa_fs_entry aa_fs_entry_rlimit[] = { - AA_FS_FILE_STRING("mask", AA_FS_RLIMIT_MASK), - { } -}; - /* audit callback for resource specific fields */ static void audit_cb(struct audit_buffer *ab, void *va) { diff --git a/trunk/security/capability.c b/trunk/security/capability.c index 5bb21b1c448c..2f680eb02b59 100644 --- a/trunk/security/capability.c +++ b/trunk/security/capability.c @@ -358,10 +358,6 @@ static int cap_task_create(unsigned long clone_flags) return 0; } -static void cap_task_free(struct task_struct *task) -{ -} - static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp) { return 0; @@ -958,7 +954,6 @@ void __init security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, file_receive); set_to_cap_if_null(ops, dentry_open); set_to_cap_if_null(ops, task_create); - set_to_cap_if_null(ops, task_free); set_to_cap_if_null(ops, cred_alloc_blank); set_to_cap_if_null(ops, cred_free); set_to_cap_if_null(ops, cred_prepare); diff --git a/trunk/security/commoncap.c b/trunk/security/commoncap.c index 0cf4b53480a7..7ce191ea29a0 100644 --- a/trunk/security/commoncap.c +++ b/trunk/security/commoncap.c @@ -28,7 +28,6 @@ #include #include #include -#include /* * If a non-root user executes a setuid-root binary in diff --git a/trunk/security/integrity/ima/Kconfig b/trunk/security/integrity/ima/Kconfig index 35664fe6daa1..4f554f20dc97 100644 --- a/trunk/security/integrity/ima/Kconfig +++ b/trunk/security/integrity/ima/Kconfig @@ -9,8 +9,8 @@ config IMA select CRYPTO_HMAC select CRYPTO_MD5 select CRYPTO_SHA1 - select TCG_TPM if HAS_IOMEM && !UML - select TCG_TIS if TCG_TPM && X86 + select TCG_TPM if !S390 && !UML + select TCG_TIS if TCG_TPM help The Trusted Computing Group(TCG) runtime Integrity Measurement Architecture(IMA) maintains a list of hash diff --git a/trunk/security/integrity/ima/ima_audit.c b/trunk/security/integrity/ima/ima_audit.c index 21e96bf188df..2ad942fb1e23 100644 --- a/trunk/security/integrity/ima/ima_audit.c +++ b/trunk/security/integrity/ima/ima_audit.c @@ -61,6 +61,6 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode, audit_log_untrustedstring(ab, inode->i_sb->s_id); audit_log_format(ab, " ino=%lu", inode->i_ino); } - audit_log_format(ab, " res=%d", !result); + audit_log_format(ab, " res=%d", !result ? 0 : 1); audit_log_end(ab); } diff --git a/trunk/security/integrity/ima/ima_policy.c b/trunk/security/integrity/ima/ima_policy.c index d8edff209bf3..d45061d02fee 100644 --- a/trunk/security/integrity/ima/ima_policy.c +++ b/trunk/security/integrity/ima/ima_policy.c @@ -62,7 +62,6 @@ static struct ima_measure_rule_entry default_rules[] = { {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, - {.action = DONT_MEASURE,.fsmagic = RAMFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC,.flags = IMA_FSMAGIC}, {.action = DONT_MEASURE,.fsmagic = SELINUX_MAGIC,.flags = IMA_FSMAGIC}, {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, @@ -418,7 +417,7 @@ static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) if (!result && (entry->action == UNKNOWN)) result = -EINVAL; - audit_log_format(ab, "res=%d", !result); + audit_log_format(ab, "res=%d", !!result); audit_log_end(ab); return result; } diff --git a/trunk/security/keys/keyctl.c b/trunk/security/keys/keyctl.c index 6523599e9ac0..0b3f5d72af1c 100644 --- a/trunk/security/keys/keyctl.c +++ b/trunk/security/keys/keyctl.c @@ -388,24 +388,11 @@ long keyctl_keyring_clear(key_serial_t ringid) keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); - - /* Root is permitted to invalidate certain special keyrings */ - if (capable(CAP_SYS_ADMIN)) { - keyring_ref = lookup_user_key(ringid, 0, 0); - if (IS_ERR(keyring_ref)) - goto error; - if (test_bit(KEY_FLAG_ROOT_CAN_CLEAR, - &key_ref_to_ptr(keyring_ref)->flags)) - goto clear; - goto error_put; - } - goto error; } -clear: ret = keyring_clear(key_ref_to_ptr(keyring_ref)); -error_put: + key_ref_put(keyring_ref); error: return ret; diff --git a/trunk/security/keys/process_keys.c b/trunk/security/keys/process_keys.c index be7ecb2018dd..1068cb1939b3 100644 --- a/trunk/security/keys/process_keys.c +++ b/trunk/security/keys/process_keys.c @@ -657,8 +657,7 @@ key_ref_t lookup_user_key(key_serial_t id, unsigned long lflags, goto error; down_read(&cred->request_key_auth->sem); - if (test_bit(KEY_FLAG_REVOKED, - &cred->request_key_auth->flags)) { + if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) { key_ref = ERR_PTR(-EKEYREVOKED); key = NULL; } else { diff --git a/trunk/security/lsm_audit.c b/trunk/security/lsm_audit.c index 8b8f0902f6e5..293b8c45b1d1 100644 --- a/trunk/security/lsm_audit.c +++ b/trunk/security/lsm_audit.c @@ -313,8 +313,12 @@ static void dump_common_audit_data(struct audit_buffer *ab, } case AF_UNIX: u = unix_sk(sk); - if (u->path.dentry) { - audit_log_d_path(ab, " path=", &u->path); + if (u->dentry) { + struct path path = { + .dentry = u->dentry, + .mnt = u->mnt + }; + audit_log_d_path(ab, " path=", &path); break; } if (!u->addr) diff --git a/trunk/security/security.c b/trunk/security/security.c index bf619ffc9a4d..d7542493454d 100644 --- a/trunk/security/security.c +++ b/trunk/security/security.c @@ -19,8 +19,6 @@ #include #include #include -#include -#include #define MAX_LSM_EVM_XATTR 2 @@ -189,11 +187,25 @@ int security_settime(const struct timespec *ts, const struct timezone *tz) return security_ops->settime(ts, tz); } +int security_vm_enough_memory(long pages) +{ + WARN_ON(current->mm == NULL); + return security_ops->vm_enough_memory(current->mm, pages); +} + int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) { + WARN_ON(mm == NULL); return security_ops->vm_enough_memory(mm, pages); } +int security_vm_enough_memory_kern(long pages) +{ + /* If current->mm is a kernel thread then we will pass NULL, + for this specific case that is fine */ + return security_ops->vm_enough_memory(current->mm, pages); +} + int security_bprm_set_creds(struct linux_binprm *bprm) { return security_ops->bprm_set_creds(bprm); @@ -717,11 +729,6 @@ int security_task_create(unsigned long clone_flags) return security_ops->task_create(clone_flags); } -void security_task_free(struct task_struct *task) -{ - security_ops->task_free(task); -} - int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) { return security_ops->cred_alloc_blank(cred, gfp); diff --git a/trunk/security/selinux/hooks.c b/trunk/security/selinux/hooks.c index 304929909375..6a3683e28426 100644 --- a/trunk/security/selinux/hooks.c +++ b/trunk/security/selinux/hooks.c @@ -81,8 +81,6 @@ #include #include #include -#include -#include #include "avc.h" #include "objsec.h" diff --git a/trunk/security/smack/smack_lsm.c b/trunk/security/smack/smack_lsm.c index cd667b4089a5..e8af5b0ba80f 100644 --- a/trunk/security/smack/smack_lsm.c +++ b/trunk/security/smack/smack_lsm.c @@ -36,9 +36,6 @@ #include #include #include -#include -#include -#include #include "smack.h" #define task_security(task) (task_cred_xxx((task), security)) diff --git a/trunk/security/tomoyo/audit.c b/trunk/security/tomoyo/audit.c index 7ef9fa3e37e0..5ca47ea3049f 100644 --- a/trunk/security/tomoyo/audit.c +++ b/trunk/security/tomoyo/audit.c @@ -446,11 +446,11 @@ void tomoyo_read_log(struct tomoyo_io_buffer *head) * tomoyo_poll_log - Wait for an audit log. * * @file: Pointer to "struct file". - * @wait: Pointer to "poll_table". Maybe NULL. + * @wait: Pointer to "poll_table". * * Returns POLLIN | POLLRDNORM when ready to read an audit log. */ -unsigned int tomoyo_poll_log(struct file *file, poll_table *wait) +int tomoyo_poll_log(struct file *file, poll_table *wait) { if (tomoyo_log_count) return POLLIN | POLLRDNORM; diff --git a/trunk/security/tomoyo/common.c b/trunk/security/tomoyo/common.c index 8656b16eef7b..c47d3ce6c733 100644 --- a/trunk/security/tomoyo/common.c +++ b/trunk/security/tomoyo/common.c @@ -1069,7 +1069,7 @@ static int tomoyo_write_task(struct tomoyo_acl_param *param) * * @domainname: The name of domain. * - * Returns 0 on success, negative value otherwise. + * Returns 0. * * Caller holds tomoyo_read_lock(). */ @@ -1081,7 +1081,7 @@ static int tomoyo_delete_domain(char *domainname) name.name = domainname; tomoyo_fill_path_info(&name); if (mutex_lock_interruptible(&tomoyo_policy_lock)) - return -EINTR; + return 0; /* Is there an active domain? */ list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { /* Never delete tomoyo_kernel_domain */ @@ -1164,16 +1164,15 @@ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) bool is_select = !is_delete && tomoyo_str_starts(&data, "select "); unsigned int profile; if (*data == '<') { - int ret = 0; domain = NULL; if (is_delete) - ret = tomoyo_delete_domain(data); + tomoyo_delete_domain(data); else if (is_select) domain = tomoyo_find_domain(data); else domain = tomoyo_assign_domain(data, false); head->w.domain = domain; - return ret; + return 0; } if (!domain) return -EINVAL; @@ -2112,7 +2111,7 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid struct tomoyo_domain_info *domain = NULL; spin_lock(&tomoyo_query_list_lock); list_for_each_entry(ptr, &tomoyo_query_list, list) { - if (ptr->serial != serial) + if (ptr->serial != serial || ptr->answer) continue; domain = ptr->domain; break; @@ -2131,13 +2130,28 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid * * Waits for access requests which violated policy in enforcing mode. */ -static unsigned int tomoyo_poll_query(struct file *file, poll_table *wait) +static int tomoyo_poll_query(struct file *file, poll_table *wait) { - if (!list_empty(&tomoyo_query_list)) - return POLLIN | POLLRDNORM; - poll_wait(file, &tomoyo_query_wait, wait); - if (!list_empty(&tomoyo_query_list)) - return POLLIN | POLLRDNORM; + struct list_head *tmp; + bool found = false; + u8 i; + for (i = 0; i < 2; i++) { + spin_lock(&tomoyo_query_list_lock); + list_for_each(tmp, &tomoyo_query_list) { + struct tomoyo_query *ptr = + list_entry(tmp, typeof(*ptr), list); + if (ptr->answer) + continue; + found = true; + break; + } + spin_unlock(&tomoyo_query_list_lock); + if (found) + return POLLIN | POLLRDNORM; + if (i) + break; + poll_wait(file, &tomoyo_query_wait, wait); + } return 0; } @@ -2161,6 +2175,8 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) spin_lock(&tomoyo_query_list_lock); list_for_each(tmp, &tomoyo_query_list) { struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); + if (ptr->answer) + continue; if (pos++ != head->r.query_index) continue; len = ptr->query_len; @@ -2178,6 +2194,8 @@ static void tomoyo_read_query(struct tomoyo_io_buffer *head) spin_lock(&tomoyo_query_list_lock); list_for_each(tmp, &tomoyo_query_list) { struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); + if (ptr->answer) + continue; if (pos++ != head->r.query_index) continue; /* @@ -2225,10 +2243,8 @@ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) struct tomoyo_query *ptr = list_entry(tmp, typeof(*ptr), list); if (ptr->serial != serial) continue; - ptr->answer = answer; - /* Remove from tomoyo_query_list. */ - if (ptr->answer) - list_del_init(&ptr->list); + if (!ptr->answer) + ptr->answer = answer; break; } spin_unlock(&tomoyo_query_list_lock); @@ -2461,17 +2477,18 @@ int tomoyo_open_control(const u8 type, struct file *file) * tomoyo_poll_control - poll() for /sys/kernel/security/tomoyo/ interface. * * @file: Pointer to "struct file". - * @wait: Pointer to "poll_table". Maybe NULL. + * @wait: Pointer to "poll_table". * - * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write, - * POLLOUT | POLLWRNORM otherwise. + * Waits for read readiness. + * /sys/kernel/security/tomoyo/query is handled by /usr/sbin/tomoyo-queryd and + * /sys/kernel/security/tomoyo/audit is handled by /usr/sbin/tomoyo-auditd. */ -unsigned int tomoyo_poll_control(struct file *file, poll_table *wait) +int tomoyo_poll_control(struct file *file, poll_table *wait) { struct tomoyo_io_buffer *head = file->private_data; - if (head->poll) - return head->poll(file, wait) | POLLOUT | POLLWRNORM; - return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; + if (!head->poll) + return -ENOSYS; + return head->poll(file, wait); } /** diff --git a/trunk/security/tomoyo/common.h b/trunk/security/tomoyo/common.h index 30fd98369700..9512222d5581 100644 --- a/trunk/security/tomoyo/common.h +++ b/trunk/security/tomoyo/common.h @@ -788,7 +788,7 @@ struct tomoyo_acl_param { struct tomoyo_io_buffer { void (*read) (struct tomoyo_io_buffer *); int (*write) (struct tomoyo_io_buffer *); - unsigned int (*poll) (struct file *file, poll_table *wait); + int (*poll) (struct file *file, poll_table *wait); /* Exclusive lock for this structure. */ struct mutex io_sem; char __user *read_user_buf; @@ -981,8 +981,8 @@ int tomoyo_path_number_perm(const u8 operation, struct path *path, unsigned long number); int tomoyo_path_perm(const u8 operation, struct path *path, const char *target); -unsigned int tomoyo_poll_control(struct file *file, poll_table *wait); -unsigned int tomoyo_poll_log(struct file *file, poll_table *wait); +int tomoyo_poll_control(struct file *file, poll_table *wait); +int tomoyo_poll_log(struct file *file, poll_table *wait); int tomoyo_socket_bind_permission(struct socket *sock, struct sockaddr *addr, int addr_len); int tomoyo_socket_connect_permission(struct socket *sock, diff --git a/trunk/security/tomoyo/mount.c b/trunk/security/tomoyo/mount.c index fe00cdfd0267..bee09d062057 100644 --- a/trunk/security/tomoyo/mount.c +++ b/trunk/security/tomoyo/mount.c @@ -199,32 +199,30 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, if (flags & MS_REMOUNT) { type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]; flags &= ~MS_REMOUNT; - } else if (flags & MS_BIND) { + } + if (flags & MS_MOVE) { + type = tomoyo_mounts[TOMOYO_MOUNT_MOVE]; + flags &= ~MS_MOVE; + } + if (flags & MS_BIND) { type = tomoyo_mounts[TOMOYO_MOUNT_BIND]; flags &= ~MS_BIND; - } else if (flags & MS_SHARED) { - if (flags & (MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) - return -EINVAL; - type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; - flags &= ~MS_SHARED; - } else if (flags & MS_PRIVATE) { - if (flags & (MS_SHARED | MS_SLAVE | MS_UNBINDABLE)) - return -EINVAL; + } + if (flags & MS_UNBINDABLE) { + type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; + flags &= ~MS_UNBINDABLE; + } + if (flags & MS_PRIVATE) { type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE]; flags &= ~MS_PRIVATE; - } else if (flags & MS_SLAVE) { - if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE)) - return -EINVAL; + } + if (flags & MS_SLAVE) { type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE]; flags &= ~MS_SLAVE; - } else if (flags & MS_UNBINDABLE) { - if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE)) - return -EINVAL; - type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; - flags &= ~MS_UNBINDABLE; - } else if (flags & MS_MOVE) { - type = tomoyo_mounts[TOMOYO_MOUNT_MOVE]; - flags &= ~MS_MOVE; + } + if (flags & MS_SHARED) { + type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; + flags &= ~MS_SHARED; } if (!type) type = ""; diff --git a/trunk/security/tomoyo/securityfs_if.c b/trunk/security/tomoyo/securityfs_if.c index 8592f2fc6ebb..482b2a5f48f0 100644 --- a/trunk/security/tomoyo/securityfs_if.c +++ b/trunk/security/tomoyo/securityfs_if.c @@ -157,10 +157,9 @@ static int tomoyo_release(struct inode *inode, struct file *file) * tomoyo_poll - poll() for /sys/kernel/security/tomoyo/ interface. * * @file: Pointer to "struct file". - * @wait: Pointer to "poll_table". Maybe NULL. + * @wait: Pointer to "poll_table". * - * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write, - * POLLOUT | POLLWRNORM otherwise. + * Returns 0 on success, negative value otherwise. */ static unsigned int tomoyo_poll(struct file *file, poll_table *wait) { diff --git a/trunk/security/yama/Kconfig b/trunk/security/yama/Kconfig deleted file mode 100644 index 51d6709d8bbd..000000000000 --- a/trunk/security/yama/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config SECURITY_YAMA - bool "Yama support" - depends on SECURITY - select SECURITYFS - select SECURITY_PATH - default n - help - This selects Yama, which extends DAC support with additional - system-wide security settings beyond regular Linux discretionary - access controls. Currently available is ptrace scope restriction. - Further information can be found in Documentation/security/Yama.txt. - - If you are unsure how to answer this question, answer N. diff --git a/trunk/security/yama/Makefile b/trunk/security/yama/Makefile deleted file mode 100644 index 8b5e06588456..000000000000 --- a/trunk/security/yama/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_SECURITY_YAMA) := yama.o - -yama-y := yama_lsm.o diff --git a/trunk/security/yama/yama_lsm.c b/trunk/security/yama/yama_lsm.c deleted file mode 100644 index 573723843a04..000000000000 --- a/trunk/security/yama/yama_lsm.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Yama Linux Security Module - * - * Author: Kees Cook - * - * Copyright (C) 2010 Canonical, Ltd. - * Copyright (C) 2011 The Chromium OS Authors. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * - */ - -#include -#include -#include -#include -#include - -static int ptrace_scope = 1; - -/* describe a ptrace relationship for potential exception */ -struct ptrace_relation { - struct task_struct *tracer; - struct task_struct *tracee; - struct list_head node; -}; - -static LIST_HEAD(ptracer_relations); -static DEFINE_SPINLOCK(ptracer_relations_lock); - -/** - * yama_ptracer_add - add/replace an exception for this tracer/tracee pair - * @tracer: the task_struct of the process doing the ptrace - * @tracee: the task_struct of the process to be ptraced - * - * Each tracee can have, at most, one tracer registered. Each time this - * is called, the prior registered tracer will be replaced for the tracee. - * - * Returns 0 if relationship was added, -ve on error. - */ -static int yama_ptracer_add(struct task_struct *tracer, - struct task_struct *tracee) -{ - int rc = 0; - struct ptrace_relation *added; - struct ptrace_relation *entry, *relation = NULL; - - added = kmalloc(sizeof(*added), GFP_KERNEL); - if (!added) - return -ENOMEM; - - spin_lock_bh(&ptracer_relations_lock); - list_for_each_entry(entry, &ptracer_relations, node) - if (entry->tracee == tracee) { - relation = entry; - break; - } - if (!relation) { - relation = added; - relation->tracee = tracee; - list_add(&relation->node, &ptracer_relations); - } - relation->tracer = tracer; - - spin_unlock_bh(&ptracer_relations_lock); - if (added != relation) - kfree(added); - - return rc; -} - -/** - * yama_ptracer_del - remove exceptions related to the given tasks - * @tracer: remove any relation where tracer task matches - * @tracee: remove any relation where tracee task matches - */ -static void yama_ptracer_del(struct task_struct *tracer, - struct task_struct *tracee) -{ - struct ptrace_relation *relation, *safe; - - spin_lock_bh(&ptracer_relations_lock); - list_for_each_entry_safe(relation, safe, &ptracer_relations, node) - if (relation->tracee == tracee || - (tracer && relation->tracer == tracer)) { - list_del(&relation->node); - kfree(relation); - } - spin_unlock_bh(&ptracer_relations_lock); -} - -/** - * yama_task_free - check for task_pid to remove from exception list - * @task: task being removed - */ -static void yama_task_free(struct task_struct *task) -{ - yama_ptracer_del(task, task); -} - -/** - * yama_task_prctl - check for Yama-specific prctl operations - * @option: operation - * @arg2: argument - * @arg3: argument - * @arg4: argument - * @arg5: argument - * - * Return 0 on success, -ve on error. -ENOSYS is returned when Yama - * does not handle the given option. - */ -static int yama_task_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) -{ - int rc; - struct task_struct *myself = current; - - rc = cap_task_prctl(option, arg2, arg3, arg4, arg5); - if (rc != -ENOSYS) - return rc; - - switch (option) { - case PR_SET_PTRACER: - /* Since a thread can call prctl(), find the group leader - * before calling _add() or _del() on it, since we want - * process-level granularity of control. The tracer group - * leader checking is handled later when walking the ancestry - * at the time of PTRACE_ATTACH check. - */ - rcu_read_lock(); - if (!thread_group_leader(myself)) - myself = rcu_dereference(myself->group_leader); - get_task_struct(myself); - rcu_read_unlock(); - - if (arg2 == 0) { - yama_ptracer_del(NULL, myself); - rc = 0; - } else if (arg2 == PR_SET_PTRACER_ANY) { - rc = yama_ptracer_add(NULL, myself); - } else { - struct task_struct *tracer; - - rcu_read_lock(); - tracer = find_task_by_vpid(arg2); - if (tracer) - get_task_struct(tracer); - else - rc = -EINVAL; - rcu_read_unlock(); - - if (tracer) { - rc = yama_ptracer_add(tracer, myself); - put_task_struct(tracer); - } - } - - put_task_struct(myself); - break; - } - - return rc; -} - -/** - * task_is_descendant - walk up a process family tree looking for a match - * @parent: the process to compare against while walking up from child - * @child: the process to start from while looking upwards for parent - * - * Returns 1 if child is a descendant of parent, 0 if not. - */ -static int task_is_descendant(struct task_struct *parent, - struct task_struct *child) -{ - int rc = 0; - struct task_struct *walker = child; - - if (!parent || !child) - return 0; - - rcu_read_lock(); - if (!thread_group_leader(parent)) - parent = rcu_dereference(parent->group_leader); - while (walker->pid > 0) { - if (!thread_group_leader(walker)) - walker = rcu_dereference(walker->group_leader); - if (walker == parent) { - rc = 1; - break; - } - walker = rcu_dereference(walker->real_parent); - } - rcu_read_unlock(); - - return rc; -} - -/** - * ptracer_exception_found - tracer registered as exception for this tracee - * @tracer: the task_struct of the process attempting ptrace - * @tracee: the task_struct of the process to be ptraced - * - * Returns 1 if tracer has is ptracer exception ancestor for tracee. - */ -static int ptracer_exception_found(struct task_struct *tracer, - struct task_struct *tracee) -{ - int rc = 0; - struct ptrace_relation *relation; - struct task_struct *parent = NULL; - bool found = false; - - spin_lock_bh(&ptracer_relations_lock); - rcu_read_lock(); - if (!thread_group_leader(tracee)) - tracee = rcu_dereference(tracee->group_leader); - list_for_each_entry(relation, &ptracer_relations, node) - if (relation->tracee == tracee) { - parent = relation->tracer; - found = true; - break; - } - - if (found && (parent == NULL || task_is_descendant(parent, tracer))) - rc = 1; - rcu_read_unlock(); - spin_unlock_bh(&ptracer_relations_lock); - - return rc; -} - -/** - * yama_ptrace_access_check - validate PTRACE_ATTACH calls - * @child: task that current task is attempting to ptrace - * @mode: ptrace attach mode - * - * Returns 0 if following the ptrace is allowed, -ve on error. - */ -static int yama_ptrace_access_check(struct task_struct *child, - unsigned int mode) -{ - int rc; - - /* If standard caps disallows it, so does Yama. We should - * only tighten restrictions further. - */ - rc = cap_ptrace_access_check(child, mode); - if (rc) - return rc; - - /* require ptrace target be a child of ptracer on attach */ - if (mode == PTRACE_MODE_ATTACH && - ptrace_scope && - !task_is_descendant(current, child) && - !ptracer_exception_found(current, child) && - !capable(CAP_SYS_PTRACE)) - rc = -EPERM; - - if (rc) { - char name[sizeof(current->comm)]; - printk_ratelimited(KERN_NOTICE "ptrace of non-child" - " pid %d was attempted by: %s (pid %d)\n", - child->pid, - get_task_comm(name, current), - current->pid); - } - - return rc; -} - -static struct security_operations yama_ops = { - .name = "yama", - - .ptrace_access_check = yama_ptrace_access_check, - .task_prctl = yama_task_prctl, - .task_free = yama_task_free, -}; - -#ifdef CONFIG_SYSCTL -static int zero; -static int one = 1; - -struct ctl_path yama_sysctl_path[] = { - { .procname = "kernel", }, - { .procname = "yama", }, - { } -}; - -static struct ctl_table yama_sysctl_table[] = { - { - .procname = "ptrace_scope", - .data = &ptrace_scope, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, - { } -}; -#endif /* CONFIG_SYSCTL */ - -static __init int yama_init(void) -{ - if (!security_module_enable(&yama_ops)) - return 0; - - printk(KERN_INFO "Yama: becoming mindful.\n"); - - if (register_security(&yama_ops)) - panic("Yama: kernel registration failed.\n"); - -#ifdef CONFIG_SYSCTL - if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) - panic("Yama: sysctl registration failed.\n"); -#endif - - return 0; -} - -security_initcall(yama_init);