diff options
687 files changed, 25963 insertions, 26274 deletions
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt new file mode 100644 index 000000000000..bc8ded641ab6 --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt @@ -0,0 +1,63 @@ +* 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 <string-list> and the value shall be of the form + "fsl,mpic-v<version>-msgr", where <version> 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 + <prop-encoded-array>. + + - 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 + <prop-encoded-array>. + +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 <u32>. 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<n>', where <n> 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/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt index 2cf38bd841fd..dc5744636a57 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt @@ -56,7 +56,27 @@ 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: <empty> + 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: <empty> + 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: <u32> + 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/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt index 5d586e1ccaf5..5693877ab377 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt @@ -6,8 +6,10 @@ Required properties: etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on the parent type. -- reg : should contain the address and the length of the shared message - interrupt register set. +- 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. - msi-available-ranges: use <start count> style section to define which msi interrupt can be used in the 256 msi interrupts. This property is diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt index 4e2575873187..7a34f827989c 100644 --- a/Documentation/filesystems/debugfs.txt +++ b/Documentation/filesystems/debugfs.txt @@ -136,7 +136,7 @@ file. void __iomem *base; }; - struct dentry *debugfs_create_regset32(const char *name, mode_t mode, + struct dentry *debugfs_create_regset32(const char *name, umode_t mode, struct dentry *parent, struct debugfs_regset32 *regset); diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index b4a3d765ff9a..74acd9618819 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -429,3 +429,9 @@ 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/Documentation/filesystems/qnx6.txt b/Documentation/filesystems/qnx6.txt new file mode 100644 index 000000000000..050223ea03c7 --- /dev/null +++ b/Documentation/filesystems/qnx6.txt @@ -0,0 +1,174 @@ +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/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 68fbfb6529eb..3b7488fc3373 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -218,6 +218,7 @@ Code Seq#(hex) Include File Comments 'h' 00-7F conflict! Charon filesystem <mailto:zapman@interlan.net> '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/Documentation/networking/dns_resolver.txt b/Documentation/networking/dns_resolver.txt index 7f531ad83285..d86adcdae420 100644 --- a/Documentation/networking/dns_resolver.txt +++ b/Documentation/networking/dns_resolver.txt @@ -102,6 +102,10 @@ 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/Documentation/powerpc/firmware-assisted-dump.txt b/Documentation/powerpc/firmware-assisted-dump.txt new file mode 100644 index 000000000000..3007bc98af28 --- /dev/null +++ b/Documentation/powerpc/firmware-assisted-dump.txt @@ -0,0 +1,270 @@ + + 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: + <region>: [<start>-<end>] <reserved-size> bytes, Dumped: <dump-size> + + 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 <mahesh@linux.vnet.ibm.com> +This document is based on the original documentation written for phyp +assisted dump by Linas Vepstas and Manish Ahuja. diff --git a/Documentation/powerpc/mpc52xx.txt b/Documentation/powerpc/mpc52xx.txt index 10dd4ab93b85..0d540a31ea1a 100644 --- a/Documentation/powerpc/mpc52xx.txt +++ b/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: # <edit Makefile to set ARCH=ppc & CROSS_COMPILE=... ( also EXTRAVERSION if you wish to ). # make lite5200_defconfig # cp your_initrd.gz arch/ppc/boot/images/ramdisk.image.gz - # make zImage.initrd - # make + # make zImage.initrd + # make then in DBug: DBug> dn -i zImage.initrd.lite5200 - + Some remarks : - The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100 diff --git a/Documentation/powerpc/phyp-assisted-dump.txt b/Documentation/powerpc/phyp-assisted-dump.txt deleted file mode 100644 index ad340205d96a..000000000000 --- a/Documentation/powerpc/phyp-assisted-dump.txt +++ /dev/null @@ -1,127 +0,0 @@ - - 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/Documentation/security/00-INDEX b/Documentation/security/00-INDEX index 99b85d39751c..eeed1de546d4 100644 --- a/Documentation/security/00-INDEX +++ b/Documentation/security/00-INDEX @@ -6,6 +6,8 @@ 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/Documentation/security/Yama.txt b/Documentation/security/Yama.txt new file mode 100644 index 000000000000..a9511f179069 --- /dev/null +++ b/Documentation/security/Yama.txt @@ -0,0 +1,65 @@ +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/Documentation/security/keys.txt b/Documentation/security/keys.txt index fcbe7a703405..787717091421 100644 --- a/Documentation/security/keys.txt +++ b/Documentation/security/keys.txt @@ -554,6 +554,10 @@ 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/MAINTAINERS b/MAINTAINERS index 92f9924c4335..58f60356f071 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4071,7 +4071,7 @@ M: Josh Boyer <jwboyer@gmail.com> M: Matt Porter <mporter@kernel.crashing.org> W: http://www.penguinppc.org/ L: linuxppc-dev@lists.ozlabs.org -T: git git://git.infradead.org/users/jwboyer/powerpc-4xx.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git S: Maintained F: arch/powerpc/platforms/40x/ F: arch/powerpc/platforms/44x/ diff --git a/arch/alpha/kernel/binfmt_loader.c b/arch/alpha/kernel/binfmt_loader.c index 3fcfad410130..d1f474d1d44d 100644 --- a/arch/alpha/kernel/binfmt_loader.c +++ b/arch/alpha/kernel/binfmt_loader.c @@ -46,6 +46,7 @@ static struct linux_binfmt loader_format = { static int __init init_loader_binfmt(void) { - return insert_binfmt(&loader_format); + insert_binfmt(&loader_format); + return 0; } arch_initcall(init_loader_binfmt); diff --git a/arch/arm/mach-tegra/fuse.c b/arch/arm/mach-tegra/fuse.c index 1fa26d9a1a68..ea49bd93c6b9 100644 --- a/arch/arm/mach-tegra/fuse.c +++ b/arch/arm/mach-tegra/fuse.c @@ -19,6 +19,7 @@ #include <linux/kernel.h> #include <linux/io.h> +#include <linux/module.h> #include <mach/iomap.h> @@ -58,6 +59,7 @@ 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/arch/m68k/Kconfig b/arch/m68k/Kconfig index ae413d4a8bb7..d318c606c888 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -7,6 +7,7 @@ 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 @@ -24,9 +25,6 @@ config ARCH_HAS_ILOG2_U64 config GENERIC_CLOCKEVENTS bool -config GENERIC_CMOS_UPDATE - def_bool !MMU - config GENERIC_GPIO bool @@ -67,6 +65,9 @@ config CPU_HAS_NO_MULDIV64 config CPU_HAS_ADDRESS_SPACES bool +config FPU + bool + config HZ int default 1000 if CLEOPATRA diff --git a/arch/m68k/include/asm/m5206sim.h b/arch/m68k/include/asm/m5206sim.h index 9015eadd5c00..69722366b084 100644 --- a/arch/m68k/include/asm/m5206sim.h +++ b/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_BASE1 0x180 /* Base address of UART1 */ -#define MCFUART_BASE2 0x140 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x180) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x140) /* Base address UART1 */ #else -#define MCFUART_BASE1 0x140 /* Base address of UART1 */ -#define MCFUART_BASE2 0x180 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x140) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x180) /* Base address UART1 */ #endif /* @@ -112,6 +112,8 @@ */ #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/arch/m68k/include/asm/m520xsim.h b/arch/m68k/include/asm/m520xsim.h index eda62de7e607..17f2aab9cf97 100644 --- a/arch/m68k/include/asm/m520xsim.h +++ b/arch/m68k/include/asm/m520xsim.h @@ -48,8 +48,21 @@ #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. */ @@ -144,15 +157,25 @@ /* * UART module. */ -#define MCFUART_BASE1 0xFC060000 /* Base address of UART1 */ -#define MCFUART_BASE2 0xFC064000 /* Base address of UART2 */ -#define MCFUART_BASE3 0xFC068000 /* Base address of UART2 */ +#define MCFUART_BASE0 0xFC060000 /* Base address of UART0 */ +#define MCFUART_BASE1 0xFC064000 /* Base address of UART1 */ +#define MCFUART_BASE2 0xFC068000 /* Base address of UART2 */ /* * FEC module. */ -#define MCFFEC_BASE 0xFC030000 /* Base of FEC ethernet */ -#define MCFFEC_SIZE 0x800 /* Register set size */ +#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 /* * Reset Control Unit. diff --git a/arch/m68k/include/asm/m523xsim.h b/arch/m68k/include/asm/m523xsim.h index 6235921eca4e..075062d4eecd 100644 --- a/arch/m68k/include/asm/m523xsim.h +++ b/arch/m68k/include/asm/m523xsim.h @@ -35,8 +35,23 @@ #define MCFINT_VECBASE 64 /* Vector base number */ #define MCFINT_UART0 13 /* Interrupt number for UART0 */ -#define MCFINT_PIT1 36 /* Interrupt number for PIT1 */ +#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) /* * SDRAM configuration registers. @@ -50,8 +65,8 @@ /* * Reset Control Unit (relative to IPSBAR). */ -#define MCF_RCR 0x110000 -#define MCF_RSR 0x110001 +#define MCF_RCR (MCF_IPSBAR + 0x110000) +#define MCF_RSR (MCF_IPSBAR + 0x110001) #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ @@ -59,15 +74,26 @@ /* * UART module. */ -#define MCFUART_BASE1 (MCF_IPSBAR + 0x200) -#define MCFUART_BASE2 (MCF_IPSBAR + 0x240) -#define MCFUART_BASE3 (MCF_IPSBAR + 0x280) +#define MCFUART_BASE0 (MCF_IPSBAR + 0x200) +#define MCFUART_BASE1 (MCF_IPSBAR + 0x240) +#define MCFUART_BASE2 (MCF_IPSBAR + 0x280) /* * FEC ethernet module. */ -#define MCFFEC_BASE (MCF_IPSBAR + 0x1000) -#define MCFFEC_SIZE 0x800 +#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 /* * GPIO module. diff --git a/arch/m68k/include/asm/m5249sim.h b/arch/m68k/include/asm/m5249sim.h index 805714ca8d7d..7f0c2c3660fd 100644 --- a/arch/m68k/include/asm/m5249sim.h +++ b/arch/m68k/include/asm/m5249sim.h @@ -76,8 +76,19 @@ /* * UART module. */ -#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ -#define MCFUART_BASE2 0x200 /* Base address of UART2 */ +#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 /* * DMA unit base addresses. @@ -108,6 +119,9 @@ #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/arch/m68k/include/asm/m5272sim.h b/arch/m68k/include/asm/m5272sim.h index 759c2b07a994..a58f1760d858 100644 --- a/arch/m68k/include/asm/m5272sim.h +++ b/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_BASE1 0x100 /* Base address of UART1 */ -#define MCFUART_BASE2 0x140 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x100) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x140) /* Base address UART1 */ #define MCFSIM_PACNT (MCF_MBAR + 0x80) /* Port A Control (r/w) */ #define MCFSIM_PADDR (MCF_MBAR + 0x84) /* Port A Direction (r/w) */ @@ -88,6 +88,9 @@ #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. */ @@ -101,8 +104,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_UART1 73 /* UART 1 */ -#define MCF_IRQ_UART2 74 /* UART 2 */ +#define MCF_IRQ_UART0 73 /* UART 0 */ +#define MCF_IRQ_UART1 74 /* UART 1 */ #define MCF_IRQ_PLIP 75 /* PLIC 2Khz Periodic */ #define MCF_IRQ_PLIA 76 /* PLIC Asynchronous */ #define MCF_IRQ_USB0 77 /* USB Endpoint 0 */ @@ -114,9 +117,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_ERX 86 /* Ethernet Receiver */ -#define MCF_IRQ_ETX 87 /* Ethernet Transmitter */ -#define MCF_IRQ_ENTC 88 /* Ethernet Non-Time Critical */ +#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_QSPI 89 /* Queued Serial Interface */ #define MCF_IRQ_EINT5 90 /* External Interrupt 5 */ #define MCF_IRQ_EINT6 91 /* External Interrupt 6 */ diff --git a/arch/m68k/include/asm/m527xsim.h b/arch/m68k/include/asm/m527xsim.h index 758810ef91ec..83db8106f50a 100644 --- a/arch/m68k/include/asm/m527xsim.h +++ b/arch/m68k/include/asm/m527xsim.h @@ -38,8 +38,29 @@ #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. */ @@ -72,9 +93,9 @@ /* * UART module. */ -#define MCFUART_BASE1 (MCF_IPSBAR + 0x200) -#define MCFUART_BASE2 (MCF_IPSBAR + 0x240) -#define MCFUART_BASE3 (MCF_IPSBAR + 0x280) +#define MCFUART_BASE0 (MCF_IPSBAR + 0x200) +#define MCFUART_BASE1 (MCF_IPSBAR + 0x240) +#define MCFUART_BASE2 (MCF_IPSBAR + 0x280) /* * FEC ethernet module. @@ -84,6 +105,28 @@ #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) @@ -285,8 +328,8 @@ /* * Reset Control Unit (relative to IPSBAR). */ -#define MCF_RCR 0x110000 -#define MCF_RSR 0x110001 +#define MCF_RCR (MCF_IPSBAR + 0x110000) +#define MCF_RSR (MCF_IPSBAR + 0x110001) #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ diff --git a/arch/m68k/include/asm/m528xsim.h b/arch/m68k/include/asm/m528xsim.h index d798bd5df56c..569476fba18c 100644 --- a/arch/m68k/include/asm/m528xsim.h +++ b/arch/m68k/include/asm/m528xsim.h @@ -35,9 +35,24 @@ #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. */ @@ -58,15 +73,26 @@ /* * UART module. */ -#define MCFUART_BASE1 (MCF_IPSBAR + 0x00000200) -#define MCFUART_BASE2 (MCF_IPSBAR + 0x00000240) -#define MCFUART_BASE3 (MCF_IPSBAR + 0x00000280) +#define MCFUART_BASE0 (MCF_IPSBAR + 0x00000200) +#define MCFUART_BASE1 (MCF_IPSBAR + 0x00000240) +#define MCFUART_BASE2 (MCF_IPSBAR + 0x00000280) /* * FEC ethernet module. */ -#define MCFFEC_BASE (MCF_IPSBAR + 0x00001000) -#define MCFFEC_SIZE 0x800 +#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 /* * GPIO registers @@ -246,8 +272,8 @@ /* * Reset Control Unit (relative to IPSBAR). */ -#define MCF_RCR 0x110000 -#define MCF_RSR 0x110001 +#define MCF_RCR (MCF_IPSBAR + 0x110000) +#define MCF_RSR (MCF_IPSBAR + 0x110001) #define MCF_RCR_SWRESET 0x80 /* Software reset bit */ #define MCF_RCR_FRCSTOUT 0x40 /* Force external reset */ diff --git a/arch/m68k/include/asm/m5307sim.h b/arch/m68k/include/asm/m5307sim.h index 8f8609fcc9b8..3bc3adaa7ee0 100644 --- a/arch/m68k/include/asm/m5307sim.h +++ b/arch/m68k/include/asm/m5307sim.h @@ -117,11 +117,11 @@ * UART module. */ #if defined(CONFIG_NETtel) || defined(CONFIG_SECUREEDGEMP3) -#define MCFUART_BASE1 0x200 /* Base address of UART1 */ -#define MCFUART_BASE2 0x1c0 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x200) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x1c0) /* Base address UART1 */ #else -#define MCFUART_BASE1 0x1c0 /* Base address of UART1 */ -#define MCFUART_BASE2 0x200 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x1c0) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x200) /* Base address UART1 */ #endif /* @@ -176,6 +176,8 @@ */ #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/arch/m68k/include/asm/m532xsim.h b/arch/m68k/include/asm/m532xsim.h index ba4cc784f574..29b66e21413a 100644 --- a/arch/m68k/include/asm/m532xsim.h +++ b/arch/m68k/include/asm/m532xsim.h @@ -24,6 +24,19 @@ #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) @@ -82,9 +95,25 @@ /* * UART module. */ -#define MCFUART_BASE1 0xFC060000 /* Base address of UART1 */ -#define MCFUART_BASE2 0xFC064000 /* Base address of UART2 */ -#define MCFUART_BASE3 0xFC068000 /* Base address of UART3 */ +#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 /* * Timer module. diff --git a/arch/m68k/include/asm/m5407sim.h b/arch/m68k/include/asm/m5407sim.h index 51e00b00b8a6..79f58dd6a83d 100644 --- a/arch/m68k/include/asm/m5407sim.h +++ b/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_BASE1 0x1c0 /* Base address of UART1 */ -#define MCFUART_BASE2 0x200 /* Base address of UART2 */ +#define MCFUART_BASE0 (MCF_MBAR + 0x1c0) /* Base address UART0 */ +#define MCFUART_BASE1 (MCF_MBAR + 0x200) /* Base address UART1 */ #define MCFSIM_PADDR (MCF_MBAR + 0x244) #define MCFSIM_PADAT (MCF_MBAR + 0x248) @@ -139,6 +139,8 @@ */ #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/arch/m68k/include/asm/m54xxsim.h b/arch/m68k/include/asm/m54xxsim.h index 1ed8bfb02772..ae56b8848a9d 100644 --- a/arch/m68k/include/asm/m54xxsim.h +++ b/arch/m68k/include/asm/m54xxsim.h @@ -31,16 +31,20 @@ /* * UART module. */ -#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 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 system peripheral IRQ usage. */ -#define MCF_IRQ_TIMER (64 + 54) /* Slice Timer 0 */ -#define MCF_IRQ_PROFILER (64 + 53) /* Slice Timer 1 */ +#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) /* * Generic GPIO support diff --git a/arch/m68k/include/asm/machdep.h b/arch/m68k/include/asm/machdep.h index 789f3b2de0e9..825c1c813196 100644 --- a/arch/m68k/include/asm/machdep.h +++ b/arch/m68k/include/asm/machdep.h @@ -22,8 +22,6 @@ 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 ); @@ -35,9 +33,8 @@ extern void (*mach_l2_flush) (int); extern void (*mach_beep) (unsigned int, unsigned int); /* Hardware clock functions */ -extern void hw_timer_init(void); +extern void hw_timer_init(irq_handler_t handler); 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/arch/m68k/include/asm/mcfqspi.h b/arch/m68k/include/asm/mcfqspi.h index 7fe631972f1f..7b51416ccae2 100644 --- a/arch/m68k/include/asm/mcfqspi.h +++ b/arch/m68k/include/asm/mcfqspi.h @@ -21,17 +21,6 @@ #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/arch/m68k/include/asm/mcfuart.h b/arch/m68k/include/asm/mcfuart.h index 2abedff0a694..2d3bc774b3c5 100644 --- a/arch/m68k/include/asm/mcfuart.h +++ b/arch/m68k/include/asm/mcfuart.h @@ -41,7 +41,10 @@ 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) */ -#else +#endif +#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \ + defined(CONFIG_M5249) || defined(CONFIG_M5307) || \ + defined(CONFIG_M5407) #define MCFUART_UIVR 0x30 /* Interrupt Vector (r/w) */ #endif #define MCFUART_UIPR 0x34 /* Input Port (r) */ diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 6cf4bd6e34f8..c54ef927e483 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -1,5 +1,378 @@ +/* + * 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 <linux/errno.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/smp.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/user.h> +#include <linux/reboot.h> +#include <linux/init_task.h> +#include <linux/mqueue.h> + +#include <asm/uaccess.h> +#include <asm/system.h> +#include <asm/traps.h> +#include <asm/machdep.h> +#include <asm/setup.h> +#include <asm/pgtable.h> + + +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 -#include "process_mm.c" + return do_fork(SIGCHLD, rdusp(), regs, 0, NULL, NULL); #else -#include "process_no.c" + return -EINVAL; #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/arch/m68k/kernel/process_mm.c b/arch/m68k/kernel/process_mm.c deleted file mode 100644 index fe4186b5fc32..000000000000 --- a/arch/m68k/kernel/process_mm.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * 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 <linux/errno.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/fs.h> -#include <linux/smp.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/reboot.h> -#include <linux/init_task.h> -#include <linux/mqueue.h> - -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/traps.h> -#include <asm/machdep.h> -#include <asm/setup.h> -#include <asm/pgtable.h> - - -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/arch/m68k/kernel/process_no.c b/arch/m68k/kernel/process_no.c deleted file mode 100644 index f7fe6c348595..000000000000 --- a/arch/m68k/kernel/process_no.c +++ /dev/null @@ -1,404 +0,0 @@ -/* - * linux/arch/m68knommu/kernel/process.c - * - * Copyright (C) 1995 Hamish Macdonald - * - * 68060 fixes by Jesper Skov - * - * uClinux changes - * Copyright (C) 2000-2002, David McCullough <davidm@snapgear.com> - */ - -/* - * This file handles the architecture-dependent parts of process handling.. - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/stddef.h> -#include <linux/unistd.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/interrupt.h> -#include <linux/reboot.h> -#include <linux/fs.h> -#include <linux/slab.h> - -#include <asm/uaccess.h> -#include <asm/system.h> -#include <asm/traps.h> -#include <asm/machdep.h> -#include <asm/setup.h> -#include <asm/pgtable.h> - -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/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 07a417550e94..149a05f8b9ee 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -1,5 +1,305 @@ +/* + * 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 <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/errno.h> +#include <linux/ptrace.h> +#include <linux/user.h> +#include <linux/signal.h> +#include <linux/tracehook.h> + +#include <asm/uaccess.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/processor.h> + +/* + * 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 -#include "ptrace_mm.c" -#else -#include "ptrace_no.c" +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); +} #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/arch/m68k/kernel/ptrace_mm.c b/arch/m68k/kernel/ptrace_mm.c deleted file mode 100644 index 7bc999b73529..000000000000 --- a/arch/m68k/kernel/ptrace_mm.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * 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 <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/signal.h> -#include <linux/tracehook.h> - -#include <asm/uaccess.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/processor.h> - -/* - * 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/arch/m68k/kernel/ptrace_no.c b/arch/m68k/kernel/ptrace_no.c deleted file mode 100644 index 6709fb707335..000000000000 --- a/arch/m68k/kernel/ptrace_no.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * 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 <linux/kernel.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/smp.h> -#include <linux/errno.h> -#include <linux/ptrace.h> -#include <linux/user.h> -#include <linux/signal.h> -#include <linux/tracehook.h> - -#include <asm/uaccess.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/processor.h> - -/* - * 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/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c index ca3df0dc7e88..7dc186b7a85f 100644 --- a/arch/m68k/kernel/setup_no.c +++ b/arch/m68k/kernel/setup_no.c @@ -31,6 +31,7 @@ #include <linux/init.h> #include <linux/initrd.h> #include <linux/root_dev.h> +#include <linux/rtc.h> #include <asm/setup.h> #include <asm/irq.h> @@ -47,7 +48,9 @@ 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/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c index 75ab79b3bdeb..d7deb7fc7eb5 100644 --- a/arch/m68k/kernel/time.c +++ b/arch/m68k/kernel/time.c @@ -1,5 +1,111 @@ -#if defined(CONFIG_MMU) && !defined(CONFIG_COLDFIRE) -#include "time_mm.c" -#else -#include "time_no.c" -#endif +/* + * 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 <linux/errno.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> + +#include <asm/machdep.h> +#include <asm/io.h> +#include <asm/irq_regs.h> + +#include <linux/time.h> +#include <linux/timex.h> +#include <linux/profile.h> + +/* + * 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<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; + dist = period / 4; + } + } +#endif /* CONFIG_HEARTBEAT */ + return IRQ_HANDLED; +} + +void read_persistent_clock(struct timespec *ts) +{ + struct rtc_time time; + ts->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 */ diff --git a/arch/m68k/kernel/time_mm.c b/arch/m68k/kernel/time_mm.c deleted file mode 100644 index 18b34ee5db3b..000000000000 --- a/arch/m68k/kernel/time_mm.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * 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 <linux/errno.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/rtc.h> -#include <linux/platform_device.h> - -#include <asm/machdep.h> -#include <asm/io.h> -#include <asm/irq_regs.h> - -#include <linux/time.h> -#include <linux/timex.h> -#include <linux/profile.h> - -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<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30; - dist = period / 4; - } - } -#endif /* CONFIG_HEARTBEAT */ - return IRQ_HANDLED; -} - -void read_persistent_clock(struct timespec *ts) -{ - struct rtc_time time; - ts->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/arch/m68k/kernel/time_no.c b/arch/m68k/kernel/time_no.c deleted file mode 100644 index 3ef0f7768dcd..000000000000 --- a/arch/m68k/kernel/time_no.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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 <linux/errno.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/kernel.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/profile.h> -#include <linux/time.h> -#include <linux/timex.h> - -#include <asm/machdep.h> -#include <asm/irq_regs.h> - -#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/arch/m68k/kernel/vmlinux-nommu.lds b/arch/m68k/kernel/vmlinux-nommu.lds index 8e66ccb0935e..40e02d9c38b4 100644 --- a/arch/m68k/kernel/vmlinux-nommu.lds +++ b/arch/m68k/kernel/vmlinux-nommu.lds @@ -1,195 +1,93 @@ /* * vmlinux.lds.S -- master linker script for m68knommu arch * - * (C) Copyright 2002-2006, Greg Ungerer <gerg@snapgear.com> + * (C) Copyright 2002-2012, Greg Ungerer <gerg@snapgear.com> * * This linker script is equipped to build either ROM loaded or RAM * run kernels. */ -#include <asm-generic/vmlinux.lds.h> -#include <asm/page.h> -#include <asm/thread_info.h> - #if defined(CONFIG_RAMKERNEL) -#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) || 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 +#define KTEXT_ADDR CONFIG_KERNELBASE #endif - -#ifndef DATA_ADDR -#define DATA_ADDR +#if defined(CONFIG_ROMKERNEL) +#define KTEXT_ADDR CONFIG_ROMSTART +#define KDATA_ADDR CONFIG_KERNELBASE +#define LOAD_OFFSET KDATA_ADDR + (ADDR(.text) + SIZEOF(.text)) #endif +#include <asm/page.h> +#include <asm/thread_info.h> +#include <asm-generic/vmlinux.lds.h> 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 ROMVEC_START - . = ROMVEC_START ; +#ifdef CONFIG_ROMVEC + . = CONFIG_ROMVEC; .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 = .; - . = 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 + EXCEPTION_TABLE(16) + NOTES + . = 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 = .; - } > INIT - - .bss : { - . = ALIGN(4); - _sbss = . ; - *(.bss) - *(COMMON) - . = ALIGN(4) ; - _ebss = . ; - _end = . ; - } > BSSS + } + + _sbss = .; + BSS_SECTION(0, 0, 0) + _ebss = .; + + _end = .; + + STABS_DEBUG + .comment 0 : { *(.comment) } + /* Sections to be discarded */ DISCARDS } diff --git a/arch/m68k/platform/5206/config.c b/arch/m68k/platform/5206/config.c index 6fa3f800277a..6bfbeebd231b 100644 --- a/arch/m68k/platform/5206/config.c +++ b/arch/m68k/platform/5206/config.c @@ -16,83 +16,6 @@ #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> - -/***************************************************************************/ - -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 */; -} /***************************************************************************/ @@ -104,9 +27,7 @@ void __init config_BSP(char *commandp, int size) commandp[size-1] = 0; #endif /* CONFIG_NETtel */ - mach_reset = m5206_cpu_reset; - m5206_timers_init(); - m5206_uarts_init(); + mach_sched_init = hw_timer_init; /* Only support the external interrupts on their primary level */ mcf_mapirq2imr(25, MCFINTC_EINT1); @@ -115,13 +36,3 @@ 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/arch/m68k/platform/520x/config.c b/arch/m68k/platform/520x/config.c index 8a98683f1b15..235947844f27 100644 --- a/arch/m68k/platform/520x/config.c +++ b/arch/m68k/platform/520x/config.c @@ -15,194 +15,14 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -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, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m520x_qspi_init(void) { @@ -214,54 +34,28 @@ 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) */ - -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 -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ -static void __init m520x_uart_init_line(int line, int irq) +static void __init m520x_uarts_init(void) { u16 par; u8 par2; - 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; + /* 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); - for (line = 0; (line < nrlines); line++) - m520x_uart_init_line(line, m520x_uart_platform[line].irq); + /* 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); } /***************************************************************************/ @@ -280,32 +74,14 @@ 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_reset = m520x_cpu_reset; + mach_sched_init = hw_timer_init; m520x_uarts_init(); m520x_fec_init(); -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI 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/arch/m68k/platform/523x/config.c b/arch/m68k/platform/523x/config.c index 71f4436ec809..c8b405d5a961 100644 --- a/arch/m68k/platform/523x/config.c +++ b/arch/m68k/platform/523x/config.c @@ -16,215 +16,13 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -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, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m523x_qspi_init(void) { @@ -237,15 +35,8 @@ 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) */ -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 -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ @@ -263,31 +54,13 @@ 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_reset = m523x_cpu_reset; -} - -/***************************************************************************/ - -static int __init init_BSP(void) -{ + mach_sched_init = hw_timer_init; m523x_fec_init(); -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI m523x_qspi_init(); #endif - platform_add_devices(m523x_devices, ARRAY_SIZE(m523x_devices)); - return 0; } -arch_initcall(init_BSP); - /***************************************************************************/ diff --git a/arch/m68k/platform/5249/config.c b/arch/m68k/platform/5249/config.c index ceb31e5744a6..bbf05135bb98 100644 --- a/arch/m68k/platform/5249/config.c +++ b/arch/m68k/platform/5249/config.c @@ -12,34 +12,13 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> +#include <linux/platform_device.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -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[] = { @@ -64,153 +43,15 @@ static struct platform_device m5249_smc91x = { #endif /* CONFIG_M5249C3 */ -#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 platform_device *m5249_devices[] __initdata = { +#ifdef CONFIG_M5249C3 + &m5249_smc91x, +#endif }; -static struct mcfqspi_platform_data m5249_qspi_data = { - .bus_num = 0, - .num_chipselect = 4, - .cs_control = &m5249_cs_control, -}; +/***************************************************************************/ -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, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m5249_qspi_init(void) { @@ -219,42 +60,8 @@ 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) */ - -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); -} +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ @@ -276,43 +83,14 @@ static void __init m5249_smc91x_init(void) /***************************************************************************/ -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) -{ - 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(); + mach_sched_init = hw_timer_init; + #ifdef CONFIG_M5249C3 m5249_smc91x_init(); #endif -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI m5249_qspi_init(); #endif } diff --git a/arch/m68k/platform/5272/config.c b/arch/m68k/platform/5272/config.c index 65bb582734e1..e68bc7a148eb 100644 --- a/arch/m68k/platform/5272/config.c +++ b/arch/m68k/platform/5272/config.c @@ -30,84 +30,18 @@ unsigned char ledbank = 0xff; /***************************************************************************/ -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) +static void __init m5272_uarts_init(void) { u32 v; - 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; + /* Enable the output lines for the serial ports */ + v = readl(MCF_MBAR + MCFSIM_PBCNT); + v = (v & ~0x000000ff) | 0x00000055; + writel(v, MCF_MBAR + MCFSIM_PBCNT); - for (line = 0; (line < nrlines); line++) - m5272_uart_init_line(line, m5272_uart_platform[line].irq); + v = readl(MCF_MBAR + MCFSIM_PDCNT); + v = (v & ~0x000003fc) | 0x000002a8; + writel(v, MCF_MBAR + MCFSIM_PDCNT); } /***************************************************************************/ @@ -146,6 +80,7 @@ void __init config_BSP(char *commandp, int size) #endif mach_reset = m5272_cpu_reset; + mach_sched_init = hw_timer_init; } /***************************************************************************/ @@ -167,7 +102,6 @@ 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/arch/m68k/platform/527x/config.c b/arch/m68k/platform/527x/config.c index 3ebc769cefda..7ed848c3b848 100644 --- a/arch/m68k/platform/527x/config.c +++ b/arch/m68k/platform/527x/config.c @@ -16,253 +16,14 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -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, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI static void __init m527x_qspi_init(void) { @@ -280,50 +41,23 @@ 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) */ -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 -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ -static void __init m527x_uart_init_line(int line, int irq) +static void __init m527x_uarts_init(void) { 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); - if (line == 0) - sepmask |= UART0_ENABLE_MASK; - else if (line == 1) - sepmask |= UART1_ENABLE_MASK; - else if (line == 2) - sepmask |= UART2_ENABLE_MASK; + sepmask |= UART0_ENABLE_MASK | UART1_ENABLE_MASK | 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) @@ -353,32 +87,14 @@ 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_reset = m527x_cpu_reset; + mach_sched_init = hw_timer_init; m527x_uarts_init(); m527x_fec_init(); -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI 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/arch/m68k/platform/528x/config.c b/arch/m68k/platform/528x/config.c index 7abe77a2f3e3..d4492926614c 100644 --- a/arch/m68k/platform/528x/config.c +++ b/arch/m68k/platform/528x/config.c @@ -17,229 +17,33 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -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, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI 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) */ -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 -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ -static void __init m528x_uart_init_line(int line, int irq) +static void __init m528x_uarts_init(void) { u8 port; - if ((line < 0) || (line > 2)) - return; - /* make sure PUAPAR is set for UART0 and UART1 */ - 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); + port = readb(MCF5282_GPIO_PUAPAR); + port |= 0x03 | (0x03 << 2); + writeb(port, MCF5282_GPIO_PUAPAR); } /***************************************************************************/ @@ -256,14 +60,6 @@ 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) { @@ -299,22 +95,12 @@ void __init config_BSP(char *commandp, int size) #ifdef CONFIG_WILDFIREMOD mach_halt = wildfiremod_halt; #endif -} - -/***************************************************************************/ - -static int __init init_BSP(void) -{ - mach_reset = m528x_cpu_reset; + mach_sched_init = hw_timer_init; m528x_uarts_init(); m528x_fec_init(); -#if defined(CONFIG_SPI_COLDFIRE_QSPI) || defined(CONFIG_SPI_COLDFIRE_QSPI_MODULE) +#ifdef CONFIG_SPI_COLDFIRE_QSPI m528x_qspi_init(); #endif - platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices)); - return 0; } -arch_initcall(init_BSP); - /***************************************************************************/ diff --git a/arch/m68k/platform/5307/config.c b/arch/m68k/platform/5307/config.c index 00900ac06a9c..a568d2870d15 100644 --- a/arch/m68k/platform/5307/config.c +++ b/arch/m68k/platform/5307/config.c @@ -16,7 +16,6 @@ #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> #include <asm/mcfwdebug.h> /***************************************************************************/ @@ -29,82 +28,6 @@ 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) || \ @@ -114,9 +37,7 @@ void __init config_BSP(char *commandp, int size) commandp[size-1] = 0; #endif - mach_reset = m5307_cpu_reset; - m5307_timers_init(); - m5307_uarts_init(); + mach_sched_init = hw_timer_init; /* Only support the external interrupts on their primary level */ mcf_mapirq2imr(25, MCFINTC_EINT1); @@ -135,13 +56,3 @@ 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/arch/m68k/platform/532x/config.c b/arch/m68k/platform/532x/config.c index ca51323f957b..2bec3477b739 100644 --- a/arch/m68k/platform/532x/config.c +++ b/arch/m68k/platform/532x/config.c @@ -21,214 +21,33 @@ #include <linux/param.h> #include <linux/init.h> #include <linux/io.h> -#include <linux/spi/spi.h> -#include <linux/gpio.h> #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> #include <asm/mcfuart.h> #include <asm/mcfdma.h> #include <asm/mcfwdebug.h> -#include <asm/mcfqspi.h> /***************************************************************************/ -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, -}; +#ifdef CONFIG_SPI_COLDFIRE_QSPI 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) */ - -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 -}; +#endif /* CONFIG_SPI_COLDFIRE_QSPI */ /***************************************************************************/ -static void __init m532x_uart_init_line(int line, int irq) -{ - 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); + /* UART GPIO initialization */ + MCF_GPIO_PAR_UART |= 0x0FFF; } + /***************************************************************************/ static void __init m532x_fec_init(void) @@ -242,14 +61,6 @@ 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) @@ -263,6 +74,13 @@ 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 @@ -274,21 +92,6 @@ void __init config_BSP(char *commandp, int size) } /***************************************************************************/ - -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/arch/m68k/platform/5407/config.c b/arch/m68k/platform/5407/config.c index 70ea789a400c..bb6c746ae819 100644 --- a/arch/m68k/platform/5407/config.c +++ b/arch/m68k/platform/5407/config.c @@ -16,91 +16,12 @@ #include <asm/machdep.h> #include <asm/coldfire.h> #include <asm/mcfsim.h> -#include <asm/mcfuart.h> - -/***************************************************************************/ - -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_reset = m5407_cpu_reset; - m5407_timers_init(); - m5407_uarts_init(); + mach_sched_init = hw_timer_init; /* Only support the external interrupts on their primary level */ mcf_mapirq2imr(25, MCFINTC_EINT1); @@ -110,13 +31,3 @@ 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/arch/m68k/platform/54xx/config.c b/arch/m68k/platform/54xx/config.c index ee043540bfa2..2081c6cbb3de 100644 --- a/arch/m68k/platform/54xx/config.c +++ b/arch/m68k/platform/54xx/config.c @@ -27,64 +27,17 @@ /***************************************************************************/ -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 */ - 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); + /* 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)); } /***************************************************************************/ @@ -145,18 +98,8 @@ 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/arch/m68k/platform/68328/config.c b/arch/m68k/platform/68328/config.c index d70bf2623db1..44b866544314 100644 --- a/arch/m68k/platform/68328/config.c +++ b/arch/m68k/platform/68328/config.c @@ -17,6 +17,7 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/rtc.h> #include <asm/system.h> #include <asm/machdep.h> #include <asm/MC68328.h> @@ -26,7 +27,7 @@ /***************************************************************************/ -void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); +int m68328_hwclk(int set, struct rtc_time *t); /***************************************************************************/ @@ -48,7 +49,7 @@ void config_BSP(char *command, int len) printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n"); printk(KERN_INFO "68328/Pilot support Bernhard Kuhn <kuhn@lpr.e-technik.tu-muenchen.de>\n"); - mach_gettod = m68328_timer_gettod; + mach_hwclk = m68328_hwclk; mach_reset = m68328_reset; } diff --git a/arch/m68k/platform/68328/ints.c b/arch/m68k/platform/68328/ints.c index 4bd456531f91..b3810febb3e3 100644 --- a/arch/m68k/platform/68328/ints.c +++ b/arch/m68k/platform/68328/ints.c @@ -68,8 +68,6 @@ 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/arch/m68k/platform/68328/timers.c b/arch/m68k/platform/68328/timers.c index f2678866067b..b15ddef1ec76 100644 --- a/arch/m68k/platform/68328/timers.c +++ b/arch/m68k/platform/68328/timers.c @@ -20,6 +20,7 @@ #include <linux/interrupt.h> #include <linux/irq.h> #include <linux/clocksource.h> +#include <linux/rtc.h> #include <asm/setup.h> #include <asm/system.h> #include <asm/pgtable.h> @@ -119,14 +120,17 @@ void hw_timer_init(void) /***************************************************************************/ -void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec) +int m68328_hwclk(int set, struct rtc_time *t) { - long now = RTCTIME; - - *year = *mon = *day = 1; - *hour = (now >> 24) % 24; - *min = (now >> 16) % 60; - *sec = now % 60; + 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; } /***************************************************************************/ diff --git a/arch/m68k/platform/68360/config.c b/arch/m68k/platform/68360/config.c index 9dd5bca38749..599a5949f320 100644 --- a/arch/m68k/platform/68360/config.c +++ b/arch/m68k/platform/68360/config.c @@ -103,11 +103,6 @@ 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 @@ -181,6 +176,5 @@ void config_BSP(char *command, int len) scc1_hwaddr = "\00\01\02\03\04\05"; #endif - mach_gettod = BSP_gettod; - mach_reset = BSP_reset; + mach_reset = BSP_reset; } diff --git a/arch/m68k/platform/68360/ints.c b/arch/m68k/platform/68360/ints.c index 7b40202d9638..8cd42692331b 100644 --- a/arch/m68k/platform/68360/ints.c +++ b/arch/m68k/platform/68360/ints.c @@ -32,8 +32,6 @@ 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/arch/m68k/platform/68EZ328/config.c b/arch/m68k/platform/68EZ328/config.c index 1be1a16f6896..dd2c53554341 100644 --- a/arch/m68k/platform/68EZ328/config.c +++ b/arch/m68k/platform/68EZ328/config.c @@ -15,6 +15,7 @@ #include <linux/types.h> #include <linux/kernel.h> +#include <linux/rtc.h> #include <asm/system.h> #include <asm/pgtable.h> #include <asm/machdep.h> @@ -25,7 +26,7 @@ /***************************************************************************/ -void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); +int m68328_hwclk(int set, struct rtc_time *t); /***************************************************************************/ @@ -69,7 +70,7 @@ void config_BSP(char *command, int len) else command[0] = 0; #endif - mach_gettod = m68328_timer_gettod; + mach_hwclk = m68328_hwclk; mach_reset = m68ez328_reset; } diff --git a/arch/m68k/platform/68VZ328/config.c b/arch/m68k/platform/68VZ328/config.c index eabaabe8af36..25ec673edc25 100644 --- a/arch/m68k/platform/68VZ328/config.c +++ b/arch/m68k/platform/68VZ328/config.c @@ -20,6 +20,7 @@ #include <linux/netdevice.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/rtc.h> #include <asm/system.h> #include <asm/pgtable.h> @@ -33,7 +34,7 @@ /***************************************************************************/ -void m68328_timer_gettod(int *year, int *mon, int *day, int *hour, int *min, int *sec); +int m68328_hwclk(int set, struct rtc_time *t); /***************************************************************************/ /* Init Drangon Engine hardware */ @@ -181,7 +182,7 @@ void config_BSP(char *command, int size) init_hardware(command, size); - mach_gettod = m68328_timer_gettod; + mach_hwclk = m68328_hwclk; mach_reset = m68vz328_reset; } diff --git a/arch/m68k/platform/coldfire/Makefile b/arch/m68k/platform/coldfire/Makefile index a8967baabd72..a0815c61dec1 100644 --- a/arch/m68k/platform/coldfire/Makefile +++ b/arch/m68k/platform/coldfire/Makefile @@ -14,18 +14,18 @@ asflags-$(CONFIG_FULLDEBUG) := -DDEBUGGER_COMPATIBLE_CACHE=1 -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_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_M5272) += timers.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_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_M54xx) += sltimers.o intc-2.o obj-y += pinmux.o gpio.o diff --git a/arch/m68k/platform/coldfire/device.c b/arch/m68k/platform/coldfire/device.c new file mode 100644 index 000000000000..fa50c48292ff --- /dev/null +++ b/arch/m68k/platform/coldfire/device.c @@ -0,0 +1,318 @@ +/* + * device.c -- common ColdFire SoC device support + * + * (C) Copyright 2011, Greg Ungerer <gerg@uclinux.org> + * + * 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/spi/spi.h> +#include <linux/gpio.h> +#include <asm/traps.h> +#include <asm/coldfire.h> +#include <asm/mcfsim.h> +#include <asm/mcfuart.h> +#include <asm/mcfqspi.h> + +/* + * 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/arch/m68k/platform/coldfire/head.S b/arch/m68k/platform/coldfire/head.S index 38f04a3f6207..c3db70ed33b3 100644 --- a/arch/m68k/platform/coldfire/head.S +++ b/arch/m68k/platform/coldfire/head.S @@ -158,6 +158,10 @@ _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/arch/m68k/platform/coldfire/pit.c b/arch/m68k/platform/coldfire/pit.c index 02663d25822d..e62dbbcb10f6 100644 --- a/arch/m68k/platform/coldfire/pit.c +++ b/arch/m68k/platform/coldfire/pit.c @@ -149,7 +149,7 @@ static struct clocksource pit_clk = { /***************************************************************************/ -void hw_timer_init(void) +void hw_timer_init(irq_handler_t handler) { cf_pit_clockevent.cpumask = cpumask_of(smp_processor_id()); cf_pit_clockevent.mult = div_sc(FREQ, NSEC_PER_SEC, 32); diff --git a/arch/m68k/platform/coldfire/reset.c b/arch/m68k/platform/coldfire/reset.c new file mode 100644 index 000000000000..933e54eacc69 --- /dev/null +++ b/arch/m68k/platform/coldfire/reset.c @@ -0,0 +1,50 @@ +/* + * reset.c -- common ColdFire SoC reset support + * + * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org> + * + * 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/io.h> +#include <asm/machdep.h> +#include <asm/coldfire.h> +#include <asm/mcfsim.h> + +/* + * 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/arch/m68k/platform/coldfire/sltimers.c b/arch/m68k/platform/coldfire/sltimers.c index 54e1452f853a..2027fc20b876 100644 --- a/arch/m68k/platform/coldfire/sltimers.c +++ b/arch/m68k/platform/coldfire/sltimers.c @@ -81,12 +81,14 @@ 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 arch_timer_interrupt(irq, dummy); + return timer_interrupt(irq, dummy); } static struct irqaction mcfslt_timer_irq = { @@ -121,7 +123,7 @@ static struct clocksource mcfslt_clk = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -void hw_timer_init(void) +void hw_timer_init(irq_handler_t handler) { mcfslt_cycles_per_jiffy = MCF_BUSCLK / HZ; /* @@ -136,6 +138,7 @@ void hw_timer_init(void) /* 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/arch/m68k/platform/coldfire/timers.c b/arch/m68k/platform/coldfire/timers.c index 0d90da32fcdb..ed96ce50d79f 100644 --- a/arch/m68k/platform/coldfire/timers.c +++ b/arch/m68k/platform/coldfire/timers.c @@ -47,6 +47,27 @@ 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) @@ -55,7 +76,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 arch_timer_interrupt(irq, dummy); + return timer_interrupt(irq, dummy); } /***************************************************************************/ @@ -94,7 +115,7 @@ static struct clocksource mcftmr_clk = { /***************************************************************************/ -void hw_timer_init(void) +void hw_timer_init(irq_handler_t handler) { __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR)); mcftmr_cycles_per_jiffy = FREQ / HZ; @@ -110,6 +131,8 @@ void hw_timer_init(void) 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/arch/m68k/platform/coldfire/vectors.c b/arch/m68k/platform/coldfire/vectors.c index 3a7cc524ecd3..a4dbdecbec7a 100644 --- a/arch/m68k/platform/coldfire/vectors.c +++ b/arch/m68k/platform/coldfire/vectors.c @@ -33,8 +33,6 @@ asmlinkage void dbginterrupt_c(struct frame *fp) /***************************************************************************/ -extern e_vector *_ramvec; - /* Assembler routines */ asmlinkage void buserr(void); asmlinkage void trap(void); diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 303703d716fe..d219ebecabf0 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -134,6 +134,7 @@ 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 @@ -377,13 +378,16 @@ config CRASH_DUMP The same kernel binary can be used as production kernel and dump capture kernel. -config PHYP_DUMP - bool "Hypervisor-assisted dump (EXPERIMENTAL)" - depends on PPC_PSERIES && EXPERIMENTAL +config FA_DUMP + bool "Firmware-assisted dump" + depends on PPC64 && PPC_RTAS && CRASH_DUMP help - Hypervisor-assisted dump is meant to be a kdump replacement - offering robustness and speed not possible without system - hypervisor assistance. + 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. If unsure, say "N" @@ -612,7 +616,7 @@ endmenu config ISA_DMA_API bool - default !PPC_ISERIES || PCI + default PCI menu "Bus options" diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 4ccb2a009f74..72d55dbc6119 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug @@ -196,13 +196,6 @@ 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/arch/powerpc/Makefile b/arch/powerpc/Makefile index b8b105c01c64..6524c6e21896 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -157,6 +157,7 @@ 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/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 8844a17ce8ed..e8461cb18d04 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile @@ -184,7 +184,6 @@ 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 @@ -247,7 +246,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 \ + cuImage.mpc8548cds_32b \ cuImage.mpc8555cds image-$(CONFIG_MPC85xx_MDS) += cuImage.mpc8568mds image-$(CONFIG_MPC85xx_DS) += cuImage.mpc8544ds \ @@ -311,12 +310,6 @@ $(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) @@ -364,7 +357,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.iseries zImage.miboot zImage.pmac zImage.pseries \ + zImage.miboot zImage.pmac zImage.pseries \ zImage.maple simpleImage.* otheros.bld *.dtb # clean up files cached by wrapper diff --git a/arch/powerpc/boot/dts/a4m072.dts b/arch/powerpc/boot/dts/a4m072.dts new file mode 100644 index 000000000000..fabe7b7d5f13 --- /dev/null +++ b/arch/powerpc/boot/dts/a4m072.dts @@ -0,0 +1,168 @@ +/* + * a4m072 board Device Tree Source + * + * Copyright (C) 2011 DENX Software Engineering GmbH + * Heiko Schocher <hs@denx.de> + * + * Copyright (C) 2007 Semihalf + * Marian Balakowicz <m8@semihalf.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/ "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/arch/powerpc/boot/dts/bluestone.dts b/arch/powerpc/boot/dts/bluestone.dts index 74876f737407..7bda373f10ef 100644 --- a/arch/powerpc/boot/dts/bluestone.dts +++ b/arch/powerpc/boot/dts/bluestone.dts @@ -33,7 +33,7 @@ aliases { ethernet0 = &EMAC0; serial0 = &UART0; - //serial1 = &UART1; --gcl missing UART1 label + serial1 = &UART1; }; cpus { @@ -52,7 +52,7 @@ d-cache-size = <32768>; dcr-controller; dcr-access-method = "native"; - //next-level-cache = <&L2C0>; --gcl missing L2C0 label + next-level-cache = <&L2C0>; }; }; @@ -117,6 +117,16 @@ 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>; @@ -182,6 +192,53 @@ 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 { @@ -195,11 +252,36 @@ 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 { @@ -250,5 +332,46 @@ }; }; + 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/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi index b37da56018b6..c8b2daa40ac8 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi @@ -202,7 +202,7 @@ /include/ "pq3-etsec1-timer-0.dtsi" usb@22000 { - compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; + compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; reg = <0x22000 0x1000>; #address-cells = <1>; #size-cells = <0>; @@ -210,7 +210,7 @@ }; usb@23000 { - compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; + compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; reg = <0x23000 0x1000>; #address-cells = <1>; #size-cells = <0>; diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi index 9d8023a69d7d..579d76cb8e32 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi @@ -89,6 +89,21 @@ }; }; +&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>; @@ -134,6 +149,7 @@ /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/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi index 289f1218d755..720422d83529 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi @@ -43,7 +43,9 @@ serial0 = &serial0; serial1 = &serial1; ethernet0 = &enet0; - ethernet1 = &enet2; + ethernet1 = &enet1; + ethernet2 = &enet2; + ethernet3 = &enet3; pci0 = &pci0; pci1 = &pci1; pci2 = &pci2; diff --git a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi index a97d1263372c..0bde9ee8afaf 100644 --- a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi @@ -156,6 +156,9 @@ /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/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi index 5de5fc351314..68cc5e7f6477 100644 --- a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi @@ -142,7 +142,13 @@ /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/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi index 38ba54d1e32e..4252ef85fb7a 100644 --- a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi @@ -142,8 +142,15 @@ /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/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi index ff9ed1d87929..06216b8c0af5 100644 --- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi @@ -35,7 +35,11 @@ &lbc { #address-cells = <2>; #size-cells = <1>; - compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus"; + /* + * 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"; interrupts = <19 2 0 0>; }; @@ -199,7 +203,13 @@ /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/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi index b06bb4cc1fe8..941fa159cefb 100644 --- a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi @@ -142,6 +142,9 @@ /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/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi index 332e9e75e6c2..884e01bcb243 100644 --- a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi @@ -171,6 +171,9 @@ /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/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi index 234a399ddeb2..531eab82c6c9 100644 --- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi @@ -309,12 +309,14 @@ /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/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi index d41d08de7f7e..af4ebc8009e3 100644 --- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi @@ -336,12 +336,14 @@ /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/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi index a63edd195ae5..b3e56929eee2 100644 --- a/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi @@ -291,6 +291,12 @@ /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/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi index 914074b91a85..64b6abea8464 100644 --- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi @@ -339,12 +339,14 @@ /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/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi index a1979ae334a7..3b0650a98478 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x24000 ] * - * Copyright 2011 Freescale Semiconductor Inc. + * Copyright 2011-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: @@ -41,6 +41,7 @@ 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/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi index 4c4fdde1ec2a..96693b41f0f1 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x25000 ] * - * Copyright 2011 Freescale Semiconductor Inc. + * Copyright 2011-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: @@ -41,6 +41,7 @@ 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/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi index 4b8ab438668a..6b3fab19da1f 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x26000 ] * - * Copyright 2011 Freescale Semiconductor Inc. + * Copyright 2011-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: @@ -41,6 +41,7 @@ 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/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi index 40c9137729ae..0da592d93ddd 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi @@ -1,7 +1,7 @@ /* * PQ3 eTSEC device tree stub [ @ offsets 0x27000 ] * - * Copyright 2011 Freescale Semiconductor Inc. + * Copyright 2011-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: @@ -41,6 +41,7 @@ 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/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi b/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi index 5c8046065844..fdedf7b1fe0f 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi @@ -39,6 +39,9 @@ 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/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi index bf957a7fca2a..d4c9d5daab21 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi @@ -33,32 +33,32 @@ */ crypto@30000 { - compatible = "fsl,sec4.4", "fsl,sec4.0"; + compatible = "fsl,sec-v4.4", "fsl,sec-v4.0"; #address-cells = <1>; #size-cells = <1>; reg = <0x30000 0x10000>; interrupts = <58 2 0 0>; sec_jr0: jr@1000 { - compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; + compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; reg = <0x1000 0x1000>; interrupts = <45 2 0 0>; }; sec_jr1: jr@2000 { - compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; + compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; reg = <0x2000 0x1000>; interrupts = <45 2 0 0>; }; sec_jr2: jr@3000 { - compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; + compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; reg = <0x3000 0x1000>; interrupts = <45 2 0 0>; }; sec_jr3: jr@4000 { - compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; + compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; reg = <0x4000 0x1000>; interrupts = <45 2 0 0>; }; diff --git a/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi index b9bada6a87dc..08f42271f86a 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi @@ -53,7 +53,7 @@ timer@41100 { msi0: msi@41600 { compatible = "fsl,mpic-msi"; - reg = <0x41600 0x200>; + reg = <0x41600 0x200 0x44140 4>; 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>; + reg = <0x41800 0x200 0x45140 4>; 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>; + reg = <0x41a00 0x200 0x46140 4>; msi-available-ranges = <0 0x100>; interrupts = < 0xf0 0 0 0 diff --git a/arch/powerpc/boot/dts/ge_imp3a.dts b/arch/powerpc/boot/dts/ge_imp3a.dts new file mode 100644 index 000000000000..fefae416a097 --- /dev/null +++ b/arch/powerpc/boot/dts/ge_imp3a.dts @@ -0,0 +1,255 @@ +/* + * 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/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts index c0e450a551bf..81dd513d6308 100644 --- a/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/arch/powerpc/boot/dts/mpc836x_mds.dts @@ -405,6 +405,10 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi-phy@2 { + device_type = "tbi-phy"; + reg = <0x2>; + }; }; qeic: interrupt-controller@80 { diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts index c15881574fdc..19736222a0b9 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dts +++ b/arch/powerpc/boot/dts/mpc8536ds.dts @@ -1,7 +1,7 @@ /* * MPC8536 DS Device Tree Source * - * Copyright 2008 Freescale Semiconductor, Inc. + * Copyright 2008, 2011 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,6 +34,10 @@ 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/arch/powerpc/boot/dts/mpc8536ds.dtsi b/arch/powerpc/boot/dts/mpc8536ds.dtsi index 1462e4cf49d7..cc46dbd9746d 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dtsi +++ b/arch/powerpc/boot/dts/mpc8536ds.dtsi @@ -32,6 +32,99 @@ * 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/arch/powerpc/boot/dts/mpc8536ds_36b.dts b/arch/powerpc/boot/dts/mpc8536ds_36b.dts index 8f4b929b1d1d..f8a3b3413176 100644 --- a/arch/powerpc/boot/dts/mpc8536ds_36b.dts +++ b/arch/powerpc/boot/dts/mpc8536ds_36b.dts @@ -1,7 +1,7 @@ /* * MPC8536DS Device Tree Source (36-bit address map) * - * Copyright 2008-2009 Freescale Semiconductor, Inc. + * Copyright 2008-2009, 2011 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,7 +33,11 @@ }; lbc: localbus@ffe05000 { - reg = <0 0xffe05000 0 0x1000>; + reg = <0xf 0xffe05000 0 0x1000>; + + ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 + 0x2 0x0 0xf 0xffa00000 0x00040000 + 0x3 0x0 0xf 0xffdf0000 0x00008000>; }; board_soc: soc: soc@fffe00000 { diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts deleted file mode 100644 index 07b8dae0f46e..000000000000 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ /dev/null @@ -1,306 +0,0 @@ -/* - * 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/arch/powerpc/boot/dts/mpc8548cds.dtsi b/arch/powerpc/boot/dts/mpc8548cds.dtsi new file mode 100644 index 000000000000..c61f525e4740 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8548cds.dtsi @@ -0,0 +1,306 @@ +/* + * 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/arch/powerpc/boot/dts/mpc8548cds_32b.dts b/arch/powerpc/boot/dts/mpc8548cds_32b.dts new file mode 100644 index 000000000000..6fd63163fc6b --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8548cds_32b.dts @@ -0,0 +1,86 @@ +/* + * 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/arch/powerpc/boot/dts/mpc8548cds_36b.dts b/arch/powerpc/boot/dts/mpc8548cds_36b.dts new file mode 100644 index 000000000000..10e551b11bd6 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8548cds_36b.dts @@ -0,0 +1,86 @@ +/* + * 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/arch/powerpc/boot/dts/mpc8572ds.dtsi b/arch/powerpc/boot/dts/mpc8572ds.dtsi index c3d4fac0532a..14178944e220 100644 --- a/arch/powerpc/boot/dts/mpc8572ds.dtsi +++ b/arch/powerpc/boot/dts/mpc8572ds.dtsi @@ -41,37 +41,47 @@ bank-width = <2>; device-width = <1>; - ramdisk@0 { + partition@0 { reg = <0x0 0x03000000>; - read-only; + label = "ramdisk-nor"; }; - diagnostic@3000000 { + partition@3000000 { reg = <0x03000000 0x00e00000>; + label = "diagnostic-nor"; read-only; }; - dink@3e00000 { + partition@3e00000 { reg = <0x03e00000 0x00200000>; + label = "dink-nor"; read-only; }; - kernel@4000000 { + partition@4000000 { reg = <0x04000000 0x00400000>; - read-only; + label = "kernel-nor"; }; - jffs2@4400000 { + partition@4400000 { reg = <0x04400000 0x03b00000>; + label = "fs-nor"; + }; + + partition@7f00000 { + reg = <0x07f00000 0x00060000>; + label = "dtb-nor"; }; - dtb@7f00000 { - reg = <0x07f00000 0x00080000>; + partition@7f60000 { + reg = <0x07f60000 0x00020000>; + label = "env-nor"; read-only; }; - u-boot@7f80000 { + partition@7f80000 { reg = <0x07f80000 0x00080000>; + label = "u-boot-nor"; read-only; }; }; @@ -83,31 +93,35 @@ "fsl,elbc-fcm-nand"; reg = <0x2 0x0 0x40000>; - u-boot@0 { + partition@0 { reg = <0x0 0x02000000>; + label = "u-boot-nand"; read-only; }; - jffs2@2000000 { + partition@2000000 { reg = <0x02000000 0x10000000>; + label = "fs-nand"; }; - ramdisk@12000000 { + partition@12000000 { reg = <0x12000000 0x08000000>; - read-only; + label = "ramdisk-nand"; }; - kernel@1a000000 { + partition@1a000000 { reg = <0x1a000000 0x04000000>; + label = "kernel-nand"; }; - dtb@1e000000 { + partition@1e000000 { reg = <0x1e000000 0x01000000>; - read-only; + label = "dtb-nand"; }; - empty@1f000000 { + partition@1f000000 { reg = <0x1f000000 0x21000000>; + label = "empty-nand"; }; }; diff --git a/arch/powerpc/boot/dts/p1010rdb.dtsi b/arch/powerpc/boot/dts/p1010rdb.dtsi index d4c4a7730285..49776143a1b8 100644 --- a/arch/powerpc/boot/dts/p1010rdb.dtsi +++ b/arch/powerpc/boot/dts/p1010rdb.dtsi @@ -138,7 +138,7 @@ #size-cells = <1>; compatible = "spansion,s25sl12801"; reg = <0>; - spi-max-frequency = <50000000>; + spi-max-frequency = <40000000>; 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/arch/powerpc/boot/dts/p1020rdb-pc.dtsi b/arch/powerpc/boot/dts/p1020rdb-pc.dtsi new file mode 100644 index 000000000000..c952cd37cf6d --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc.dtsi @@ -0,0 +1,247 @@ +/* + * 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/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts new file mode 100644 index 000000000000..4de69b726dc5 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts @@ -0,0 +1,90 @@ +/* + * 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/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts new file mode 100644 index 000000000000..5237da7441bc --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts @@ -0,0 +1,90 @@ +/* + * 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/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts new file mode 100644 index 000000000000..f411515937ec --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts @@ -0,0 +1,64 @@ +/* + * 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/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts new file mode 100644 index 000000000000..a91335ad82c2 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts @@ -0,0 +1,142 @@ +/* + * 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/arch/powerpc/boot/dts/p1021rdb.dts b/arch/powerpc/boot/dts/p1021rdb.dts new file mode 100644 index 000000000000..90b6b4caa273 --- /dev/null +++ b/arch/powerpc/boot/dts/p1021rdb.dts @@ -0,0 +1,96 @@ +/* + * 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/arch/powerpc/boot/dts/p1021rdb.dtsi b/arch/powerpc/boot/dts/p1021rdb.dtsi new file mode 100644 index 000000000000..b973461ab751 --- /dev/null +++ b/arch/powerpc/boot/dts/p1021rdb.dtsi @@ -0,0 +1,236 @@ +/* + * 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/arch/powerpc/boot/dts/p1021rdb_36b.dts b/arch/powerpc/boot/dts/p1021rdb_36b.dts new file mode 100644 index 000000000000..ea6d8b5fa10b --- /dev/null +++ b/arch/powerpc/boot/dts/p1021rdb_36b.dts @@ -0,0 +1,96 @@ +/* + * 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/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts deleted file mode 100644 index ef95717db4bc..000000000000 --- a/arch/powerpc/boot/dts/p1022ds.dts +++ /dev/null @@ -1,274 +0,0 @@ -/* - * 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/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi new file mode 100644 index 000000000000..7cdb505036bb --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds.dtsi @@ -0,0 +1,234 @@ +/* + * 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/arch/powerpc/boot/dts/p1022ds_32b.dts b/arch/powerpc/boot/dts/p1022ds_32b.dts new file mode 100644 index 000000000000..d96cae00a9e3 --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds_32b.dts @@ -0,0 +1,103 @@ +/* + * 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/arch/powerpc/boot/dts/p1022ds_36b.dts b/arch/powerpc/boot/dts/p1022ds_36b.dts new file mode 100644 index 000000000000..f7aacce40bf6 --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds_36b.dts @@ -0,0 +1,103 @@ +/* + * 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/arch/powerpc/boot/dts/p1025rdb.dtsi b/arch/powerpc/boot/dts/p1025rdb.dtsi new file mode 100644 index 000000000000..cf3676fc714b --- /dev/null +++ b/arch/powerpc/boot/dts/p1025rdb.dtsi @@ -0,0 +1,286 @@ +/* + * 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/arch/powerpc/boot/dts/p1025rdb_32b.dts b/arch/powerpc/boot/dts/p1025rdb_32b.dts new file mode 100644 index 000000000000..ac5729c14eda --- /dev/null +++ b/arch/powerpc/boot/dts/p1025rdb_32b.dts @@ -0,0 +1,135 @@ +/* + * 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/arch/powerpc/boot/dts/p1025rdb_36b.dts b/arch/powerpc/boot/dts/p1025rdb_36b.dts new file mode 100644 index 000000000000..4ce4bfa0eda4 --- /dev/null +++ b/arch/powerpc/boot/dts/p1025rdb_36b.dts @@ -0,0 +1,88 @@ +/* + * 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/arch/powerpc/boot/dts/p2020rdb-pc.dtsi b/arch/powerpc/boot/dts/p2020rdb-pc.dtsi new file mode 100644 index 000000000000..c21d1c7d16cd --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb-pc.dtsi @@ -0,0 +1,241 @@ +/* + * 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/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts new file mode 100644 index 000000000000..852e5b27485d --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts @@ -0,0 +1,96 @@ +/* + * 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/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts new file mode 100644 index 000000000000..b5a56ca51cf7 --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts @@ -0,0 +1,96 @@ +/* + * 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/arch/powerpc/boot/dts/p2020rdb.dts b/arch/powerpc/boot/dts/p2020rdb.dts index eb8a6aa2bda5..153bc76bb48e 100644 --- a/arch/powerpc/boot/dts/p2020rdb.dts +++ b/arch/powerpc/boot/dts/p2020rdb.dts @@ -34,7 +34,7 @@ /* NOR and NAND Flashes */ ranges = <0x0 0x0 0x0 0xef000000 0x01000000 - 0x1 0x0 0x0 0xffa00000 0x00040000 + 0x1 0x0 0x0 0xff800000 0x00040000 0x2 0x0 0x0 0xffb00000 0x00020000>; nor@0,0 { @@ -157,7 +157,7 @@ #size-cells = <1>; compatible = "spansion,s25sl12801"; reg = <0>; - spi-max-frequency = <50000000>; + spi-max-frequency = <40000000>; partition@0 { /* 512KB for u-boot Bootloader Image */ diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index f090e6d2907e..6761c746048d 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper @@ -144,6 +144,7 @@ tmp=$tmpdir/zImage.$$.o ksection=.kernel:vmlinux.strip isection=.kernel:initrd link_address='0x400000' +make_space=y case "$platform" in pseries) @@ -210,6 +211,7 @@ ps3) ksection=.kernel:vmlinux.bin isection=.kernel:initrd link_address='' + make_space=n pie= ;; ep88xc|ep405|ep8248e) @@ -278,17 +280,19 @@ else rm -f $vmz.$$ fi -# Round the size to next higher MB limit -round_size=$(((strip_size + 0xfffff) & 0xfff00000)) +if [ "$make_space" = "y" ]; then + # 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 + 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 fi vmz="$vmz$gzip" diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig new file mode 100644 index 000000000000..f8c51a4ab995 --- /dev/null +++ b/arch/powerpc/configs/85xx/ge_imp3a_defconfig @@ -0,0 +1,257 @@ +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/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig index d41857a5152d..da731c2fe984 100644 --- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig +++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig @@ -131,6 +131,7 @@ 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/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig index 38303ec11bcd..2149360a1e62 100644 --- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig @@ -132,6 +132,7 @@ 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/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig index 98533973d20f..af2e8e1edba6 100644 --- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig @@ -183,6 +183,8 @@ 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/arch/powerpc/configs/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig deleted file mode 100644 index 27c46d679968..000000000000 --- a/arch/powerpc/configs/iseries_defconfig +++ /dev/null @@ -1,236 +0,0 @@ -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/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig index 2a1320fb2723..6640a35bebb7 100644 --- a/arch/powerpc/configs/mpc5200_defconfig +++ b/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,15 +13,12 @@ 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 @@ -36,23 +33,20 @@ 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 @@ -61,11 +55,10 @@ CONFIG_ATA=y CONFIG_PATA_MPC52xx=y CONFIG_PATA_PLATFORM=y CONFIG_NETDEVICES=y -CONFIG_LXT_PHY=y -CONFIG_NET_ETHERNET=y CONFIG_FEC_MPC52xx=y -# CONFIG_NETDEV_1000 is not set -# CONFIG_NETDEV_10000 is not set +CONFIG_AMD_PHY=y +CONFIG_LXT_PHY=y +CONFIG_FIXED_PHY=y # CONFIG_INPUT_KEYBOARD is not set # CONFIG_INPUT_MOUSE is not set # CONFIG_SERIO is not set @@ -80,11 +73,17 @@ 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 @@ -124,10 +123,11 @@ 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,5 +145,4 @@ 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/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index f37a2ab48881..5fb0c8a94811 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig @@ -1,4 +1,5 @@ CONFIG_PPC_85xx=y +CONFIG_PHYS_64BIT=y CONFIG_EXPERIMENTAL=y CONFIG_SYSVIPC=y CONFIG_POSIX_MQUEUE=y diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index abdcd317cda7..fb51bc90edd2 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig @@ -1,4 +1,5 @@ CONFIG_PPC_85xx=y +CONFIG_PHYS_64BIT=y CONFIG_SMP=y CONFIG_NR_CPUS=8 CONFIG_EXPERIMENTAL=y diff --git a/arch/powerpc/include/asm/abs_addr.h b/arch/powerpc/include/asm/abs_addr.h index 5ab0b71531be..9d92ba04b033 100644 --- a/arch/powerpc/include/asm/abs_addr.h +++ b/arch/powerpc/include/asm/abs_addr.h @@ -17,7 +17,6 @@ #include <asm/types.h> #include <asm/page.h> #include <asm/prom.h> -#include <asm/firmware.h> struct mschunks_map { unsigned long num_chunks; @@ -46,30 +45,12 @@ static inline unsigned long addr_to_chunk(unsigned long addr) static inline unsigned long phys_to_abs(unsigned long 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); + return pa; } /* 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/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 02e41b53488d..14174e838ad9 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -212,6 +212,36 @@ 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) @@ -467,7 +497,34 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) return t != u; } -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) +/** + * 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; +} #endif /* __powerpc64__ */ diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index ad55a1ccb9fb..b9219e99bd2a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h @@ -390,6 +390,10 @@ 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 */ @@ -442,7 +446,7 @@ extern const char *powerpc_base_platform; #ifdef __powerpc64__ #ifdef CONFIG_PPC_BOOK3E -#define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500 | CPU_FTRS_A2) +#define CPU_FTRS_POSSIBLE (CPU_FTRS_E6500 | CPU_FTRS_E5500 | CPU_FTRS_A2) #else #define CPU_FTRS_POSSIBLE \ (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ @@ -483,7 +487,7 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC | - CPU_FTRS_E5500 | + CPU_FTRS_E5500 | CPU_FTRS_E6500 | #endif 0, }; @@ -491,7 +495,7 @@ enum { #ifdef __powerpc64__ #ifdef CONFIG_PPC_BOOK3E -#define CPU_FTRS_ALWAYS (CPU_FTRS_E5500 & CPU_FTRS_A2) +#define CPU_FTRS_ALWAYS (CPU_FTRS_E6500 & CPU_FTRS_E5500 & CPU_FTRS_A2) #else #define CPU_FTRS_ALWAYS \ (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \ @@ -528,7 +532,7 @@ enum { #endif #ifdef CONFIG_E500 CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC & - CPU_FTRS_E5500 & + CPU_FTRS_E5500 & CPU_FTRS_E6500 & #endif CPU_FTRS_POSSIBLE, }; diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h index d57c08acedfc..63d5ca49cece 100644 --- a/arch/powerpc/include/asm/device.h +++ b/arch/powerpc/include/asm/device.h @@ -31,6 +31,9 @@ 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/arch/powerpc/include/asm/dma.h b/arch/powerpc/include/asm/dma.h index a7e06e25c708..adadb9943610 100644 --- a/arch/powerpc/include/asm/dma.h +++ b/arch/powerpc/include/asm/dma.h @@ -34,8 +34,6 @@ /* 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 @@ -354,7 +352,5 @@ 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/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 66ea9b8b95c5..d60f99814ffb 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/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,44 +31,105 @@ struct device_node; #ifdef CONFIG_EEH -extern int eeh_subsystem_enabled; +/* + * 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; +} -/* 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) +/* + * 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. */ +/* + * 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 *); /** @@ -87,8 +148,25 @@ 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/arch/powerpc/include/asm/eeh_event.h b/arch/powerpc/include/asm/eeh_event.h index cc3cb04539ac..c68b012b7797 100644 --- a/arch/powerpc/include/asm/eeh_event.h +++ b/arch/powerpc/include/asm/eeh_event.h @@ -1,6 +1,4 @@ /* - * 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 @@ -22,32 +20,19 @@ #define ASM_POWERPC_EEH_EVENT_H #ifdef __KERNEL__ -/** 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. +/* + * 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; - struct device_node *dn; /* struct device node */ - struct pci_dev *dev; /* affected device */ + struct list_head list; /* to form event queue */ + struct eeh_dev *edev; /* EEH device */ }; -/** - * 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 *); +int eeh_send_failure_event(struct eeh_dev *edev); +struct eeh_dev *handle_eeh_events(struct eeh_event *); #endif /* __KERNEL__ */ #endif /* ASM_POWERPC_EEH_EVENT_H */ diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 8057f4f6980f..548da3aa0a30 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h @@ -232,23 +232,30 @@ label##_hv: \ EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ EXC_HV, KVMTEST, vec) -#define __SOFTEN_TEST(h) \ +/* 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) \ lbz r10,PACASOFTIRQEN(r13); \ cmpwi r10,0; \ + li r10,SOFTEN_VALUE_##vec; \ beq masked_##h##interrupt -#define _SOFTEN_TEST(h) __SOFTEN_TEST(h) +#define _SOFTEN_TEST(h, vec) __SOFTEN_TEST(h, vec) #define SOFTEN_TEST_PR(vec) \ KVMTEST_PR(vec); \ - _SOFTEN_TEST(EXC_STD) + _SOFTEN_TEST(EXC_STD, vec) #define SOFTEN_TEST_HV(vec) \ KVMTEST(vec); \ - _SOFTEN_TEST(EXC_HV) + _SOFTEN_TEST(EXC_HV, vec) #define SOFTEN_TEST_HV_201(vec) \ KVMTEST(vec); \ - _SOFTEN_TEST(EXC_STD) + _SOFTEN_TEST(EXC_STD, vec) #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ HMT_MEDIUM; \ @@ -272,73 +279,55 @@ label##_hv: \ _MASKABLE_EXCEPTION_PSERIES(vec, label, \ EXC_HV, SOFTEN_TEST_HV) -#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 */ +/* + * 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) +/* 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 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 +#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) /* * Like STD_EXCEPTION_COMMON, but for exceptions that can occur - * in the idle task and therefore need the special idle handling. + * in the idle task and therefore need the special idle handling + * (finish nap and runlatch) */ -#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 +#define STD_EXCEPTION_COMMON_ASYNC(trap, label, hdlr) \ + EXCEPTION_COMMON(trap, label, hdlr, ret_from_except_lite, \ + FINISH_NAP;RUNLATCH_ON;DISABLE_INTS) /* * When the idle code in power4_idle puts the CPU into NAP mode, diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h new file mode 100644 index 000000000000..88dbf9659185 --- /dev/null +++ b/arch/powerpc/include/asm/fadump.h @@ -0,0 +1,218 @@ +/* + * 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 <mahesh@linux.vnet.ibm.com> + */ + +#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/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index 14db29b18d0e..ad0b751b0d78 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h @@ -41,7 +41,6 @@ #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) @@ -65,8 +64,6 @@ 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, @@ -79,9 +76,6 @@ 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 @@ -99,9 +93,6 @@ 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/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index bebd12463ec9..ce04530d2000 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h @@ -4,7 +4,7 @@ * Authors: Jeff Brown * Timur Tabi <timur@freescale.com> * - * Copyright 2004,2007 Freescale Semiconductor, Inc + * Copyright 2004,2007,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 @@ -114,6 +114,10 @@ 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/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index bb712c9488b3..51010bfc792e 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h @@ -11,6 +11,27 @@ #include <asm/ptrace.h> #include <asm/processor.h> +#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 @@ -42,7 +63,6 @@ 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) { @@ -68,16 +88,33 @@ 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(mfmsr() | MSR_EE, 1) -#define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) +#define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1) +#define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1) #endif -#define hard_irq_disable() \ - do { \ - __hard_irq_disable(); \ - get_paca()->soft_enabled = 0; \ - get_paca()->hard_enabled = 0; \ - } while(0) +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; +} #else /* CONFIG_PPC64 */ @@ -139,6 +176,13 @@ 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 @@ -149,5 +193,6 @@ static inline bool arch_irqs_disabled(void) */ struct irq_chip; +#endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _ASM_POWERPC_HW_IRQ_H */ diff --git a/arch/powerpc/include/asm/irqflags.h b/arch/powerpc/include/asm/irqflags.h index b0b06d85788d..6f9b6e23dc5a 100644 --- a/arch/powerpc/include/asm/irqflags.h +++ b/arch/powerpc/include/asm/irqflags.h @@ -39,24 +39,31 @@ #define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) #define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) -#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: +/* + * 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: + #else #define TRACE_ENABLE_INTS #define TRACE_DISABLE_INTS -#define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) -#define TRACE_AND_RESTORE_IRQ(en) \ - stb en,PACASOFTIRQEN(r13) + +#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) #endif #endif diff --git a/arch/powerpc/include/asm/iseries/alpaca.h b/arch/powerpc/include/asm/iseries/alpaca.h deleted file mode 100644 index c0cce6727a69..000000000000 --- a/arch/powerpc/include/asm/iseries/alpaca.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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/arch/powerpc/include/asm/iseries/hv_call.h b/arch/powerpc/include/asm/iseries/hv_call.h deleted file mode 100644 index 162d653ad51f..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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 <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> -#include <asm/paca.h> - -/* 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/arch/powerpc/include/asm/iseries/hv_call_event.h b/arch/powerpc/include/asm/iseries/hv_call_event.h deleted file mode 100644 index cc029d388e11..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call_event.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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 <linux/types.h> -#include <linux/dma-mapping.h> - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> -#include <asm/abs_addr.h> - -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/arch/powerpc/include/asm/iseries/hv_call_sc.h b/arch/powerpc/include/asm/iseries/hv_call_sc.h deleted file mode 100644 index f5d210959250..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call_sc.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 <linux/types.h> - -#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/arch/powerpc/include/asm/iseries/hv_call_xm.h b/arch/powerpc/include/asm/iseries/hv_call_xm.h deleted file mode 100644 index 392ac3f54df0..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call_xm.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -#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/arch/powerpc/include/asm/iseries/hv_lp_config.h b/arch/powerpc/include/asm/iseries/hv_lp_config.h deleted file mode 100644 index a006fd1e4a2c..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_lp_config.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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 <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -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/arch/powerpc/include/asm/iseries/hv_lp_event.h b/arch/powerpc/include/asm/iseries/hv_lp_event.h deleted file mode 100644 index 8f5da7d77202..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_lp_event.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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 <asm/types.h> -#include <asm/ptrace.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_call_event.h> - -/* - * 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/arch/powerpc/include/asm/iseries/hv_types.h b/arch/powerpc/include/asm/iseries/hv_types.h deleted file mode 100644 index c3e6d2a1d1c3..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_types.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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 <asm/types.h> - -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/arch/powerpc/include/asm/iseries/iommu.h b/arch/powerpc/include/asm/iseries/iommu.h deleted file mode 100644 index 1b9692c60899..000000000000 --- a/arch/powerpc/include/asm/iseries/iommu.h +++ /dev/null @@ -1,37 +0,0 @@ -#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/arch/powerpc/include/asm/iseries/it_lp_queue.h b/arch/powerpc/include/asm/iseries/it_lp_queue.h deleted file mode 100644 index 428278838821..000000000000 --- a/arch/powerpc/include/asm/iseries/it_lp_queue.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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 <asm/types.h> -#include <asm/ptrace.h> - -#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/arch/powerpc/include/asm/iseries/lpar_map.h b/arch/powerpc/include/asm/iseries/lpar_map.h deleted file mode 100644 index 5e9f3e128ee2..000000000000 --- a/arch/powerpc/include/asm/iseries/lpar_map.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 <asm/types.h> - -#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/arch/powerpc/include/asm/iseries/mf.h b/arch/powerpc/include/asm/iseries/mf.h deleted file mode 100644 index eb851a9c9e5c..000000000000 --- a/arch/powerpc/include/asm/iseries/mf.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 <linux/types.h> - -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_call_event.h> - -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/arch/powerpc/include/asm/iseries/vio.h b/arch/powerpc/include/asm/iseries/vio.h deleted file mode 100644 index f9ac0d00b951..000000000000 --- a/arch/powerpc/include/asm/iseries/vio.h +++ /dev/null @@ -1,265 +0,0 @@ -/* -*- linux-c -*- - * - * iSeries Virtual I/O Message Path header - * - * Authors: Dave Boutcher <boutcher@us.ibm.com> - * Ryan Arnold <ryanarn@us.ibm.com> - * Colin Devilbiss <devilbis@us.ibm.com> - * - * (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 <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> - -/* - * 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/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index e0298d26ce5d..a76254af0aaa 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h @@ -41,15 +41,7 @@ * 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/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index a5b7c56237f9..c65b9294376e 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h @@ -273,7 +273,6 @@ 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 */ @@ -349,8 +348,6 @@ 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 */ @@ -363,15 +360,11 @@ 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 -/* Disable resetting of the MPIC. - * NOTE: This flag trumps MPIC_WANTS_RESET. - */ +/* Do not reset the MPIC during initialization */ #define MPIC_NO_RESET 0x00004000 /* Freescale MPIC (compatible includes "fsl,mpic") */ #define MPIC_FSL 0x00008000 diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h new file mode 100644 index 000000000000..3ec37dc9003e --- /dev/null +++ b/arch/powerpc/include/asm/mpic_msgr.h @@ -0,0 +1,132 @@ +/* + * 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 <linux/types.h> +#include <linux/spinlock.h> + +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/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 269c05a36d91..daf813fea91f 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/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 hard_enabled; /* set if irqs are enabled in MSR */ + u8 irq_happened; /* irq happened while soft-disabled */ 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/arch/powerpc/include/asm/phyp_dump.h b/arch/powerpc/include/asm/phyp_dump.h deleted file mode 100644 index fa74c6c3e106..000000000000 --- a/arch/powerpc/include/asm/phyp_dump.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index 6d422979ebaf..e660b37aa7d0 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h @@ -47,92 +47,21 @@ 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); -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 *); - +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 *); 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); - -/** - * 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_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); void eeh_sysfs_add_device(struct pci_dev *pdev); void eeh_sysfs_remove_device(struct pci_dev *pdev); diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 368f72f79808..50f73aa2ba21 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h @@ -60,6 +60,8 @@ 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/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 7fdc2c0b7fa0..b1a215eabef6 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1079,30 +1079,12 @@ #define proc_trap() asm volatile("trap") -#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) +#define __get_SP() ({unsigned long sp; \ + asm volatile("mr %0,1": "=r" (sp)); sp;}) 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/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 500fe1dc43e6..8a97aa7289d3 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h @@ -62,6 +62,7 @@ #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/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h index f9611bd69ed2..7124fc06ad47 100644 --- a/arch/powerpc/include/asm/spinlock.h +++ b/arch/powerpc/include/asm/spinlock.h @@ -23,7 +23,6 @@ #ifdef CONFIG_PPC64 #include <asm/paca.h> #include <asm/hvcall.h> -#include <asm/iseries/hv_call.h> #endif #include <asm/asm-compat.h> #include <asm/synch.h> @@ -95,12 +94,12 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) * value. */ -#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) +#if defined(CONFIG_PPC_SPLPAR) /* 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 || ISERIES */ +#else /* SPLPAR */ #define __spin_yield(x) barrier() #define __rw_yield(x) barrier() #define SHARED_PROCESSOR 0 diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h index c377457d1b89..a02883d5af43 100644 --- a/arch/powerpc/include/asm/system.h +++ b/arch/powerpc/include/asm/system.h @@ -550,5 +550,43 @@ 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/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 964714940961..4a741c7efd02 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h @@ -110,7 +110,6 @@ 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<<TIF_SYSCALL_TRACE) @@ -141,11 +140,13 @@ static inline struct thread_info *current_thread_info(void) #define TLF_SLEEPING 1 /* suspend code enabled SLEEP mode */ #define TLF_RESTORE_SIGMASK 2 /* Restore signal mask in do_signal */ #define TLF_LAZY_MMU 3 /* tlb_batch is active */ +#define TLF_RUNLATCH 4 /* Is the runlatch enabled? */ #define _TLF_NAPPING (1 << TLF_NAPPING) #define _TLF_SLEEPING (1 << TLF_SLEEPING) #define _TLF_RESTORE_SIGMASK (1 << TLF_RESTORE_SIGMASK) #define _TLF_LAZY_MMU (1 << TLF_LAZY_MMU) +#define _TLF_RUNLATCH (1 << TLF_RUNLATCH) #ifndef __ASSEMBLY__ #define HAVE_SET_RESTORE_SIGMASK 1 @@ -156,6 +157,12 @@ static inline void set_restore_sigmask(void) set_bit(TIF_SIGPENDING, &ti->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/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h index 7eb10fb96cd0..2136f58a54e8 100644 --- a/arch/powerpc/include/asm/time.h +++ b/arch/powerpc/include/asm/time.h @@ -18,11 +18,6 @@ #include <linux/percpu.h> #include <asm/processor.h> -#ifdef CONFIG_PPC_ISERIES -#include <asm/paca.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_call.h> -#endif /* time.c */ extern unsigned long tb_ticks_per_jiffy; @@ -167,15 +162,6 @@ static inline void set_dec(int val) #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 */ } @@ -217,7 +203,6 @@ 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/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index ee728e433aa2..f5808a35688c 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -60,6 +60,7 @@ 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 @@ -113,15 +114,6 @@ 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/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 04caee7d9bc1..cc492e48ddfa 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -46,9 +46,6 @@ #include <asm/hvcall.h> #include <asm/xics.h> #endif -#ifdef CONFIG_PPC_ISERIES -#include <asm/iseries/alpaca.h> -#endif #ifdef CONFIG_PPC_POWERNV #include <asm/opal.h> #endif @@ -147,7 +144,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(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled)); + DEFINE(PACAIRQHAPPENED, offsetof(struct paca_struct, irq_happened)); DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); #ifdef CONFIG_PPC_MM_SLICES DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct, @@ -384,17 +381,6 @@ 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/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 81db9e2a8a20..138ae183c440 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c @@ -1816,7 +1816,7 @@ static struct cpu_spec __initdata cpu_specs[] = { .platform = "ppc440", }, { /* 464 in APM821xx */ - .pvr_mask = 0xffffff00, + .pvr_mask = 0xfffffff0, .pvr_value = 0x12C41C80, .cpu_name = "APM821XX", .cpu_features = CPU_FTRS_44X, @@ -2019,6 +2019,24 @@ 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/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 2cc451aaaca7..5b25c8060fd6 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c @@ -37,6 +37,8 @@ void doorbell_exception(struct pt_regs *regs) irq_enter(); + may_hard_irq_enable(); + smp_ipi_demux(); irq_exit(); diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 866462cbe2d8..f8a7a1a1a9f4 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -32,6 +32,7 @@ #include <asm/ptrace.h> #include <asm/irqflags.h> #include <asm/ftrace.h> +#include <asm/hw_irq.h> /* * System calls. @@ -115,39 +116,33 @@ BEGIN_FW_FTR_SECTION END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) #endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */ -#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 */ + /* + * 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 - /* Hard enable interrupts */ #ifdef CONFIG_PPC_BOOK3E wrteei 1 #else - mfmsr r11 + ld r11,PACAKMSR(r13) 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) @@ -198,16 +193,14 @@ 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 - mfmsr r10 - rldicl r10,r10,48,1 - rotldi r10,r10,16 + ld r10,PACAKMSR(r13) mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ @@ -319,7 +312,7 @@ syscall_exit_work: #ifdef CONFIG_PPC_BOOK3E wrteei 1 #else - mfmsr r10 + ld r10,PACAKMSR(r13) ori r10,r10,MSR_EE mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ @@ -565,10 +558,8 @@ _GLOBAL(ret_from_except_lite) #ifdef CONFIG_PPC_BOOK3E wrteei 0 #else - mfmsr r10 /* Get current interrupt state */ - rldicl r9,r10,48,1 /* clear MSR_EE */ - rotldi r9,r9,16 - mtmsrd r9,1 /* Update machine state */ + ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */ + mtmsrd r10,1 /* Update machine state */ #endif /* CONFIG_PPC_BOOK3E */ #ifdef CONFIG_PREEMPT @@ -591,25 +582,74 @@ _GLOBAL(ret_from_except_lite) ld r4,TI_FLAGS(r9) andi. r0,r4,_TIF_USER_WORK_MASK bne do_work -#endif +#endif /* !CONFIG_PREEMPT */ + .globl fast_exc_return_irq +fast_exc_return_irq: restore: -BEGIN_FW_FTR_SECTION + /* + * This is the main kernel exit path, we first check if we + * have to change our interrupt state. + */ ld r5,SOFTE(r1) -FW_FTR_SECTION_ELSE - b .Liseries_check_pending_irqs -ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES) -2: - TRACE_AND_RESTORE_IRQ(r5); + 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 - /* 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) +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 + /* + * 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); + + /* + * 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 @@ -623,28 +663,18 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES) 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. */ - mfmsr r4 - andc r4,r4,r0 /* r0 contains MSR_RI here */ + ld r4,PACAKMSR(r13) /* Get kernel MSR without EE */ + 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 + * userspace the value stored in the stack frame may belong to + * another CPU. */ andi. r0,r3,MSR_PR beq 1f @@ -669,30 +699,55 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) #endif /* CONFIG_PPC_BOOK3E */ -.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 + /* + * 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) + /* + * 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? */ @@ -705,31 +760,22 @@ do_work: crandc eq,cr1*4+eq,eq bne restore - /* 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 + /* + * Here we are preempting the current task. We want to make + * sure we are soft-disabled first */ - li r0,0 - stb r0,PACASOFTIRQEN(r13) - stb r0,PACAHARDIRQEN(r13) - TRACE_DISABLE_INTS - - /* Call the scheduler with soft IRQs off */ + SOFT_DISABLE_INTS(r3,r4) 1: bl .preempt_schedule_irq /* Hard-disable interrupts again (and update PACA) */ #ifdef CONFIG_PPC_BOOK3E wrteei 0 #else - mfmsr r10 - rldicl r10,r10,48,1 - rotldi r10,r10,16 + ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */ mtmsrd r10,1 #endif /* CONFIG_PPC_BOOK3E */ - li r0,0 - stb r0,PACAHARDIRQEN(r13) + li r0,PACA_IRQ_HARD_DIS + stb r0,PACAIRQHAPPENED(r13) /* Re-test flags and eventually loop */ clrrdi r9,r1,THREAD_SHIFT @@ -751,14 +797,12 @@ user_work: andi. r0,r4,_TIF_NEED_RESCHED beq 1f - li r5,1 - TRACE_AND_RESTORE_IRQ(r5); + bl .restore_interrupts bl .schedule b .ret_from_except_lite 1: bl .save_nvgprs - li r5,1 - TRACE_AND_RESTORE_IRQ(r5); + bl .restore_interrupts addi r3,r1,STACK_FRAME_OVERHEAD bl .do_notify_resume b .ret_from_except diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 429983c06f91..7215cc2495df 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S @@ -24,6 +24,7 @@ #include <asm/ptrace.h> #include <asm/ppc-opcode.h> #include <asm/mmu.h> +#include <asm/hw_irq.h> /* XXX This will ultimately add space for a special exception save * structure used to save things like SRR0/SRR1, SPRGs, MAS, etc... @@ -77,59 +78,55 @@ #define SPRN_MC_SRR1 SPRN_MCSRR1 #define NORMAL_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, GEN, addition##_GEN) + EXCEPTION_PROLOG(n, GEN, addition##_GEN(n)) #define CRIT_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, CRIT, addition##_CRIT) + EXCEPTION_PROLOG(n, CRIT, addition##_CRIT(n)) #define DBG_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, DBG, addition##_DBG) + EXCEPTION_PROLOG(n, DBG, addition##_DBG(n)) #define MC_EXCEPTION_PROLOG(n, addition) \ - EXCEPTION_PROLOG(n, MC, addition##_MC) + EXCEPTION_PROLOG(n, MC, addition##_MC(n)) /* Variants of the "addition" argument for the prolog */ -#define PROLOG_ADDITION_NONE_GEN -#define PROLOG_ADDITION_NONE_CRIT -#define PROLOG_ADDITION_NONE_DBG -#define PROLOG_ADDITION_NONE_MC +#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_MASKABLE_GEN \ +#define PROLOG_ADDITION_MASKABLE_GEN(n) \ lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ cmpwi cr0,r11,0; /* yes -> go out of line */ \ - beq masked_interrupt_book3e; + beq masked_interrupt_book3e_##n -#define PROLOG_ADDITION_2REGS_GEN \ +#define PROLOG_ADDITION_2REGS_GEN(n) \ std r14,PACA_EXGEN+EX_R14(r13); \ std r15,PACA_EXGEN+EX_R15(r13) -#define PROLOG_ADDITION_1REG_GEN \ +#define PROLOG_ADDITION_1REG_GEN(n) \ std r14,PACA_EXGEN+EX_R14(r13); -#define PROLOG_ADDITION_2REGS_CRIT \ +#define PROLOG_ADDITION_2REGS_CRIT(n) \ std r14,PACA_EXCRIT+EX_R14(r13); \ std r15,PACA_EXCRIT+EX_R15(r13) -#define PROLOG_ADDITION_2REGS_DBG \ +#define PROLOG_ADDITION_2REGS_DBG(n) \ std r14,PACA_EXDBG+EX_R14(r13); \ std r15,PACA_EXDBG+EX_R15(r13) -#define PROLOG_ADDITION_2REGS_MC \ +#define PROLOG_ADDITION_2REGS_MC(n) \ 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 */ \ @@ -167,20 +164,21 @@ std r0,RESULT(r1); /* clear regs->result */ \ ints; -/* Variants for the "ints" argument */ +/* Variants for the "ints" argument. This one does nothing when we want + * to keep interrupts in their original state + */ #define INTS_KEEP -#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 + +/* 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 * * 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 @@ -238,7 +236,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_ALL) \ + EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE) \ ack(r8); \ CHECK_NAPPING(); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ @@ -289,7 +287,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_ALL) +// EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD @@ -300,7 +298,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_ALL) +// EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE) // bl special_reg_save_mc // addi r3,r1,STACK_FRAME_OVERHEAD // CHECK_NAPPING(); @@ -313,7 +311,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_KEEP) + EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_DISABLE) b storage_fault_common /* Instruction Storage Interrupt */ @@ -321,7 +319,7 @@ interrupt_end_book3e: NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS) li r15,0 mr r14,r10 - EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_KEEP) + EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_DISABLE) b storage_fault_common /* External Input Interrupt */ @@ -339,12 +337,11 @@ interrupt_end_book3e: START_EXCEPTION(program); NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG) mfspr r14,SPRN_ESR - EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT) + EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE) 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 @@ -353,15 +350,16 @@ 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) - bne 1f /* if from user, just load it up */ + ld r12,_MSR(r1) + andi. r0,r12,MSR_PR; + beq- 1f + bl .load_up_fpu + b fast_exception_return +1: INTS_DISABLE bl .save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD - INTS_RESTORE_HARD bl .kernel_fp_unavailable_exception - BUG_OPCODE -1: ld r12,_MSR(r1) - bl .load_up_fpu - b fast_exception_return + b .ret_from_except /* Decrementer Interrupt */ MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC) @@ -372,7 +370,7 @@ interrupt_end_book3e: /* Watchdog Timer Interrupt */ START_EXCEPTION(watchdog); CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL) +// EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD @@ -391,10 +389,9 @@ interrupt_end_book3e: /* Auxiliary Processor Unavailable Interrupt */ START_EXCEPTION(ap_unavailable); NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE) - EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP) - addi r3,r1,STACK_FRAME_OVERHEAD + EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_DISABLE) bl .save_nvgprs - INTS_RESTORE_HARD + addi r3,r1,STACK_FRAME_OVERHEAD bl .unknown_exception b .ret_from_except @@ -450,7 +447,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_ALL) + EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE) std r14,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r14 @@ -465,7 +462,7 @@ kernel_dbg_exc: /* Debug exception as a debug interrupt*/ START_EXCEPTION(debug_debug); - DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) + DBG_EXCEPTION_PROLOG(0xd08, PROLOG_ADDITION_2REGS) /* * If there is a single step or branch-taken exception in an @@ -515,7 +512,7 @@ kernel_dbg_exc: mfspr r15,SPRN_SPRG_DBG_SCRATCH mtspr SPRN_SPRG_GEN_SCRATCH,r15 mfspr r14,SPRN_DBSR - EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL) + EXCEPTION_COMMON(0xd08, PACA_EXDBG, INTS_DISABLE) std r14,_DSISR(r1) addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r14 @@ -525,21 +522,20 @@ kernel_dbg_exc: bl .DebugException b .ret_from_except - MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE) - -/* Doorbell interrupt */ - START_EXCEPTION(doorbell) - NORMAL_EXCEPTION_PROLOG(0x2070, PROLOG_ADDITION_DOORBELL) - EXCEPTION_COMMON(0x2070, PACA_EXGEN, INTS_DISABLE_ALL) - CHECK_NAPPING() + START_EXCEPTION(perfmon); + NORMAL_EXCEPTION_PROLOG(0x260, PROLOG_ADDITION_NONE) + EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE) addi r3,r1,STACK_FRAME_OVERHEAD - bl .doorbell_exception + bl .performance_monitor_exception b .ret_from_except_lite +/* Doorbell interrupt */ + MASKABLE_EXCEPTION(0x280, doorbell, .doorbell_exception, ACK_NONE) + /* Doorbell critical Interrupt */ START_EXCEPTION(doorbell_crit); - CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE) -// EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL) + CRIT_EXCEPTION_PROLOG(0x2a0, PROLOG_ADDITION_NONE) +// EXCEPTION_COMMON(0x2a0, PACA_EXCRIT, INTS_DISABLE) // bl special_reg_save_crit // CHECK_NAPPING(); // addi r3,r1,STACK_FRAME_OVERHEAD @@ -547,36 +543,114 @@ 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; clear EE in SRR1, - * clear paca->hard_enabled and return. + * An interrupt came in while soft-disabled; We mark paca->irq_happened + * accordingly and if the interrupt is level sensitive, we hard disable */ -masked_doorbell_book3e: - mtcr r10 - /* Resend the doorbell to fire again when ints enabled */ - mfspr r10,SPRN_PIR - PPC_MSGSND(r10) - b masked_interrupt_book3e_common -masked_interrupt_book3e: +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: + mtcr r10 + lbz r10,PACAIRQHAPPENED(r13) + or r10,r10,r11 + stb r10,PACAIRQHAPPENED(r13) + b 1f +masked_interrupt_book3e_full_mask: mtcr r10 -masked_interrupt_book3e_common: - stb r11,PACAHARDIRQEN(r13) + lbz r10,PACAIRQHAPPENED(r13) + or r10,r10,r11 + stb r10,PACAIRQHAPPENED(r13) mfspr r10,SPRN_SRR1 rldicl r11,r10,48,1 /* clear MSR_EE */ rotldi r10,r11,16 mtspr SPRN_SRR1,r10 - ld r10,PACA_EXGEN+EX_R10(r13); /* restore registers */ +1: ld r10,PACA_EXGEN+EX_R10(r13); 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 @@ -591,7 +665,6 @@ 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 @@ -680,6 +753,8 @@ 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) @@ -697,11 +772,10 @@ 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/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 15c5a4f6de01..2d0868a4e2f0 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S @@ -12,6 +12,7 @@ * */ +#include <asm/hw_irq.h> #include <asm/exception-64s.h> #include <asm/ptrace.h> @@ -19,7 +20,7 @@ * We layout physical memory as follows: * 0x0000 - 0x00ff : Secondary processor spin code * 0x0100 - 0x2fff : pSeries Interrupt prologs - * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs + * 0x3000 - 0x5fff : interrupt support common interrupt prologs * 0x6000 - 0x6fff : Initial (CPU0) segment table * 0x7000 - 0x7fff : FWNMI data area * 0x8000 - : Early init and support code @@ -356,34 +357,60 @@ do_stab_bolted_pSeries: KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40) /* - * An interrupt came in while soft-disabled; clear EE in SRR1, - * clear paca->hard_enabled and return. + * 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. */ -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 +#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; \ b . + + MASKED_INTERRUPT() + MASKED_INTERRUPT(H) -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 . +/* + * 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 #ifdef CONFIG_PPC_PSERIES /* @@ -458,14 +485,15 @@ machine_check_common: bl .machine_check_exception b .ret_from_except - STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt) + STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) + STD_EXCEPTION_COMMON_ASYNC(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_IDLE(0xf00, performance_monitor, .performance_monitor_exception) + STD_EXCEPTION_COMMON_ASYNC(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) @@ -482,6 +510,9 @@ 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, @@ -555,6 +586,8 @@ 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 @@ -569,6 +602,7 @@ 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 @@ -577,6 +611,8 @@ 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 @@ -672,12 +708,6 @@ _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 @@ -690,12 +720,6 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) 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) @@ -704,13 +728,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) rfid b . /* prevent speculative execution */ -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 +2: mfspr r11,SPRN_SRR0 ld r10,PACAKBASE(r13) LOAD_HANDLER(r10,unrecov_slb) mtspr SPRN_SRR0,r10 @@ -727,20 +745,6 @@ 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: @@ -785,8 +789,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 @@ -805,8 +809,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 @@ -816,13 +820,14 @@ vsx_unavailable_common: EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN) #ifdef CONFIG_VSX BEGIN_FTR_SECTION - bne .load_up_vsx + beq 1f + b .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 @@ -831,66 +836,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) __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 */ .align 7 @@ -912,28 +857,6 @@ 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 @@ -951,62 +874,25 @@ 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 + * at return r3 = 0 for success, 1 for page fault, negative for error */ bl .hash_page /* build HPTE if possible */ cmpdi r3,0 /* see if hash_page succeeded */ -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. - */ + /* Success */ 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 -/* 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 + /* Error */ + blt- 13f /* 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+ 13f + beq+ 12f bl .save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD @@ -1014,12 +900,20 @@ handle_page_fault: bl .bad_page_fault b .ret_from_except -13: b .ret_from_except_lite +/* 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 + /* We have a page fault that hash_page could handle but HV refused * the PTE insertion */ -12: bl .save_nvgprs +13: bl .save_nvgprs mr r5,r3 addi r3,r1,STACK_FRAME_OVERHEAD ld r4,_DAR(r1) @@ -1141,51 +1035,19 @@ _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. - * - * 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 */ +/* Space for CPU0's segment table */ + .balign 4096 .globl initial_stab initial_stab: .space 4096 + #ifdef CONFIG_PPC_POWERNV _GLOBAL(opal_mc_secondary_handler) HMT_MEDIUM diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c new file mode 100644 index 000000000000..cfe7a38708c3 --- /dev/null +++ b/arch/powerpc/kernel/fadump.c @@ -0,0 +1,1315 @@ +/* + * 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 <mahesh@linux.vnet.ibm.com> + */ + +#undef DEBUG +#define pr_fmt(fmt) "fadump: " fmt + +#include <linux/string.h> +#include <linux/memblock.h> +#include <linux/delay.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <linux/crash_dump.h> +#include <linux/kobject.h> +#include <linux/sysfs.h> + +#include <asm/page.h> +#include <asm/prom.h> +#include <asm/rtas.h> +#include <asm/fadump.h> + +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/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 0654dba2c1f1..dc0488b6f6e1 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/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_EE_LITE(0x300, handle_page_fault) + EXC_XFER_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_EE_LITE(0x400, handle_page_fault) + EXC_XFER_LITE(0x400, handle_page_fault) /* External interrupt */ EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index 872a6af83bad..4989661b710b 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/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_EE_LITE(0x400, handle_page_fault) + EXC_XFER_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_EE_LITE(0x300, handle_page_fault) + EXC_XFER_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/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 06c7251c1bf7..58bddee8e1e8 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S @@ -32,13 +32,13 @@ #include <asm/cputable.h> #include <asm/setup.h> #include <asm/hvcall.h> -#include <asm/iseries/lpar_map.h> #include <asm/thread_info.h> #include <asm/firmware.h> #include <asm/page_64.h> #include <asm/irqflags.h> #include <asm/kvm_book3s_asm.h> #include <asm/ptrace.h> +#include <asm/hw_irq.h> /* The physical memory is laid out such that the secondary processor * spin code sits at 0x0000...0x00ff. On server, the vectors follow @@ -57,10 +57,6 @@ * 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 @@ -93,15 +89,6 @@ __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 @@ -564,7 +551,8 @@ _GLOBAL(pmac_secondary_start) */ li r0,0 stb r0,PACASOFTIRQEN(r13) - stb r0,PACAHARDIRQEN(r13) + li r0,PACA_IRQ_HARD_DIS + stb r0,PACAIRQHAPPENED(r13) /* Create a temp kernel stack for use before relocation is on. */ ld r1,PACAEMERGSP(r13) @@ -582,7 +570,7 @@ _GLOBAL(pmac_secondary_start) * 1. Processor number * 2. Segment table pointer (virtual address) * On entry the following are set: - * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries + * r1 = stack pointer (real addr of temp stack) * r24 = cpu# (in Linux terms) * r13 = paca virtual address * SPRG_PACA = paca virtual address @@ -595,7 +583,7 @@ __secondary_start: /* Set thread priority to MEDIUM */ HMT_MEDIUM - /* Initialize the kernel stack. Just a repeat for iSeries. */ + /* Initialize the kernel stack */ LOAD_REG_ADDR(r3, current_set) sldi r28,r24,3 /* get current_set[cpu#] */ ldx r14,r3,r28 @@ -615,20 +603,16 @@ __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 @@ -771,22 +755,18 @@ _INIT_GLOBAL(start_here_common) /* Load the TOC (virtual address) */ ld r2,PACATOC(r13) + /* Do more system initializations in virtual mode */ bl .setup_system - /* 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 */ + /* 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) + /* Generic kernel entry */ bl .start_kernel /* Not reached */ diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index b68cb173ba2c..b2a5860accfb 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/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_EE_LITE(0x300, handle_page_fault) + EXC_XFER_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_EE_LITE(0x400, handle_page_fault) + EXC_XFER_LITE(0x400, handle_page_fault) /* External interrupt */ EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index fc921bf62e15..0e4175388f47 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h @@ -359,7 +359,7 @@ label: mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \ stw r5,_ESR(r11); \ mfspr r4,SPRN_DEAR; /* Grab the DEAR */ \ - EXC_XFER_EE_LITE(0x0300, handle_page_fault) + EXC_XFER_LITE(0x0300, handle_page_fault) #define INSTRUCTION_STORAGE_EXCEPTION \ START_EXCEPTION(InstructionStorage) \ @@ -368,7 +368,7 @@ label: stw r5,_ESR(r11); \ mr r4,r12; /* Pass SRR0 as arg2 */ \ li r5,0; /* Pass zero as arg3 */ \ - EXC_XFER_EE_LITE(0x0400, handle_page_fault) + EXC_XFER_LITE(0x0400, handle_page_fault) #define ALIGNMENT_EXCEPTION \ START_EXCEPTION(Alignment) \ diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index d5d78c4ceef6..28e62598d0e8 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/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_EE_LITE(0x0300, handle_page_fault) + EXC_XFER_LITE(0x0300, handle_page_fault) 1: addi r3,r1,STACK_FRAME_OVERHEAD EXC_XFER_EE_LITE(0x0300, CacheLockingException) diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index c97fc60c790c..e8e821146f38 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c @@ -84,7 +84,11 @@ void cpu_idle(void) start_critical_timings(); - local_irq_enable(); + /* Some power_save functions return with + * interrupts enabled, some don't. + */ + if (irqs_disabled()) + local_irq_enable(); set_thread_flag(TIF_POLLING_NRFLAG); } else { diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S index 16c002d6bdf1..ff007b59448d 100644 --- a/arch/powerpc/kernel/idle_book3e.S +++ b/arch/powerpc/kernel/idle_book3e.S @@ -29,43 +29,30 @@ _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...). We know - * that since PACAHARDIRQEN will have been cleared in that case. + * since we may otherwise lose it (doorbells etc...). */ - lbz r3,PACAHARDIRQEN(r13) + lbz r3,PACAIRQHAPPENED(r13) cmpwi cr0,r3,0 - beqlr + bnelr - /* Now we are going to mark ourselves as soft and hard enables in + /* Now we are going to mark ourselves as soft and hard enabled 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 - /* 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 + /* And return (interrupts are on) */ ld r0,16(r1) mtlr r0 blr diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S index ba3195478600..2c71b0fc9f91 100644 --- a/arch/powerpc/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S @@ -14,6 +14,7 @@ #include <asm/thread_info.h> #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> +#include <asm/irqflags.h> #undef DEBUG @@ -29,14 +30,31 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) cmpwi 0,r4,0 beqlr - /* Go to NAP now */ + /* Hard disable interrupts */ mfmsr r7 rldicl r0,r7,48,1 rotldi r0,r0,16 - mtmsrd r0,1 /* hard-disable interrupts */ + 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 */ + li r0,1 stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ - stb r0,PACAHARDIRQEN(r13) BEGIN_FTR_SECTION DSSALL sync diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index fcdff198da4b..0cdc9a392839 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S @@ -1,5 +1,5 @@ /* - * This file contains the power_save function for 970-family CPUs. + * This file contains the power_save function for Power7 CPUs. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -15,6 +15,7 @@ #include <asm/ppc_asm.h> #include <asm/asm-offsets.h> #include <asm/ppc-opcode.h> +#include <asm/hw_irq.h> #undef DEBUG @@ -51,9 +52,25 @@ _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/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 0cfcf98aafca..359f078571c7 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c @@ -39,6 +39,7 @@ #include <asm/pci-bridge.h> #include <asm/machdep.h> #include <asm/kdump.h> +#include <asm/fadump.h> #define DBG(...) @@ -445,7 +446,12 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, static void iommu_table_clear(struct iommu_table *tbl) { - if (!is_kdump_kernel()) { + /* + * 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()) { /* 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/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index bdfb3eee3e6f..a3d128e94cff 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -93,20 +93,16 @@ 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_hard_enabled(void) +static inline notrace unsigned long get_irq_happened(void) { - unsigned long enabled; + unsigned long happened; __asm__ __volatile__("lbz %0,%1(13)" - : "=r" (enabled) : "i" (offsetof(struct paca_struct, hard_enabled))); + : "=r" (happened) : "i" (offsetof(struct paca_struct, irq_happened))); - return enabled; + return happened; } static inline notrace void set_soft_enabled(unsigned long enable) @@ -115,88 +111,162 @@ static inline notrace void set_soft_enabled(unsigned long enable) : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); } -static inline notrace void decrementer_check_overflow(void) +static inline notrace int decrementer_check_overflow(void) { - u64 now = get_tb_or_rtc(); - u64 *next_tb; - - preempt_disable(); - next_tb = &__get_cpu_var(decrementers_next_tb); - + u64 now = get_tb_or_rtc(); + u64 *next_tb = &__get_cpu_var(decrementers_next_tb); + if (now >= *next_tb) set_dec(1); - preempt_enable(); + return now >= *next_tb; } -notrace void arch_local_irq_restore(unsigned long en) +/* 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) { /* - * 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. + * We use local_paca rather than get_paca() to avoid all + * the debug_smp_processor_id() business in this low level + * function */ - set_soft_enabled(en); - if (!en) - return; + unsigned char happened = local_paca->irq_happened; -#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(); + /* 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. + */ + if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { + u64 tmp, tmp2; + lv1_get_version_info(&tmp, &tmp2); } -#endif /* CONFIG_PPC_STD_MMU_64 */ /* - * 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. + * 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 */ - if (get_hard_enabled()) + 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; + /* + * 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. + */ + irq_happened = get_irq_happened(); + if (!irq_happened) return; /* - * 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. + * 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. */ - local_paca->hard_enabled = en; + if (unlikely(irq_happened != PACA_IRQ_HARD_DIS)) + __hard_irq_disable(); + set_soft_enabled(0); /* - * 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. + * 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 */ - decrementer_check_overflow(); + replay = __check_irq_replay(); + + /* We can soft-enable now */ + set_soft_enabled(1); /* - * Force the delivery of pending soft-disabled interrupts on PS3. - * Any HV call will have this side effect. + * And replay if we have to. This will return with interrupts + * hard-enabled. */ - if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { - u64 tmp, tmp2; - lv1_get_version_info(&tmp, &tmp2); + if (replay) { + __replay_interrupt(replay); + return; } + /* 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) @@ -364,8 +434,17 @@ 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) @@ -374,15 +453,6 @@ 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/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c index 479752901ec6..d45ec58703ce 100644 --- a/arch/powerpc/kernel/isa-bridge.c +++ b/arch/powerpc/kernel/isa-bridge.c @@ -29,7 +29,6 @@ #include <asm/pci-bridge.h> #include <asm/machdep.h> #include <asm/ppc-pci.h> -#include <asm/firmware.h> unsigned long isa_io_base; /* NULL if no ISA bus */ EXPORT_SYMBOL(isa_io_base); @@ -261,8 +260,6 @@ 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/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 578f35f18723..ac12bd80ad95 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -26,7 +26,6 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <asm/uaccess.h> -#include <asm/iseries/hv_lp_config.h> #include <asm/lppaca.h> #include <asm/hvcall.h> #include <asm/firmware.h> @@ -55,80 +54,14 @@ static unsigned long get_purr(void) int cpu; for_each_possible_cpu(cpu) { - if (firmware_has_feature(FW_FEATURE_ISERIES)) - sum_purr += lppaca_of(cpu).emulated_time_base; - else { - struct cpu_usage *cu; + 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. */ @@ -648,8 +581,7 @@ 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) || - firmware_has_feature(FW_FEATURE_ISERIES)) + if (!firmware_has_feature(FW_FEATURE_SPLPAR)) return -EINVAL; if (count > kbuf_sz) @@ -709,21 +641,6 @@ 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; @@ -738,19 +655,11 @@ 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) @@ -761,8 +670,6 @@ 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); } @@ -786,8 +693,7 @@ 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) && - !firmware_has_feature(FW_FEATURE_ISERIES)) + if (firmware_has_feature(FW_FEATURE_SPLPAR)) mode |= S_IWUSR; ent = proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops); diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index b69463ec2010..ba16874fe294 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S @@ -5,7 +5,6 @@ * 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/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index e1612dfb4a93..2049f2d00ffe 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c @@ -21,12 +21,13 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_platform.h> +#include <linux/atomic.h> #include <asm/errno.h> #include <asm/topology.h> #include <asm/pci-bridge.h> #include <asm/ppc-pci.h> -#include <linux/atomic.h> +#include <asm/eeh.h> #ifdef CONFIG_PPC_OF_PLATFORM_PCI @@ -66,6 +67,9 @@ 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/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 41456ff55e14..0bb1f98613ba 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c @@ -11,13 +11,10 @@ #include <linux/export.h> #include <linux/memblock.h> -#include <asm/firmware.h> #include <asm/lppaca.h> #include <asm/paca.h> #include <asm/sections.h> #include <asm/pgtable.h> -#include <asm/iseries/lpar_map.h> -#include <asm/iseries/hv_types.h> #include <asm/kexec.h> /* This symbol is provided by the linker - let it fill in the paca @@ -30,8 +27,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 legacy iSeries and POWER5 - * pSeries boxes. The lppaca is 640 bytes long, and cannot readily + * boundary. The lppaca is also used on 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. */ @@ -183,12 +180,9 @@ 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. On iSeries they must be within the area mapped - * by the HV, which is HvPagesToMap * HVPAGESIZE bytes. + * the first segment. */ 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/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index cce98d76e905..d0373bcb7c9d 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -38,7 +38,6 @@ #include <asm/byteorder.h> #include <asm/machdep.h> #include <asm/ppc-pci.h> -#include <asm/firmware.h> #include <asm/eeh.h> static DEFINE_SPINLOCK(hose_spinlock); @@ -219,20 +218,6 @@ 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/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index d817ab018486..e40707032ac3 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -647,6 +647,9 @@ 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); @@ -1220,34 +1223,32 @@ void dump_stack(void) EXPORT_SYMBOL(dump_stack); #ifdef CONFIG_PPC64 -void ppc64_runlatch_on(void) +/* Called with hard IRQs off */ +void __ppc64_runlatch_on(void) { + struct thread_info *ti = current_thread_info(); unsigned long 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); + ctrl = mfspr(SPRN_CTRLF); + ctrl |= CTRL_RUNLATCH; + mtspr(SPRN_CTRLT, ctrl); - set_thread_flag(TIF_RUNLATCH); - } + ti->local_flags |= TLF_RUNLATCH; } +/* Called with hard IRQs off */ void __ppc64_runlatch_off(void) { + struct thread_info *ti = current_thread_info(); unsigned long ctrl; - HMT_medium(); - - clear_thread_flag(TIF_RUNLATCH); + ti->local_flags &= ~TLF_RUNLATCH; ctrl = mfspr(SPRN_CTRLF); ctrl &= ~CTRL_RUNLATCH; mtspr(SPRN_CTRLT, ctrl); } -#endif +#endif /* CONFIG_PPC64 */ #if THREAD_SHIFT < PAGE_SHIFT diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index abe405dab34d..89e850af3dd6 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c @@ -52,9 +52,9 @@ #include <asm/machdep.h> #include <asm/pSeries_reconfig.h> #include <asm/pci-bridge.h> -#include <asm/phyp_dump.h> #include <asm/kexec.h> #include <asm/opal.h> +#include <asm/fadump.h> #include <mm/mmu_decl.h> @@ -615,86 +615,6 @@ 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; @@ -714,9 +634,9 @@ void __init early_init_devtree(void *params) of_scan_flat_dt(early_init_dt_scan_opal, NULL); #endif -#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); +#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); #endif /* Pre-initialize the cmd_line with the content of boot_commmand_line, @@ -750,9 +670,15 @@ void __init early_init_devtree(void *params) if (PHYSICAL_START > MEMORY_START) memblock_reserve(MEMORY_START, 0x8000); reserve_kdump_trampoline(); - reserve_crashkernel(); +#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(); early_reserve_mem(); - phyp_dump_reserve_mem(); /* * Ensure that total memory size is page-aligned, because otherwise diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index eca626ea3f23..e2d599048142 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -48,14 +48,6 @@ #include <linux/linux_logo.h> /* - * 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 */ #define DEVTREE_CHUNK_SIZE 0x100000 @@ -2273,13 +2265,6 @@ 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/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 6cd8f0196b6d..517bd86bc3f0 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c @@ -275,6 +275,9 @@ 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/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 77bb77da05c1..b0ebdeab9494 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -61,6 +61,7 @@ #include <asm/xmon.h> #include <asm/cputhreads.h> #include <mm/mmu_decl.h> +#include <asm/fadump.h> #include "setup.h" @@ -109,6 +110,14 @@ 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(); } @@ -639,6 +648,11 @@ 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/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index ac6e437b1021..7006b7f4267a 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -57,10 +57,7 @@ void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, void restore_sigmask(sigset_t *set) { sigdelsetmask(set, ~_BLOCKABLE); - spin_lock_irq(¤t->sighand->siglock); - current->blocked = *set; - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + set_current_blocked(set); } static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, @@ -169,13 +166,7 @@ static int do_signal(struct pt_regs *regs) regs->trap = 0; if (ret) { - 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); + block_sigmask(&ka, signr); /* * A signal was successfully delivered; the saved sigmask is in diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 836a5a19eb2c..e061ef5dd449 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -242,12 +242,13 @@ static inline int restore_general_regs(struct pt_regs *regs, */ long sys_sigsuspend(old_sigset_t mask) { - mask &= _BLOCKABLE; - spin_lock_irq(¤t->sighand->siglock); + sigset_t blocked; + current->saved_sigmask = current->blocked; - siginitset(¤t->blocked, mask); - recalc_sigpending(); - spin_unlock_irq(¤t->sighand->siglock); + + mask &= _BLOCKABLE; + siginitset(&blocked, mask); + set_current_blocked(&blocked); current->state = TASK_INTERRUPTIBLE; schedule(); diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 883e74c0d1b3..0c683d376b1c 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -12,7 +12,6 @@ #include <asm/current.h> #include <asm/processor.h> #include <asm/cputable.h> -#include <asm/firmware.h> #include <asm/hvcall.h> #include <asm/prom.h> #include <asm/machdep.h> @@ -341,8 +340,7 @@ static void __cpuinit register_cpu_online(unsigned int cpu) int i, nattrs; #ifdef CONFIG_PPC64 - if (!firmware_has_feature(FW_FEATURE_ISERIES) && - cpu_has_feature(CPU_FTR_SMT)) + if (cpu_has_feature(CPU_FTR_SMT)) device_create_file(s, &dev_attr_smt_snooze_delay); #endif @@ -414,8 +412,7 @@ static void unregister_cpu_online(unsigned int cpu) BUG_ON(!c->hotpluggable); #ifdef CONFIG_PPC64 - if (!firmware_has_feature(FW_FEATURE_ISERIES) && - cpu_has_feature(CPU_FTR_SMT)) + if (cpu_has_feature(CPU_FTR_SMT)) device_remove_file(s, &dev_attr_smt_snooze_delay); #endif diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 567dd7c3ac2a..2c42cd72d0f5 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -17,8 +17,7 @@ * * TODO (not necessarily in this file): * - improve precision and reproducibility of timebase frequency - * measurement at boot time. (for iSeries, we calibrate the timebase - * against the Titan chip's clock.) + * measurement at boot time. * - 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. @@ -70,10 +69,6 @@ #include <asm/vdso_datapage.h> #include <asm/firmware.h> #include <asm/cputime.h> -#ifdef CONFIG_PPC_ISERIES -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/hv_call_xm.h> -#endif /* powerpc clocksource/clockevent code */ @@ -117,14 +112,6 @@ 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 @@ -259,7 +246,6 @@ 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 @@ -268,7 +254,6 @@ 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); @@ -277,7 +262,6 @@ 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) @@ -426,74 +410,6 @@ 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 /* @@ -550,16 +466,6 @@ 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. */ @@ -580,6 +486,11 @@ 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++; @@ -597,20 +508,10 @@ 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)) { @@ -982,9 +883,8 @@ void __init time_init(void) */ start_cpu_decrementer(); - /* Register the clocksource, if we're not running on iSeries */ - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - clocksource_init(); + /* Register the clocksource */ + clocksource_init(); init_decrementer_clockevent(); } diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index c091527efd89..a750409ccc4e 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -57,6 +57,7 @@ #include <asm/kexec.h> #include <asm/ppc-opcode.h> #include <asm/rio.h> +#include <asm/fadump.h> #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) int (*__debugger)(struct pt_regs *regs) __read_mostly; @@ -145,6 +146,8 @@ 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. @@ -244,6 +247,9 @@ 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/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 8b086299ba25..bca3fc427b45 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -34,11 +34,6 @@ #include <asm/abs_addr.h> #include <asm/page.h> #include <asm/hvcall.h> -#include <asm/iseries/vio.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/iommu.h> static struct bus_type vio_bus_type; @@ -1042,7 +1037,6 @@ 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; } @@ -1060,9 +1054,6 @@ 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) @@ -1195,8 +1186,7 @@ static void __devinit vio_dev_release(struct device *dev) { struct iommu_table *tbl = get_iommu_table_base(dev); - /* iSeries uses a common table for all vio devices */ - if (!firmware_has_feature(FW_FEATURE_ISERIES) && tbl) + if (tbl) iommu_free_table(tbl, dev->of_node ? dev->of_node->full_name : dev_name(dev)); of_node_put(dev->of_node); @@ -1244,12 +1234,6 @@ 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/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 710a54005dfb..65d1c08cf09e 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S @@ -109,11 +109,6 @@ 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/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 336983da9e72..a7267167a550 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -46,7 +46,6 @@ #include <asm/page.h> #include <asm/hvcall.h> #include <linux/gfp.h> -#include <linux/sched.h> #include <linux/vmalloc.h> #include <linux/highmem.h> diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c index a6ebba56fdd4..bb7cfecf2788 100644 --- a/arch/powerpc/lib/locks.c +++ b/arch/powerpc/lib/locks.c @@ -19,11 +19,9 @@ #include <linux/smp.h> /* waiting for a spinlock... */ -#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) +#if defined(CONFIG_PPC_SPLPAR) #include <asm/hvcall.h> -#include <asm/iseries/hv_call.h> #include <asm/smp.h> -#include <asm/firmware.h> void __spin_yield(arch_spinlock_t *lock) { @@ -40,14 +38,8 @@ void __spin_yield(arch_spinlock_t *lock) rmb(); if (lock->slock != lock_value) return; /* something has changed */ - 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 + plpar_hcall_norets(H_CONFER, + get_hard_smp_processor_id(holder_cpu), yield_count); } /* @@ -71,14 +63,8 @@ void __rw_yield(arch_rwlock_t *rw) rmb(); if (rw->lock != lock_value) return; /* something has changed */ - 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 + plpar_hcall_norets(H_CONFER, + get_hard_smp_processor_id(holder_cpu), yield_count); } #endif diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 2f0d1b032a89..19f2f9498b27 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c @@ -105,6 +105,82 @@ 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 @@ -124,11 +200,12 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, { struct vm_area_struct * vma; struct mm_struct *mm = current->mm; - siginfo_t info; + unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; int code = SEGV_MAPERR; - int is_write = 0, ret; + int is_write = 0; int trap = TRAP(regs); int is_exec = trap == 0x400; + int fault; #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) /* @@ -145,6 +222,9 @@ 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 @@ -152,13 +232,11 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, * look at it */ if (error_code & ICSWX_DSI_UCT) { - int ret; - - ret = acop_handle_fault(regs, address, error_code); - if (ret) - return ret; + int rc = acop_handle_fault(regs, address, error_code); + if (rc) + return rc; } -#endif +#endif /* CONFIG_PPC_ICSWX */ if (notify_page_fault(regs)) return 0; @@ -179,6 +257,10 @@ 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; @@ -212,7 +294,15 @@ 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); @@ -327,30 +417,43 @@ good_area: * make sure we exit gracefully rather than endlessly redo * the fault. */ - 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(); + 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; } - if (ret & VM_FAULT_MAJOR) { - current->maj_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, - regs, address); + + /* + * 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); #ifdef CONFIG_PPC_SMLPAR - if (firmware_has_feature(FW_FEATURE_CMO)) { - preempt_disable(); - get_lppaca()->page_ins += (1 << PAGE_FACTOR); - preempt_enable(); + 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; } -#endif - } else { - current->min_flt++; - perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, - regs, address); } + up_read(&mm->mmap_sem); return 0; @@ -371,28 +474,6 @@ bad_area_nosemaphore: 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/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index 66a6fd38e9cd..07ba45b0f07c 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -149,12 +149,19 @@ 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) & ~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; + 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; + } if (camsize > align) camsize = align; diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 2d282186cb45..3e8c37a4e395 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -55,6 +55,8 @@ #include <asm/spu.h> #include <asm/udbg.h> #include <asm/code-patching.h> +#include <asm/fadump.h> +#include <asm/firmware.h> #ifdef DEBUG #define DBG(fmt...) udbg_printf(fmt) @@ -625,6 +627,16 @@ 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 @@ -745,12 +757,9 @@ void __init early_init_mmu(void) */ htab_initialize(); - /* Initialize stab / SLB management except on iSeries - */ + /* Initialize stab / SLB management */ 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 @@ -761,8 +770,7 @@ 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 and we want a virtual address on - * iSeries anyway + * in real mode on pSeries. */ if (mmu_has_feature(MMU_FTR_SLB)) slb_initialize(); diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c index 5d9a59eaad93..8cdbd8634a58 100644 --- a/arch/powerpc/mm/icswx.c +++ b/arch/powerpc/mm/icswx.c @@ -163,7 +163,7 @@ EXPORT_SYMBOL_GPL(drop_cop); static int acop_use_cop(int ct) { - /* todo */ + /* There is no alternate policy, yet */ return -1; } @@ -227,11 +227,30 @@ 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", + pr_warn("%s[%d]: Coprocessor %d is unavailable\n", current->comm, current->pid, ct); /* get inst if we don't already have it */ diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h index 42176bd0884c..6dedc08e62c8 100644 --- a/arch/powerpc/mm/icswx.h +++ b/arch/powerpc/mm/icswx.h @@ -59,4 +59,10 @@ 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/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 51f87956f8f8..0907f92ce309 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/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 %p\n", + printk("__ioremap(): phys addr 0x%llx is RAM lr %pf\n", (unsigned long long)p, __builtin_return_address(0)); return NULL; } diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index e22276cb67a4..a538c80db2df 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c @@ -21,7 +21,6 @@ #include <asm/cputable.h> #include <asm/cacheflush.h> #include <asm/smp.h> -#include <asm/firmware.h> #include <linux/compiler.h> #include <asm/udbg.h> #include <asm/code-patching.h> @@ -307,11 +306,6 @@ 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/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index ef653dc95b65..b9ee79ce2200 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S @@ -217,21 +217,6 @@ 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 @@ -282,7 +267,6 @@ _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/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 41e31642a86a..9106ebb118f5 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c @@ -21,8 +21,6 @@ #include <asm/cputable.h> #include <asm/prom.h> #include <asm/abs_addr.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_call.h> struct stab_entry { unsigned long esid_data; @@ -285,12 +283,5 @@ 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/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index d65e68f3cb25..6f01624f317f 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c @@ -195,9 +195,6 @@ 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/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile new file mode 100644 index 000000000000..af3fac23768c --- /dev/null +++ b/arch/powerpc/perf/Makefile @@ -0,0 +1,14 @@ +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/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/perf/callchain.c index 564c1d8bdb5c..e8a18d1cc7c9 100644 --- a/arch/powerpc/kernel/perf_callchain.c +++ b/arch/powerpc/perf/callchain.c @@ -20,7 +20,7 @@ #include <asm/ucontext.h> #include <asm/vdso.h> #ifdef CONFIG_PPC64 -#include "ppc32.h" +#include "../kernel/ppc32.h" #endif diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/perf/core-book3s.c index c2e27ede07ec..c2e27ede07ec 100644 --- a/arch/powerpc/kernel/perf_event.c +++ b/arch/powerpc/perf/core-book3s.c diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/perf/core-fsl-emb.c index 0a6d2a9d569c..0a6d2a9d569c 100644 --- a/arch/powerpc/kernel/perf_event_fsl_emb.c +++ b/arch/powerpc/perf/core-fsl-emb.c diff --git a/arch/powerpc/kernel/e500-pmu.c b/arch/powerpc/perf/e500-pmu.c index cb2e2949c8d1..cb2e2949c8d1 100644 --- a/arch/powerpc/kernel/e500-pmu.c +++ b/arch/powerpc/perf/e500-pmu.c diff --git a/arch/powerpc/kernel/mpc7450-pmu.c b/arch/powerpc/perf/mpc7450-pmu.c index fe21b515ca44..fe21b515ca44 100644 --- a/arch/powerpc/kernel/mpc7450-pmu.c +++ b/arch/powerpc/perf/mpc7450-pmu.c diff --git a/arch/powerpc/kernel/power4-pmu.c b/arch/powerpc/perf/power4-pmu.c index b4f1dda4d089..b4f1dda4d089 100644 --- a/arch/powerpc/kernel/power4-pmu.c +++ b/arch/powerpc/perf/power4-pmu.c diff --git a/arch/powerpc/kernel/power5+-pmu.c b/arch/powerpc/perf/power5+-pmu.c index a8757baa28f3..a8757baa28f3 100644 --- a/arch/powerpc/kernel/power5+-pmu.c +++ b/arch/powerpc/perf/power5+-pmu.c diff --git a/arch/powerpc/kernel/power5-pmu.c b/arch/powerpc/perf/power5-pmu.c index e7f06eb7a861..e7f06eb7a861 100644 --- a/arch/powerpc/kernel/power5-pmu.c +++ b/arch/powerpc/perf/power5-pmu.c diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/perf/power6-pmu.c index 0bbc901e7efc..31128e086fed 100644 --- a/arch/powerpc/kernel/power6-pmu.c +++ b/arch/powerpc/perf/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/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c index 1251e4d7e262..1251e4d7e262 100644 --- a/arch/powerpc/kernel/power7-pmu.c +++ b/arch/powerpc/perf/power7-pmu.c diff --git a/arch/powerpc/kernel/ppc970-pmu.c b/arch/powerpc/perf/ppc970-pmu.c index 8c2190206964..111eb25bb0b6 100644 --- a/arch/powerpc/kernel/ppc970-pmu.c +++ b/arch/powerpc/perf/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/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index fcf6bf2ceee9..2e4e64abfab4 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig @@ -23,6 +23,7 @@ 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/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c index 3f6229b5dee0..583e67fee37e 100644 --- a/arch/powerpc/platforms/44x/currituck.c +++ b/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, 0, 0, 0, " MPIC "); + mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); ppc_md.get_irq = mpic_get_irq; diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c index 5b8cdbb82f80..a28a8629727e 100644 --- a/arch/powerpc/platforms/44x/iss4xx.c +++ b/arch/powerpc/platforms/44x/iss4xx.c @@ -71,8 +71,7 @@ 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, 0, 0, 0, - " MPIC "); + struct mpic *mpic = mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); ppc_md.get_irq = mpic_get_irq; diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c index 8d2202763415..3ffb915446e3 100644 --- a/arch/powerpc/platforms/44x/ppc44x_simple.c +++ b/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", - "amcc,bluestone", + "apm,bluestone", "amcc,glacier", "ibm,ebony", "amcc,eiger", diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index 846b789fb195..c0aa04068d69 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c @@ -50,6 +50,7 @@ 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/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 369fd5457a3f..d7e94f49532a 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c @@ -98,13 +98,11 @@ 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 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"); + /* 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"); } /* diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index d7946be298b6..f000d81c4e31 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig @@ -6,6 +6,7 @@ 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 @@ -13,6 +14,15 @@ 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 @@ -30,6 +40,7 @@ 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 @@ -80,7 +91,6 @@ 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. @@ -171,6 +181,21 @@ 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/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 9cb2d4320dcc..2125d4ca068a 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile @@ -27,3 +27,4 @@ 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/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c index 07e3e6c47371..df69e99e511c 100644 --- a/arch/powerpc/platforms/85xx/corenet_ds.c +++ b/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_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU; + unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU | + MPIC_NO_RESET; if (ppc_md.get_irq == mpic_get_coreint_irq) flags |= MPIC_ENABLE_COREINT; diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c new file mode 100644 index 000000000000..d50056f424f6 --- /dev/null +++ b/arch/powerpc/platforms/85xx/ge_imp3a.c @@ -0,0 +1,246 @@ +/* + * GE IMP3A Board Setup + * + * Author Martyn Welch <martyn.welch@ge.com> + * + * 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 <linux/stddef.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/kdev_t.h> +#include <linux/delay.h> +#include <linux/seq_file.h> +#include <linux/interrupt.h> +#include <linux/of_platform.h> +#include <linux/memblock.h> + +#include <asm/system.h> +#include <asm/time.h> +#include <asm/machdep.h> +#include <asm/pci-bridge.h> +#include <mm/mmu_decl.h> +#include <asm/prom.h> +#include <asm/udbg.h> +#include <asm/mpic.h> +#include <asm/swiotlb.h> +#include <asm/nvram.h> + +#include <sysdev/fsl_soc.h> +#include <sysdev/fsl_pci.h> +#include "smp.h" + +#include "mpc85xx.h" +#include <sysdev/ge/ge_pic.h> + +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/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c index 20f75d7819c6..60120e55da41 100644 --- a/arch/powerpc/platforms/85xx/ksi8560.c +++ b/arch/powerpc/platforms/85xx/ksi8560.c @@ -57,8 +57,7 @@ static void machine_restart(char *cmd) static void __init ksi8560_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index cf266826682e..f58872688d8f 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c @@ -36,9 +36,7 @@ void __init mpc8536_ds_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 3bebb5173bfc..d19f675cb369 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c @@ -50,8 +50,7 @@ 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_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 40f03da616a9..ab5f0bf19454 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c @@ -3,7 +3,7 @@ * * Maintained by Kumar Gala (see MAINTAINERS for contact information) * - * Copyright 2005 Freescale Semiconductor Inc. + * Copyright 2005, 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 @@ -48,17 +48,24 @@ #include "mpc85xx.h" -/* 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) - +/* + * 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 */ +}; -static int cds_pci_slot = 2; -static volatile u8 *cadmus; +static struct cadmus_reg *cadmus; #ifdef CONFIG_PCI @@ -158,6 +165,33 @@ 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) @@ -188,8 +222,7 @@ static struct irqaction mpc85xxcds_8259_irqaction = { static void __init mpc85xx_cds_pic_init(void) { struct mpic *mpic; - mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); @@ -249,20 +282,30 @@ machine_device_initcall(mpc85xx_cds, mpc85xx_cds_8259_attach); */ static void __init mpc85xx_cds_setup_arch(void) { -#ifdef CONFIG_PCI struct device_node *np; -#endif + int cds_pci_slot; if (ppc_md.progress) ppc_md.progress("mpc85xx_cds_setup_arch()", 0); - cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE); - cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1; + 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; + } 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", - cadmus[CM_VER], cds_pci_slot); + in_8(&cadmus->cm_ver), cds_pci_slot); ppc_md.progress(buf, 0); } @@ -292,7 +335,8 @@ 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", cadmus[CM_VER]); + seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", + in_8(&cadmus->cm_ver)); seq_printf(m, "PVR\t\t: 0x%x\n", pvid); seq_printf(m, "SVR\t\t: 0x%x\n", svid); @@ -323,7 +367,7 @@ define_machine(mpc85xx_cds) { .get_irq = mpic_get_irq, #ifdef CONFIG_PCI .restart = mpc85xx_cds_restart, - .pcibios_fixup_bus = fsl_pcibios_fixup_bus, + .pcibios_fixup_bus = mpc85xx_cds_fixup_bus, #else .restart = fsl_rstcr_restart, #endif diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index eefbb91e1d61..6e23e3e34bd9 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/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_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + MPIC_NO_RESET | + MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } else { mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); } diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 1d15a0cd2c82..f33662b46b8d 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c @@ -1,5 +1,6 @@ /* - * Copyright (C) Freescale Semicondutor, Inc. 2006-2010. All rights reserved. + * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc. + * All rights reserved. * * Author: Andy Fleming <afleming@freescale.com> * @@ -51,6 +52,7 @@ #include <asm/qe_ic.h> #include <asm/mpic.h> #include <asm/swiotlb.h> +#include <asm/fsl_guts.h> #include "smp.h" #include "mpc85xx.h" @@ -268,34 +270,27 @@ static void __init mpc85xx_mds_qe_init(void) mpc85xx_mds_reset_ucc_phys(); if (machine_is(p1021_mds)) { -#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"); + struct ccsr_guts_85xx __iomem *guts; + np = of_find_node_by_name(NULL, "global-utilities"); if (np) { - pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET; - - if (!pmuxcr) - printk(KERN_EMERG "Error: Alternate function" - " signal multiplex control register not" - " mapped!\n"); - else + guts = of_iomap(np, 0); + if (!guts) + pr_err("mpc85xx-rdb: could not map global utilities register\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(pmuxcr, MPC85xx_PMUXCR_QE0 | - MPC85xx_PMUXCR_QE3 | - MPC85xx_PMUXCR_QE9 | - MPC85xx_PMUXCR_QE12); - + 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); } @@ -434,9 +429,8 @@ 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_WANTS_RESET | MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index ccf520e890be..db214cd4c822 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c @@ -1,7 +1,7 @@ /* * MPC85xx RDB Board Setup * - * Copyright 2009 Freescale Semiconductor Inc. + * Copyright 2009,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 @@ -26,6 +26,9 @@ #include <asm/prom.h> #include <asm/udbg.h> #include <asm/mpic.h> +#include <asm/qe.h> +#include <asm/qe_ic.h> +#include <asm/fsl_guts.h> #include <sysdev/fsl_soc.h> #include <sysdev/fsl_pci.h> @@ -47,21 +50,36 @@ 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_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + 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_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + MPIC_BIG_ENDIAN | 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 + } /* @@ -69,7 +87,7 @@ void __init mpc85xx_rdb_pic_init(void) */ static void __init mpc85xx_rdb_setup_arch(void) { -#ifdef CONFIG_PCI +#if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE) struct device_node *np; #endif @@ -85,11 +103,73 @@ 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 @@ -112,6 +192,52 @@ 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, @@ -139,3 +265,87 @@ 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/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index 538bc3f57e9d..d8bd6563d9ca 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c @@ -32,9 +32,8 @@ void __init p1010_rdb_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index b0984ada3f83..0fe88e39945e 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c @@ -33,6 +33,10 @@ #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 @@ -50,11 +54,22 @@ #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 * @@ -133,44 +148,117 @@ 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 *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"); + 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"); return; } - pixis = of_iomap(np, 0); - if (!pixis) { - pr_err("p1022ds: could not map ngPIXIS registers\n"); - return; + guts = of_iomap(guts_node, 0); + if (!guts) { + pr_err("p1022ds: could not map global utilties device\n"); + goto exit; } - brdcfg1 = pixis + 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */ + + 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); + } + 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 */ - clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT, - PX_BRDCFG1_DVIEN); + 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); break; case FSL_DIU_PORT_LVDS: - printk(KERN_INFO "%s:%u\n", __func__, __LINE__); + /* + * LVDS also needs backlight enabled, otherwise the display + * will be blank. + */ /* Enable the DFP port, disable the DVI and the backlight */ - clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT, - PX_BRDCFG1_DFPEN); + 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); break; default: pr_err("p1022ds: unsupported monitor port %i\n", port); } - iounmap(pixis); +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); } /** @@ -242,15 +330,56 @@ 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_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | 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 */ @@ -288,6 +417,34 @@ 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/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c index d951e7027bb6..6b07398e4369 100644 --- a/arch/powerpc/platforms/85xx/p1023_rds.c +++ b/arch/powerpc/platforms/85xx/p1023_rds.c @@ -93,9 +93,8 @@ 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_WANTS_RESET | MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c index 184a50784617..1677b8a22677 100644 --- a/arch/powerpc/platforms/85xx/sbc8548.c +++ b/arch/powerpc/platforms/85xx/sbc8548.c @@ -54,8 +54,7 @@ static int sbc_rev; static void __init sbc8548_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c index 940752e93051..3c3bbcc27566 100644 --- a/arch/powerpc/platforms/85xx/sbc8560.c +++ b/arch/powerpc/platforms/85xx/sbc8560.c @@ -41,8 +41,7 @@ static void __init sbc8560_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c index 18f635906b27..b71919217756 100644 --- a/arch/powerpc/platforms/85xx/socrates.c +++ b/arch/powerpc/platforms/85xx/socrates.c @@ -48,8 +48,7 @@ static void __init socrates_pic_init(void) { struct device_node *np; - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index e9e5234b4e76..27ca3a7b04ab 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c @@ -48,8 +48,7 @@ static void __init stx_gp3_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index bf7c89fb75bb..d7504cefe016 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/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_WANTS_RESET | MPIC_BIG_ENDIAN, + MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 3a69f8b77de6..503c21596c63 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c @@ -43,9 +43,7 @@ void __init xes_mpc85xx_pic_init(void) { - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | - MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, 0, 256, " OpenPIC "); BUG_ON(mpic == NULL); mpic_init(mpic); diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 8d6599d54ea6..7a6279e38213 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig @@ -39,6 +39,7 @@ 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. @@ -48,6 +49,7 @@ 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. @@ -57,6 +59,7 @@ 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/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 4b0d7b1aa005..ede815d6489d 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile @@ -7,7 +7,6 @@ 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 -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) +obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o +obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o +obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index 60ce07e39100..ed58b6cfd60c 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c @@ -37,9 +37,9 @@ #include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h> #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index 3ecee25bf3ed..710db69bd523 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c @@ -37,9 +37,9 @@ #include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h> #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index 5090d608d9ee..4a13d2f4ac20 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c @@ -37,9 +37,9 @@ #include <sysdev/fsl_pci.h> #include <sysdev/fsl_soc.h> +#include <sysdev/ge/ge_pic.h> #include "mpc86xx.h" -#include "gef_pic.h" #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c index 52bbfa031531..22cc3571ae19 100644 --- a/arch/powerpc/platforms/86xx/pic.c +++ b/arch/powerpc/platforms/86xx/pic.c @@ -37,9 +37,8 @@ void __init mpc86xx_init_irq(void) int cascade_irq; #endif - struct mpic *mpic = mpic_alloc(NULL, 0, - MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | - MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, + struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | + MPIC_SINGLE_DEST_CPU, 0, 256, " MPIC "); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 0cfb46d54b8c..a35ca44ade66 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig @@ -2,7 +2,6 @@ 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" @@ -87,6 +86,14 @@ 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 @@ -138,7 +145,7 @@ config MPIC_BROKEN_REGREAD of the register contents in software. config IBMVIO - depends on PPC_PSERIES || PPC_ISERIES + depends on PPC_PSERIES bool default y diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 2635a22bade2..879b4a448498 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile @@ -16,7 +16,6 @@ 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/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 62002a7edfed..fa3e294fd343 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c @@ -197,7 +197,8 @@ 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, 0, 0, " MPIC "); + mpic = mpic_alloc(dn, 0, MPIC_SECONDARY | MPIC_NO_RESET, + 0, 0, " MPIC "); if (mpic == NULL) continue; mpic_init(mpic); diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index d4a094ca96f3..1d75c92ea8fb 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -646,6 +646,7 @@ long spufs_create(struct path *path, struct dentry *dentry, out: mutex_unlock(&path->dentry->d_inode->i_mutex); + dput(dentry); return ret; } @@ -757,9 +758,9 @@ spufs_create_root(struct super_block *sb, void *data) goto out_iput; ret = -ENOMEM; - sb->s_root = d_alloc_root(inode); + sb->s_root = d_make_root(inode); if (!sb->s_root) - goto out_iput; + goto out; return 0; out_iput: @@ -828,19 +829,19 @@ static int __init spufs_init(void) ret = spu_sched_init(); if (ret) goto out_cache; - ret = register_filesystem(&spufs_type); + ret = register_spu_syscalls(&spufs_calls); if (ret) goto out_sched; - ret = register_spu_syscalls(&spufs_calls); + ret = register_filesystem(&spufs_type); if (ret) - goto out_fs; + goto out_syscalls; spufs_init_isolated_loader(); return 0; -out_fs: - unregister_filesystem(&spufs_type); +out_syscalls: + unregister_spu_syscalls(&spufs_calls); out_sched: spu_sched_exit(); out_cache: diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 8591bb62d7fc..5665dcc382c7 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -70,8 +70,6 @@ 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/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index f1f17bb2c33c..c665d7de6c99 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c @@ -435,7 +435,8 @@ static void __init chrp_find_openpic(void) if (len > 1) isu_size = iranges[3]; - chrp_mpic = mpic_alloc(np, opaddr, 0, isu_size, 0, " MPIC "); + chrp_mpic = mpic_alloc(np, opaddr, MPIC_NO_RESET, + isu_size, 0, " MPIC "); if (chrp_mpic == NULL) { printk(KERN_ERR "Failed to allocate MPIC structure\n"); goto bail; diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 9cfcf20c0560..ab51b21b4bd7 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c @@ -154,11 +154,9 @@ static void __init holly_init_IRQ(void) struct device_node *cascade_node = NULL; #endif - mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, - 24, - NR_IRQS-4, /* num_sources used */ + 24, 0, "Tsi108_PIC"); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index bcfad92c9cec..455e7c087422 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c @@ -82,8 +82,7 @@ static void __init linkstation_init_IRQ(void) { struct mpic *mpic; - mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, - 4, 32, " EPIC "); + mpic = mpic_alloc(NULL, 0, 0, 4, 0, " EPIC "); BUG_ON(mpic == NULL); /* PCI IRQs */ diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index f3350d786f5b..74ccce36baed 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c @@ -108,11 +108,9 @@ static void __init mpc7448_hpc2_init_IRQ(void) struct device_node *cascade_node = NULL; #endif - mpic = mpic_alloc(NULL, 0, - MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | + mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, - 24, - NR_IRQS-4, /* num_sources used */ + 24, 0, "Tsi108_PIC"); BUG_ON(mpic == NULL); diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c index afa638834965..e0ed3c71d69b 100644 --- a/arch/powerpc/platforms/embedded6xx/storcenter.c +++ b/arch/powerpc/platforms/embedded6xx/storcenter.c @@ -84,8 +84,7 @@ static void __init storcenter_init_IRQ(void) { struct mpic *mpic; - mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, - 16, 32, " OpenPIC "); + mpic = mpic_alloc(NULL, 0, 0, 16, 0, " OpenPIC "); BUG_ON(mpic == NULL); /* diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig deleted file mode 100644 index 63835e09e5cc..000000000000 --- a/arch/powerpc/platforms/iseries/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -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/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile deleted file mode 100644 index a7602b11ed9d..000000000000 --- a/arch/powerpc/platforms/iseries/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -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/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h deleted file mode 100644 index 8d95fe4b554e..000000000000 --- a/arch/powerpc/platforms/iseries/call_hpt.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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 <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> -#include <asm/mmu.h> - -#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/arch/powerpc/platforms/iseries/call_pci.h b/arch/powerpc/platforms/iseries/call_pci.h deleted file mode 100644 index dbdf69850ed9..000000000000 --- a/arch/powerpc/platforms/iseries/call_pci.h +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Provides the Hypervisor PCI calls for iSeries Linux Parition. - * Copyright (C) 2001 <Wayne G Holm> <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, Jan 9, 2001 - */ - -#ifndef _PLATFORMS_ISERIES_CALL_PCI_H -#define _PLATFORMS_ISERIES_CALL_PCI_H - -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -/* - * 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/arch/powerpc/platforms/iseries/call_sm.h b/arch/powerpc/platforms/iseries/call_sm.h deleted file mode 100644 index c7e251619f48..000000000000 --- a/arch/powerpc/platforms/iseries/call_sm.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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 <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - -#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/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c deleted file mode 100644 index f0491cc28900..000000000000 --- a/arch/powerpc/platforms/iseries/dt.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * 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 <linux/types.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/pci_regs.h> -#include <linux/pci_ids.h> -#include <linux/threads.h> -#include <linux/bitops.h> -#include <linux/string.h> -#include <linux/kernel.h> -#include <linux/if_ether.h> /* ETH_ALEN */ - -#include <asm/machdep.h> -#include <asm/prom.h> -#include <asm/lppaca.h> -#include <asm/cputable.h> -#include <asm/abs_addr.h> -#include <asm/system.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/udbg.h> - -#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/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S deleted file mode 100644 index f519ee17ff7d..000000000000 --- a/arch/powerpc/platforms/iseries/exception.S +++ /dev/null @@ -1,311 +0,0 @@ -/* - * 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 <cort@cs.nmt.edu> - * 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 <asm/reg.h> -#include <asm/ppc_asm.h> -#include <asm/asm-offsets.h> -#include <asm/thread_info.h> -#include <asm/ptrace.h> -#include <asm/cputable.h> -#include <asm/mmu.h> - -#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/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h deleted file mode 100644 index 50271b550a99..000000000000 --- a/arch/powerpc/platforms/iseries/exception.h +++ /dev/null @@ -1,58 +0,0 @@ -#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 <cort@cs.nmt.edu> - * 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 <asm/exception-64s.h> - -#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/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c deleted file mode 100644 index 3ae66ab9d5e7..000000000000 --- a/arch/powerpc/platforms/iseries/htab.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * iSeries hashtable management. - * Derived from pSeries_htab.c - * - * SMP scalability work: - * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, 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 <asm/machdep.h> -#include <asm/pgtable.h> -#include <asm/mmu.h> -#include <asm/mmu_context.h> -#include <asm/abs_addr.h> -#include <linux/spinlock.h> - -#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/arch/powerpc/platforms/iseries/hvcall.S b/arch/powerpc/platforms/iseries/hvcall.S deleted file mode 100644 index 07ae6ad5f49f..000000000000 --- a/arch/powerpc/platforms/iseries/hvcall.S +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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 <asm/ppc_asm.h> -#include <asm/processor.h> -#include <asm/ptrace.h> /* 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/arch/powerpc/platforms/iseries/hvlog.c b/arch/powerpc/platforms/iseries/hvlog.c deleted file mode 100644 index f476d71194fa..000000000000 --- a/arch/powerpc/platforms/iseries/hvlog.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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 <asm/page.h> -#include <asm/abs_addr.h> -#include <asm/iseries/hv_call.h> -#include <asm/iseries/hv_call_sc.h> -#include <asm/iseries/hv_types.h> - - -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/arch/powerpc/platforms/iseries/hvlpconfig.c b/arch/powerpc/platforms/iseries/hvlpconfig.c deleted file mode 100644 index f62a0c5fa670..000000000000 --- a/arch/powerpc/platforms/iseries/hvlpconfig.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 <linux/export.h> -#include <asm/iseries/hv_lp_config.h> -#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/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c deleted file mode 100644 index 2f3d9110248c..000000000000 --- a/arch/powerpc/platforms/iseries/iommu.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation - * - * Rewrite, cleanup: - * - * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation - * Copyright (C) 2006 Olof Johansson <olof@lixom.net> - * - * 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 <linux/types.h> -#include <linux/dma-mapping.h> -#include <linux/list.h> -#include <linux/pci.h> -#include <linux/export.h> -#include <linux/slab.h> - -#include <asm/iommu.h> -#include <asm/vio.h> -#include <asm/tce.h> -#include <asm/machdep.h> -#include <asm/abs_addr.h> -#include <asm/prom.h> -#include <asm/pci-bridge.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/hv_call_event.h> -#include <asm/iseries/iommu.h> - -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/arch/powerpc/platforms/iseries/ipl_parms.h b/arch/powerpc/platforms/iseries/ipl_parms.h deleted file mode 100644 index 83e4ca42fc57..000000000000 --- a/arch/powerpc/platforms/iseries/ipl_parms.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * 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 <asm/types.h> - -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/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c deleted file mode 100644 index 05ce5164cafc..000000000000 --- a/arch/powerpc/platforms/iseries/irq.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * This module supports the iSeries PCI bus interrupt handling - * Copyright (C) 20yy <Robert L Holtorf> <IBM Corp> - * 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 <linux/pci.h> -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/bootmem.h> -#include <linux/irq.h> -#include <linux/spinlock.h> - -#include <asm/paca.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/it_lp_queue.h> - -#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/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h deleted file mode 100644 index a1c236074034..000000000000 --- a/arch/powerpc/platforms/iseries/irq.h +++ /dev/null @@ -1,13 +0,0 @@ -#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/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h b/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h deleted file mode 100644 index 6de9097b7f57..000000000000 --- a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 <asm/types.h> - -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/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h deleted file mode 100644 index cf6dcf6ef07b..000000000000 --- a/arch/powerpc/platforms/iseries/it_lp_naca.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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 <linux/types.h> - -/* - * 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/arch/powerpc/platforms/iseries/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c deleted file mode 100644 index 997e234fb8b7..000000000000 --- a/arch/powerpc/platforms/iseries/ksyms.c +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (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 <linux/export.h> - -#include <asm/hw_irq.h> -#include <asm/iseries/hv_call_sc.h> - -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/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c deleted file mode 100644 index 00e0ec813a1c..000000000000 --- a/arch/powerpc/platforms/iseries/lpardata.c +++ /dev/null @@ -1,318 +0,0 @@ -/* - * 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 <linux/types.h> -#include <linux/threads.h> -#include <linux/bitops.h> -#include <asm/processor.h> -#include <asm/ptrace.h> -#include <asm/abs_addr.h> -#include <asm/lppaca.h> -#include <asm/paca.h> -#include <asm/iseries/lpar_map.h> -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/alpaca.h> - -#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/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c deleted file mode 100644 index 202e22798d30..000000000000 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * 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 <linux/stddef.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/bootmem.h> -#include <linux/seq_file.h> -#include <linux/proc_fs.h> -#include <linux/export.h> - -#include <asm/system.h> -#include <asm/paca.h> -#include <asm/firmware.h> -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_call_event.h> -#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/arch/powerpc/platforms/iseries/main_store.h b/arch/powerpc/platforms/iseries/main_store.h deleted file mode 100644 index 1a7a3f50e40b..000000000000 --- a/arch/powerpc/platforms/iseries/main_store.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c deleted file mode 100644 index 254c1fc3d8dd..000000000000 --- a/arch/powerpc/platforms/iseries/mf.c +++ /dev/null @@ -1,1275 +0,0 @@ -/* - * 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 <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/completion.h> -#include <linux/delay.h> -#include <linux/export.h> -#include <linux/proc_fs.h> -#include <linux/dma-mapping.h> -#include <linux/bcd.h> -#include <linux/rtc.h> -#include <linux/slab.h> - -#include <asm/time.h> -#include <asm/uaccess.h> -#include <asm/paca.h> -#include <asm/abs_addr.h> -#include <asm/firmware.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/it_lp_queue.h> - -#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/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S deleted file mode 100644 index 2c6ff0fdac98..000000000000 --- a/arch/powerpc/platforms/iseries/misc.S +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 <asm/processor.h> -#include <asm/asm-offsets.h> -#include <asm/ppc_asm.h> - - .text - -/* Handle pending interrupts in interrupt context */ -_GLOBAL(iseries_handle_interrupts) - li r0,0x5555 - sc - blr diff --git a/arch/powerpc/platforms/iseries/naca.h b/arch/powerpc/platforms/iseries/naca.h deleted file mode 100644 index f01708e12862..000000000000 --- a/arch/powerpc/platforms/iseries/naca.h +++ /dev/null @@ -1,24 +0,0 @@ -#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 <asm/types.h> - -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/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c deleted file mode 100644 index c75412884625..000000000000 --- a/arch/powerpc/platforms/iseries/pci.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * 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 <linux/jiffies.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/string.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/pci.h> -#include <linux/of.h> -#include <linux/ratelimit.h> - -#include <asm/types.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/prom.h> -#include <asm/machdep.h> -#include <asm/pci-bridge.h> -#include <asm/iommu.h> -#include <asm/abs_addr.h> -#include <asm/firmware.h> - -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/iommu.h> - -#include <asm/ppc-pci.h> - -#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/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h deleted file mode 100644 index d9cf974c2718..000000000000 --- a/arch/powerpc/platforms/iseries/pci.h +++ /dev/null @@ -1,58 +0,0 @@ -#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/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c deleted file mode 100644 index 06763682db47..000000000000 --- a/arch/powerpc/platforms/iseries/proc.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 <linux/init.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/param.h> /* for HZ */ -#include <asm/paca.h> -#include <asm/processor.h> -#include <asm/time.h> -#include <asm/lppaca.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_call_xm.h> - -#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/arch/powerpc/platforms/iseries/processor_vpd.h b/arch/powerpc/platforms/iseries/processor_vpd.h deleted file mode 100644 index 7ac5d0d0dbfa..000000000000 --- a/arch/powerpc/platforms/iseries/processor_vpd.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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 <asm/types.h> - -/* - * 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/arch/powerpc/platforms/iseries/release_data.h b/arch/powerpc/platforms/iseries/release_data.h deleted file mode 100644 index 6ad7d843e8fc..000000000000 --- a/arch/powerpc/platforms/iseries/release_data.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 <asm/types.h> -#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/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c deleted file mode 100644 index a5fbf4cb6329..000000000000 --- a/arch/powerpc/platforms/iseries/setup.c +++ /dev/null @@ -1,718 +0,0 @@ -/* - * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * 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 <cort@fsmlabs.com>, and Dan Malek - * <dan@net4x.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. - */ - -#undef DEBUG - -#include <linux/init.h> -#include <linux/threads.h> -#include <linux/smp.h> -#include <linux/param.h> -#include <linux/string.h> -#include <linux/export.h> -#include <linux/seq_file.h> -#include <linux/kdev_t.h> -#include <linux/kexec.h> -#include <linux/major.h> -#include <linux/root_dev.h> -#include <linux/kernel.h> -#include <linux/hrtimer.h> -#include <linux/tick.h> - -#include <asm/processor.h> -#include <asm/machdep.h> -#include <asm/page.h> -#include <asm/mmu.h> -#include <asm/pgtable.h> -#include <asm/mmu_context.h> -#include <asm/cputable.h> -#include <asm/sections.h> -#include <asm/iommu.h> -#include <asm/firmware.h> -#include <asm/system.h> -#include <asm/time.h> -#include <asm/paca.h> -#include <asm/cache.h> -#include <asm/abs_addr.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_call_event.h> -#include <asm/iseries/hv_call_xm.h> -#include <asm/iseries/it_lp_queue.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/lpar_map.h> -#include <asm/udbg.h> -#include <asm/irq.h> - -#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/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h deleted file mode 100644 index 729754bbb018..000000000000 --- a/arch/powerpc/platforms/iseries/setup.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> - * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> - * - * 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 <cort@cs.nmt.edu>, and Dan Malek - * <dan@netx4.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. - */ - -#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/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c deleted file mode 100644 index 02df49fb59f0..000000000000 --- a/arch/powerpc/platforms/iseries/smp.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/interrupt.h> -#include <linux/kernel_stat.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/spinlock.h> -#include <linux/cache.h> -#include <linux/err.h> -#include <linux/device.h> -#include <linux/cpu.h> - -#include <asm/ptrace.h> -#include <linux/atomic.h> -#include <asm/irq.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/smp.h> -#include <asm/paca.h> -#include <asm/iseries/hv_call.h> -#include <asm/time.h> -#include <asm/machdep.h> -#include <asm/cputable.h> -#include <asm/system.h> - -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/arch/powerpc/platforms/iseries/spcomm_area.h b/arch/powerpc/platforms/iseries/spcomm_area.h deleted file mode 100644 index 598b7c14573a..000000000000 --- a/arch/powerpc/platforms/iseries/spcomm_area.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c deleted file mode 100644 index 04be62d368a6..000000000000 --- a/arch/powerpc/platforms/iseries/vio.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * 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 <linux/of.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/completion.h> -#include <linux/proc_fs.h> -#include <linux/export.h> - -#include <asm/firmware.h> -#include <asm/vio.h> -#include <asm/iseries/vio.h> -#include <asm/iseries/iommu.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> - -#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/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c deleted file mode 100644 index 40dad0840eb3..000000000000 --- a/arch/powerpc/platforms/iseries/viopath.c +++ /dev/null @@ -1,677 +0,0 @@ -/* -*- linux-c -*- - * - * iSeries Virtual I/O Message Path code - * - * Authors: Dave Boutcher <boutcher@us.ibm.com> - * Ryan Arnold <ryanarn@us.ibm.com> - * Colin Devilbiss <devilbis@us.ibm.com> - * - * (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 <linux/export.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/vmalloc.h> -#include <linux/string.h> -#include <linux/proc_fs.h> -#include <linux/dma-mapping.h> -#include <linux/wait.h> -#include <linux/seq_file.h> -#include <linux/interrupt.h> -#include <linux/completion.h> - -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/prom.h> -#include <asm/firmware.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/mf.h> -#include <asm/iseries/vio.h> - -/* 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=<UNKNOWN>\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/arch/powerpc/platforms/iseries/vpd_areas.h b/arch/powerpc/platforms/iseries/vpd_areas.h deleted file mode 100644 index feb001f3a5fe..000000000000 --- a/arch/powerpc/platforms/iseries/vpd_areas.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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 <asm/types.h> - -/* 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/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 0bcbfe7b2c55..3b7545a51aa9 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/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 | MPIC_WANTS_RESET; + flags |= MPIC_U3_HT_IRQS; /* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */ flags |= MPIC_BIG_ENDIAN; diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 98b7a7c13176..e777ad471a48 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/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_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS | MPIC_NO_RESET; nmiprop = of_get_property(mpic_node, "nmi-source", NULL); if (nmiprop) diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index 54d227127c9f..da18b26dcc6f 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/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, i; + int stat; unsigned long timeout; u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; @@ -301,11 +301,10 @@ static int sm_erase_bank(int bank) out_8(base, SM_FLASH_CMD_CLEAR_STATUS); out_8(base, SM_FLASH_CMD_RESET); - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != 0xff) { - printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); - return -ENXIO; - } + if (memchr_inv(base, 0xff, NVRAM_SIZE)) { + printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); + return -ENXIO; + } return 0; } @@ -336,17 +335,16 @@ static int sm_write_bank(int bank, u8* datas) } out_8(base, SM_FLASH_CMD_CLEAR_STATUS); out_8(base, SM_FLASH_CMD_RESET); - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != datas[i]) { - printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); - return -ENXIO; - } + if (memcmp(base, datas, NVRAM_SIZE)) { + printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); + return -ENXIO; + } return 0; } static int amd_erase_bank(int bank) { - int i, stat = 0; + int stat = 0; unsigned long timeout; u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; @@ -382,12 +380,11 @@ static int amd_erase_bank(int bank) /* Reset */ out_8(base, 0xf0); udelay(1); - - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != 0xff) { - printk(KERN_ERR "nvram: AMD flash erase failed !\n"); - return -ENXIO; - } + + if (memchr_inv(base, 0xff, NVRAM_SIZE)) { + printk(KERN_ERR "nvram: AMD flash erase failed !\n"); + return -ENXIO; + } return 0; } @@ -429,11 +426,10 @@ static int amd_write_bank(int bank, u8* datas) out_8(base, 0xf0); udelay(1); - for (i=0; i<NVRAM_SIZE; i++) - if (base[i] != datas[i]) { - printk(KERN_ERR "nvram: AMD flash write failed !\n"); - return -ENXIO; - } + if (memcmp(base, datas, NVRAM_SIZE)) { + printk(KERN_ERR "nvram: AMD flash write failed !\n"); + return -ENXIO; + } return 0; } diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 92afc382a49e..66ad93de1d55 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c @@ -457,7 +457,6 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np, pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); - flags |= MPIC_WANTS_RESET; if (of_get_property(np, "big-endian", NULL)) flags |= MPIC_BIG_ENDIAN; diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index f92b9ef7340e..214478d781ae 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c @@ -31,6 +31,7 @@ #include <asm/iommu.h> #include <asm/tce.h> #include <asm/abs_addr.h> +#include <asm/firmware.h> #include "powernv.h" #include "pci.h" diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 467bd4ac6824..db1ad1c8f68f 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c @@ -31,7 +31,6 @@ #include <asm/xics.h> #include <asm/rtas.h> #include <asm/opal.h> -#include <asm/xics.h> #include "powernv.h" diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index f2556257bbdc..aadbe4f6d537 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig @@ -73,7 +73,7 @@ config IO_EVENT_IRQ config LPARCFG bool "LPAR Configuration Data" - depends on PPC_PSERIES || PPC_ISERIES + depends on PPC_PSERIES help Provide system capacity information via human readable <key word>=<value> pairs through a /proc/ppc64/lparcfg interface. diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 236db46b4078..c222189f5bb2 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile @@ -6,7 +6,8 @@ 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_cache.o eeh_driver.o eeh_event.o eeh_sysfs.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_KEXEC) += kexec.o obj-$(CONFIG_PCI) += pci.o pci_dlpar.o obj-$(CONFIG_PSERIES_MSI) += msi.o @@ -18,7 +19,6 @@ 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/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index c0b40af4ce4f..8011088392d3 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/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 <linux/delay.h> -#include <linux/sched.h> /* for init_mm */ +#include <linux/sched.h> #include <linux/init.h> #include <linux/list.h> #include <linux/pci.h> @@ -86,16 +86,8 @@ /* Time to wait for a PCI slot to report status, in milliseconds */ #define PCI_BUS_RESET_WAIT_MSEC (60*1000) -/* 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; +/* Platform dependent EEH operations */ +struct eeh_ops *eeh_ops = NULL; int eeh_subsystem_enabled; EXPORT_SYMBOL(eeh_subsystem_enabled); @@ -103,14 +95,6 @@ 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. @@ -118,74 +102,50 @@ static int eeh_error_buf_size; #define EEH_PCI_REGS_LOG_LEN 4096 static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN]; -/* 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 */ +/* + * 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 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; +static struct eeh_stats eeh_stats; - /* 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); -} +#define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) /** - * gather_pci_data - copy assorted PCI config space registers to buff - * @pdn: device to report data for + * eeh_gather_pci_data - Copy assorted PCI config space registers to buff + * @edev: 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 gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) +static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) { - struct pci_dev *dev = pdn->pcidev; + struct device_node *dn = eeh_dev_to_of_node(edev); + struct pci_dev *dev = eeh_dev_to_pci_dev(edev); u32 cfg; int cap, i; int n = 0; - n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name); - printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name); + n += scnprintf(buf+n, len-n, "%s\n", dn->full_name); + printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name); - rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg); + eeh_ops->read_config(dn, 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); - rtas_read_config(pdn, PCI_COMMAND, 4, &cfg); + eeh_ops->read_config(dn, 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); @@ -196,11 +156,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) /* Gather bridge-specific registers */ if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { - rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg); + eeh_ops->read_config(dn, 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); - rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg); + eeh_ops->read_config(dn, 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); } @@ -208,11 +168,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, 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) { - rtas_read_config(pdn, cap, 4, &cfg); + eeh_ops->read_config(dn, cap, 4, &cfg); n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg); printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); - rtas_read_config(pdn, cap+4, 4, &cfg); + eeh_ops->read_config(dn, 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); } @@ -225,7 +185,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) "EEH: PCI-E capabilities and status follow:\n"); for (i=0; i<=8; i++) { - rtas_read_config(pdn, cap+4*i, 4, &cfg); + eeh_ops->read_config(dn, 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); } @@ -237,7 +197,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) "EEH: PCI-E AER capability register set follows:\n"); for (i=0; i<14; i++) { - rtas_read_config(pdn, cap+4*i, 4, &cfg); + eeh_ops->read_config(dn, 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); } @@ -246,111 +206,46 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) /* Gather status on devices under the bridge */ if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { - struct device_node *dn; + struct device_node *child; - for_each_child_of_node(pdn->node, dn) { - pdn = PCI_DN(dn); - if (pdn) - n += gather_pci_data(pdn, buf+n, len-n); + 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); } } return n; } -void eeh_slot_error_detail(struct pci_dn *pdn, int severity) -{ - size_t loglen = 0; - pci_regs_buf[0] = 0; - - 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); - - rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); -} - /** - * 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 - * - * Return negative value if a permanent error, else return - * Partition Endpoint (PE) status value. + * 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 * - * 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. + * 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. */ -int -eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs) +void eeh_slot_error_detail(struct eeh_dev *edev, int severity) { - 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 */ + size_t loglen = 0; + pci_regs_buf[0] = 0; - if (max_wait_msecs <= 0) break; + 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); - 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_ops->get_log(eeh_dev_to_of_node(edev), 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.... + * eeh_token_to_phys - Convert EEH address token to phys address + * @token: I/O token, should be address in the form 0xA.... + * + * This routine should be called to convert virtual I/O address + * to physical one. */ static inline unsigned long eeh_token_to_phys(unsigned long token) { @@ -365,36 +260,43 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) return pa | (token & (PAGE_SIZE-1)); } -/** - * Return the "partitionable endpoint" (pe) under which this device lies +/** + * eeh_find_device_pe - Retrieve the PE for the given device + * @dn: device node + * + * Return the PE under which this device lies */ -struct device_node * find_device_pe(struct device_node *dn) +struct device_node *eeh_find_device_pe(struct device_node *dn) { - while ((dn->parent) && PCI_DN(dn->parent) && - (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { + while (dn->parent && of_node_to_eeh_dev(dn->parent) && + (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { dn = dn->parent; } return dn; } -/** 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. +/** + * __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. */ - static void __eeh_mark_slot(struct device_node *parent, int mode_flag) { struct device_node *dn; for_each_child_of_node(parent, dn) { - if (PCI_DN(dn)) { + if (of_node_to_eeh_dev(dn)) { /* Mark the pci device driver too */ - struct pci_dev *dev = PCI_DN(dn)->pcidev; + struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; - PCI_DN(dn)->eeh_mode |= mode_flag; + of_node_to_eeh_dev(dn)->mode |= mode_flag; if (dev && dev->driver) dev->error_state = pci_channel_io_frozen; @@ -404,92 +306,81 @@ static void __eeh_mark_slot(struct device_node *parent, int mode_flag) } } -void eeh_mark_slot (struct device_node *dn, 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) { struct pci_dev *dev; - dn = find_device_pe (dn); + dn = eeh_find_device_pe(dn); /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) dn = dn->parent; - PCI_DN(dn)->eeh_mode |= mode_flag; + of_node_to_eeh_dev(dn)->mode |= mode_flag; /* Mark the pci device too */ - dev = PCI_DN(dn)->pcidev; + dev = of_node_to_eeh_dev(dn)->pdev; 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 (PCI_DN(dn)) { - PCI_DN(dn)->eeh_mode &= ~mode_flag; - PCI_DN(dn)->eeh_check_count = 0; + 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; __eeh_clear_slot(dn, mode_flag); } } } -void eeh_clear_slot (struct device_node *dn, int 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) { unsigned long flags; raw_spin_lock_irqsave(&confirm_error_lock, flags); - dn = find_device_pe (dn); + dn = eeh_find_device_pe(dn); /* Back up one, since config addrs might be shared */ - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) dn = dn->parent; - PCI_DN(dn)->eeh_mode &= ~mode_flag; - PCI_DN(dn)->eeh_check_count = 0; + of_node_to_eeh_dev(dn)->mode &= ~mode_flag; + of_node_to_eeh_dev(dn)->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 @@ -504,35 +395,34 @@ void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) { int ret; - int rets[3]; unsigned long flags; - struct pci_dn *pdn; + struct eeh_dev *edev; int rc = 0; const char *location; - total_mmio_ffs++; + eeh_stats.total_mmio_ffs++; if (!eeh_subsystem_enabled) return 0; if (!dn) { - no_dn++; + eeh_stats.no_dn++; return 0; } - dn = find_device_pe(dn); - pdn = PCI_DN(dn); + dn = eeh_find_device_pe(dn); + edev = of_node_to_eeh_dev(dn); /* Access to IO BARs might get this far and still not want checking. */ - if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || - pdn->eeh_mode & EEH_MODE_NOCHECK) { - ignored_check++; + if (!(edev->mode & EEH_MODE_SUPPORTED) || + edev->mode & EEH_MODE_NOCHECK) { + eeh_stats.ignored_check++; pr_debug("EEH: Ignored check (%x) for %s %s\n", - pdn->eeh_mode, eeh_pci_name(dev), dn->full_name); + edev->mode, eeh_pci_name(dev), dn->full_name); return 0; } - if (!pdn->eeh_config_addr && !pdn->eeh_pe_config_addr) { - no_cfg_addr++; + if (!edev->config_addr && !edev->pe_config_addr) { + eeh_stats.no_cfg_addr++; return 0; } @@ -544,15 +434,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 (pdn->eeh_mode & EEH_MODE_ISOLATED) { - pdn->eeh_check_count ++; - if (pdn->eeh_check_count % EEH_MAX_FAILS == 0) { + if (edev->mode & EEH_MODE_ISOLATED) { + edev->check_count++; + if (edev->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", - pdn->eeh_check_count, location, + edev->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(); } @@ -566,58 +456,39 @@ 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 = 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; - } + ret = eeh_ops->get_state(dn, NULL); /* Note that config-io to empty slots may fail; - * 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; - } - - /* 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 ++; + * 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 ++; rc = 0; goto dn_unlock; } - slot_resets++; + eeh_stats.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 (dn, dev); + eeh_send_failure_event(edev); /* 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; @@ -629,9 +500,9 @@ dn_unlock: 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 @@ -648,14 +519,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_get_device_by_addr(addr); + dev = pci_addr_cache_get_device(addr); if (!dev) { - no_device++; + eeh_stats.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; @@ -663,115 +534,54 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon EXPORT_SYMBOL(eeh_check_failure); -/* ------------------------------------------------------------- */ -/* The code below deals with error recovery */ /** - * rtas_pci_enable - enable MMIO or DMA transfers for this slot - * @pdn pci device node + * 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. */ - -int -rtas_pci_enable(struct pci_dn *pdn, int function) +int eeh_pci_enable(struct eeh_dev *edev, int function) { - int config_addr; int rc; + struct device_node *dn = eeh_dev_to_of_node(edev); - /* 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); - + rc = eeh_ops->set_option(dn, function); if (rc) printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", - function, rc, pdn->node->full_name); + function, rc, dn->full_name); - rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC); - if ((rc == 4) && (function == EEH_THAW_MMIO)) + rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); + if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) && + (function == EEH_OPT_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: - rtas_pci_slot_reset(pdn, 0); + eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); break; case pcie_hot_reset: - rtas_pci_slot_reset(pdn, 1); + eeh_ops->reset(dn, EEH_RESET_HOT); break; case pcie_warm_reset: - rtas_pci_slot_reset(pdn, 3); + eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); break; default: return -EINVAL; @@ -781,13 +591,66 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat } /** - * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second - * @pdn: pci device node to be reset. + * __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. */ +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; -static void __rtas_set_slot_reset(struct pci_dn *pdn) + __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) { 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) @@ -795,58 +658,68 @@ static void __rtas_set_slot_reset(struct pci_dn *pdn) * A fundamental reset required by any device under * Partitionable Endpoint trumps hot-reset. */ - eeh_set_pe_freset(pdn->node, &freset); + eeh_set_pe_freset(dn, &freset); if (freset) - rtas_pci_slot_reset(pdn, 3); + eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); else - rtas_pci_slot_reset(pdn, 1); + eeh_ops->reset(dn, EEH_RESET_HOT); /* 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 (pdn->node, EEH_MODE_ISOLATED); + * these, and clear the flag now. + */ + eeh_clear_slot(dn, EEH_MODE_ISOLATED); - rtas_pci_slot_reset (pdn, 0); + eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); /* 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); } -int rtas_set_slot_reset(struct pci_dn *pdn) +/** + * 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 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++) { - __rtas_set_slot_reset(pdn); + eeh_reset_pe_once(edev); - rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC); - if (rc == 0) + rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); + if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) return 0; if (rc < 0) { printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", - pdn->node->full_name); + dn->full_name); return -1; } printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", - i+1, pdn->node->full_name, rc); + i+1, dn->full_name, rc); } return -1; } -/* ------------------------------------------------------- */ /** Save and restore of PCI BARs * * Although firmware will set up BARs during boot, it doesn't @@ -856,181 +729,122 @@ int rtas_set_slot_reset(struct pci_dn *pdn) */ /** - * __restore_bars - Restore the Base Address Registers - * @pdn: pci device node + * eeh_restore_one_device_bars - Restore the Base Address Registers for one device + * @edev: PCI device associated EEH device * * 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 __restore_bars (struct pci_dn *pdn) +static inline void eeh_restore_one_device_bars(struct eeh_dev *edev) { 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++) { - rtas_write_config(pdn, i*4, 4, pdn->config_space[i]); + eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); } /* 12 == Expansion ROM Address */ - rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]); + eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) -#define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)]) +#define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) - rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1, + eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, SAVED_BYTE(PCI_CACHE_LINE_SIZE)); - rtas_write_config (pdn, PCI_LATENCY_TIMER, 1, + eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, SAVED_BYTE(PCI_LATENCY_TIMER)); /* max latency, min grant, interrupt pin and line */ - rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]); + eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); /* Restore PERR & SERR bits, some devices require it, - don't touch the other command bits */ - rtas_read_config(pdn, PCI_COMMAND, 4, &cmd); - if (pdn->config_space[1] & PCI_COMMAND_PARITY) + * don't touch the other command bits + */ + eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); + if (edev->config_space[1] & PCI_COMMAND_PARITY) cmd |= PCI_COMMAND_PARITY; else cmd &= ~PCI_COMMAND_PARITY; - if (pdn->config_space[1] & PCI_COMMAND_SERR) + if (edev->config_space[1] & PCI_COMMAND_SERR) cmd |= PCI_COMMAND_SERR; else cmd &= ~PCI_COMMAND_SERR; - rtas_write_config(pdn, PCI_COMMAND, 4, cmd); + eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); } /** - * eeh_restore_bars - restore the PCI config space info + * eeh_restore_bars - Restore the PCI config space info + * @edev: EEH device * * This routine performs a recursive walk to the children * of this device as well. */ -void eeh_restore_bars(struct pci_dn *pdn) +void eeh_restore_bars(struct eeh_dev *edev) { struct device_node *dn; - if (!pdn) + if (!edev) return; - if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code)) - __restore_bars (pdn); + if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code)) + eeh_restore_one_device_bars(edev); - for_each_child_of_node(pdn->node, dn) - eeh_restore_bars (PCI_DN(dn)); + for_each_child_of_node(eeh_dev_to_of_node(edev), dn) + eeh_restore_bars(of_node_to_eeh_dev(dn)); } /** - * eeh_save_bars - save device bars + * eeh_save_bars - Save device bars + * @edev: PCI device associated EEH device * * 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 pci_dn *pdn) +static void eeh_save_bars(struct eeh_dev *edev) { int i; + struct device_node *dn; - if (!pdn ) + if (!edev) return; + dn = eeh_dev_to_of_node(edev); for (i = 0; i < 16; i++) - rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]); -} - -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); - } + eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]); } -/* ------------------------------------------------------------- */ -/* 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. +/** + * 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. */ - -#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) +static void *eeh_early_enable(struct device_node *dn, void *data) { - 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 pci_dn *pdn = PCI_DN(dn); + struct eeh_dev *edev = of_node_to_eeh_dev(dn); - pdn->class_code = 0; - pdn->eeh_mode = 0; - pdn->eeh_check_count = 0; - pdn->eeh_freeze_count = 0; - pdn->eeh_false_positives = 0; + edev->class_code = 0; + edev->mode = 0; + edev->check_count = 0; + edev->freeze_count = 0; + edev->false_positives = 0; if (!of_device_is_available(dn)) return NULL; @@ -1041,54 +855,56 @@ static void *early_enable_eeh(struct device_node *dn, void *data) /* There is nothing to check on PCI to ISA bridges */ if (dn->type && !strcmp(dn->type, "isa")) { - pdn->eeh_mode |= EEH_MODE_NOCHECK; + edev->mode |= EEH_MODE_NOCHECK; return NULL; } - pdn->class_code = *class_code; + edev->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 = rtas_call(ibm_set_eeh_option, 4, 1, NULL, - regs[0], info->buid_hi, info->buid_lo, - EEH_ENABLE); + ret = eeh_ops->set_option(dn, EEH_OPT_ENABLE); enable = 0; if (ret == 0) { - pdn->eeh_config_addr = regs[0]; + edev->config_addr = regs[0]; /* If the newer, better, ibm,get-config-addr-info is supported, - * then use that instead. */ - pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info); + * then use that instead. + */ + edev->pe_config_addr = eeh_ops->get_pe_addr(dn); /* 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 = read_slot_reset_state(pdn, rets); - if ((ret == 0) && (rets[1] == 1)) + * explicitly. + */ + ret = eeh_ops->get_state(dn, NULL); + if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT) enable = 1; } if (enable) { eeh_subsystem_enabled = 1; - pdn->eeh_mode |= EEH_MODE_SUPPORTED; + edev->mode |= EEH_MODE_SUPPORTED; pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", - dn->full_name, pdn->eeh_config_addr, - pdn->eeh_pe_config_addr); + dn->full_name, edev->config_addr, + edev->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 && PCI_DN(dn->parent) - && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { + * 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)) { /* Parent supports EEH. */ - pdn->eeh_mode |= EEH_MODE_SUPPORTED; - pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr; + edev->mode |= EEH_MODE_SUPPORTED; + edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr; return NULL; } } @@ -1097,11 +913,63 @@ static void *early_enable_eeh(struct device_node *dn, void *data) dn->full_name); } - eeh_save_bars(pdn); + eeh_save_bars(edev); 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 @@ -1117,50 +985,35 @@ static void *early_enable_eeh(struct device_node *dn, void *data) void __init eeh_init(void) { struct device_node *phb, *np; - struct eeh_early_enable_info info; + 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; + } 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 || PCI_DN(phb) == NULL) + if (buid == 0 || !of_node_to_eeh_dev(phb)) continue; - info.buid_lo = BUID_LO(buid); - info.buid_hi = BUID_HI(buid); - traverse_pci_devices(phb, early_enable_eeh, &info); + traverse_pci_devices(phb, eeh_early_enable, NULL); } if (eeh_subsystem_enabled) @@ -1170,7 +1023,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 @@ -1184,21 +1037,26 @@ 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 || !PCI_DN(dn)) + if (!dn || !of_node_to_eeh_dev(dn)) return; - phb = PCI_DN(dn)->phb; + phb = of_node_to_eeh_dev(dn)->phb; /* USB Bus children of PCI devices will not have BUID's */ if (NULL == phb || 0 == phb->buid) return; - info.buid_hi = BUID_HI(phb->buid); - info.buid_lo = BUID_LO(phb->buid); - early_enable_eeh(dn, &info); + eeh_early_enable(dn, NULL); } +/** + * 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; @@ -1210,7 +1068,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 @@ -1219,7 +1077,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); static void eeh_add_device_late(struct pci_dev *dev) { struct device_node *dn; - struct pci_dn *pdn; + struct eeh_dev *edev; if (!dev || !eeh_subsystem_enabled) return; @@ -1227,20 +1085,29 @@ 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); - pdn = PCI_DN(dn); - if (pdn->pcidev == dev) { + edev = pci_dev_to_eeh_dev(dev); + if (edev->pdev == dev) { pr_debug("EEH: Already referenced !\n"); return; } - WARN_ON(pdn->pcidev); + WARN_ON(edev->pdev); - pci_dev_get (dev); - pdn->pcidev = dev; + pci_dev_get(dev); + edev->pdev = dev; + dev->dev.archdata.edev = edev; 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; @@ -1257,7 +1124,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 @@ -1268,25 +1135,35 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); */ static void eeh_remove_device(struct pci_dev *dev) { - struct device_node *dn; + struct eeh_dev *edev; + 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)); - dn = pci_device_to_OF_node(dev); - if (PCI_DN(dn)->pcidev == NULL) { + if (!edev || !edev->pdev) { pr_debug("EEH: Not referenced !\n"); return; } - PCI_DN(dn)->pcidev = NULL; - pci_dev_put (dev); + edev->pdev = NULL; + dev->dev.archdata.edev = 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; @@ -1305,21 +1182,24 @@ 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=%ld\n", total_mmio_ffs); + seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); } else { seq_printf(m, "EEH Subsystem is enabled\n"); seq_printf(m, - "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); + "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); } return 0; diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index fc5ae767989e..e5ae1c687c66 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c @@ -1,5 +1,4 @@ /* - * eeh_cache.c * PCI address cache; allows the lookup of PCI devices based on I/O address * * Copyright IBM Corporation 2004 @@ -47,8 +46,7 @@ * 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; @@ -56,13 +54,12 @@ 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_get_device_by_addr(unsigned long addr) +static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) { struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; @@ -86,7 +83,7 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) } /** - * pci_get_device_by_addr - Get device, given only address + * pci_addr_cache_get_device - 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 @@ -95,13 +92,13 @@ static inline struct pci_dev *__pci_get_device_by_addr(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_get_device_by_addr(unsigned long addr) +struct pci_dev *pci_addr_cache_get_device(unsigned long addr) { struct pci_dev *dev; unsigned long flags; spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); - dev = __pci_get_device_by_addr(addr); + dev = __pci_addr_cache_get_device(addr); spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); return dev; } @@ -166,7 +163,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); @@ -178,7 +175,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 pci_dn *pdn; + struct eeh_dev *edev; int i; dn = pci_device_to_OF_node(dev); @@ -187,13 +184,19 @@ 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. */ - pdn = PCI_DN(dn); - if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || - pdn->eeh_mode & EEH_MODE_NOCHECK) { + if (!(edev->mode & EEH_MODE_SUPPORTED) || + edev->mode & EEH_MODE_NOCHECK) { #ifdef DEBUG - printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n", - pci_name(dev), pdn->node->full_name); + pr_info("PCI: skip building address cache for=%s - %s\n", + pci_name(dev), dn->full_name); #endif return; } @@ -284,6 +287,7 @@ 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); @@ -294,8 +298,14 @@ 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() */ - PCI_DN(dn)->pcidev = dev; + dev->dev.archdata.edev = edev; + edev->pdev = dev; eeh_sysfs_add_device(dev); } diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/platforms/pseries/eeh_dev.c new file mode 100644 index 000000000000..f3aed7dcae95 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_dev.c @@ -0,0 +1,102 @@ +/* + * 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 <linux/export.h> +#include <linux/gfp.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/string.h> + +#include <asm/pci-bridge.h> +#include <asm/ppc-pci.h> + +/** + * 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/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 1b6cb10589e0..baf92cd9dfab 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c @@ -33,8 +33,14 @@ #include <asm/prom.h> #include <asm/rtas.h> - -static inline const char * pcid_name (struct pci_dev *pdev) +/** + * 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) { if (pdev && pdev->dev.driver) return pdev->dev.driver->name; @@ -64,48 +70,59 @@ static void print_device_node_tree(struct pci_dn *pdn, int dent) #endif /** - * eeh_disable_irq - disable interrupt for the recovering device + * 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. */ static void eeh_disable_irq(struct pci_dev *dev) { - struct device_node *dn = pci_device_to_OF_node(dev); + struct eeh_dev *edev = pci_dev_to_eeh_dev(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; - PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; + edev->mode |= EEH_MODE_IRQ_DISABLED; disable_irq_nosync(dev->irq); } /** - * eeh_enable_irq - enable interrupt for the recovering device + * 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. */ static void eeh_enable_irq(struct pci_dev *dev) { - struct device_node *dn = pci_device_to_OF_node(dev); + struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); - if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { - PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; + if ((edev->mode) & EEH_MODE_IRQ_DISABLED) { + edev->mode &= ~EEH_MODE_IRQ_DISABLED; enable_irq(dev->irq); } } -/* ------------------------------------------------------- */ /** - * eeh_report_error - report pci error to each device driver + * eeh_report_error - Report pci error to each device driver + * @dev: PCI device + * @userdata: return value * * 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; @@ -122,7 +139,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; @@ -132,13 +149,14 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) } /** - * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled + * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled + * @dev: PCI device + * @userdata: return value * * 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; @@ -149,7 +167,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; @@ -159,9 +177,15 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) } /** - * eeh_report_reset - tell device that slot has been reset + * 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. */ - static int eeh_report_reset(struct pci_dev *dev, void *userdata) { enum pci_ers_result rc, *res = userdata; @@ -188,9 +212,14 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata) } /** - * eeh_report_resume - tell device to resume normal operations + * 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. */ - static int eeh_report_resume(struct pci_dev *dev, void *userdata) { struct pci_driver *driver = dev->driver; @@ -212,12 +241,13 @@ static int eeh_report_resume(struct pci_dev *dev, void *userdata) } /** - * eeh_report_failure - tell device driver that device is dead. + * eeh_report_failure - Tell device driver that device is dead. + * @dev: PCI device + * @userdata: return value * * 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; @@ -238,65 +268,46 @@ static int eeh_report_failure(struct pci_dev *dev, void *userdata) return 0; } -/* ------------------------------------------------------- */ /** - * 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. + * eeh_reset_device - Perform actual reset of a pci slot + * @edev: PE associated EEH device + * @bus: PCI bus corresponding to the isolcated slot * - * 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). + * 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. */ - -/** - * 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) +static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) { struct device_node *dn; int cnt, rc; /* pcibios will clear the counter; save the value */ - cnt = pe_dn->eeh_freeze_count; + cnt = edev->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 = rtas_set_slot_reset(pe_dn); + * up if the reset failed for some reason. + */ + rc = eeh_reset_pe(edev); if (rc) return rc; - /* Walk over all functions on this device. */ - dn = pe_dn->node; - if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) + /* 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)) dn = dn->parent->child; while (dn) { - struct pci_dn *ppe = PCI_DN(dn); + struct eeh_dev *pedev = of_node_to_eeh_dev(dn); + /* On Power4, always true because eeh_pe_config_addr=0 */ - if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { - rtas_configure_bridge(ppe); - eeh_restore_bars(ppe); + if (edev->pe_config_addr == pedev->pe_config_addr) { + eeh_ops->configure_bridge(dn); + eeh_restore_bars(pedev); } dn = dn->sibling; } @@ -308,10 +319,10 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) * potentially weird things happen. */ if (bus) { - ssleep (5); + ssleep(5); pcibios_add_pci_devices(bus); } - pe_dn->eeh_freeze_count = cnt; + edev->freeze_count = cnt; return 0; } @@ -321,23 +332,39 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) */ #define MAX_WAIT_FOR_RECOVERY 150 -struct pci_dn * handle_eeh_events (struct eeh_event *event) +/** + * 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 device_node *frozen_dn; - struct pci_dn *frozen_pdn; + struct eeh_dev *frozen_edev; 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 = find_device_pe(event->dn); + frozen_dn = eeh_find_device_pe(eeh_dev_to_of_node(event->edev)); if (!frozen_dn) { - - location = of_get_property(event->dn, "ibm,loc-code", NULL); + location = of_get_property(eeh_dev_to_of_node(event->edev), "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(event->dev)); + location, eeh_pci_name(eeh_dev_to_pci_dev(event->edev))); return NULL; } @@ -350,9 +377,10 @@ struct pci_dn * 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 " @@ -361,22 +389,21 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) return NULL; } - frozen_pdn = PCI_DN(frozen_dn); - frozen_pdn->eeh_freeze_count++; + 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)); - pci_str = eeh_pci_name(event->dev); - drv_str = pcid_name(event->dev); - - if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) + if (frozen_edev->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_pdn->eeh_freeze_count); + frozen_edev->freeze_count); - if (frozen_pdn->pcidev) { - bus_pci_str = pci_name(frozen_pdn->pcidev); - bus_drv_str = pcid_name(frozen_pdn->pcidev); + if (frozen_edev->pdev) { + bus_pci_str = pci_name(frozen_edev->pdev); + bus_drv_str = eeh_pcid_name(frozen_edev->pdev); printk(KERN_WARNING "EEH: Bus location=%s driver=%s pci addr=%s\n", location, bus_drv_str, bus_pci_str); @@ -395,9 +422,10 @@ struct pci_dn * 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_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000); - if (rc < 0) { + * 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) { printk(KERN_WARNING "EEH: Permanent failure\n"); goto hard_fail; } @@ -406,14 +434,14 @@ struct pci_dn * 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_pdn, EEH_LOG_TEMP_FAILURE); + eeh_slot_error_detail(frozen_edev, EEH_LOG_TEMP); /* 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_pdn, frozen_bus); + rc = eeh_reset_device(frozen_edev, frozen_bus); if (rc) { printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); goto hard_fail; @@ -422,7 +450,7 @@ struct pci_dn * 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 = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO); + rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_MMIO); if (rc < 0) goto hard_fail; @@ -436,7 +464,7 @@ struct pci_dn * 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 = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA); + rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_DMA); if (rc < 0) goto hard_fail; @@ -454,7 +482,7 @@ struct pci_dn * 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_pdn, NULL); + rc = eeh_reset_device(frozen_edev, NULL); if (rc) { printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); goto hard_fail; @@ -473,7 +501,7 @@ struct pci_dn * 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_pdn; + return frozen_edev; excess_failures: /* @@ -486,7 +514,7 @@ excess_failures: "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_pdn->eeh_freeze_count); + location, drv_str, pci_str, frozen_edev->freeze_count); goto perm_error; hard_fail: @@ -497,7 +525,7 @@ hard_fail: location, drv_str, pci_str); perm_error: - eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE); + eeh_slot_error_detail(frozen_edev, EEH_LOG_PERM); /* Notify all devices that they're about to go down. */ pci_walk_bus(frozen_bus, eeh_report_failure, NULL); @@ -508,4 +536,3 @@ perm_error: return NULL; } -/* ---------- end of file ---------- */ diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index d2383cfb6dfd..4a4752565856 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c @@ -1,6 +1,4 @@ /* - * 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 @@ -46,7 +44,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, @@ -58,10 +56,10 @@ DEFINE_MUTEX(eeh_event_mutex); static int eeh_event_handler(void * dummy) { unsigned long flags; - struct eeh_event *event; - struct pci_dn *pdn; + struct eeh_event *event; + struct eeh_dev *edev; - daemonize ("eehd"); + daemonize("eehd"); set_current_state(TASK_INTERRUPTIBLE); spin_lock_irqsave(&eeh_eventlist_lock, flags); @@ -79,31 +77,37 @@ static int eeh_event_handler(void * dummy) /* Serialize processing of EEH events */ mutex_lock(&eeh_event_mutex); - eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); + edev = event->edev; + eeh_mark_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", - eeh_pci_name(event->dev)); + eeh_pci_name(edev->pdev)); + + edev = handle_eeh_events(event); - pdn = handle_eeh_events(event); + eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); + pci_dev_put(edev->pdev); - 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 (pdn && pdn->eeh_freeze_count>0) { - msleep_interruptible (3600*1000); - if (pdn->eeh_freeze_count>0) - pdn->eeh_freeze_count--; + if (edev && edev->freeze_count>0) { + msleep_interruptible(3600*1000); + if (edev->freeze_count>0) + edev->freeze_count--; + } return 0; } /** - * eeh_thread_launcher + * eeh_thread_launcher - Start kernel thread to handle EEH events * @dummy - unused + * + * This routine is called to start the kernel thread for processing + * EEH event. */ static void eeh_thread_launcher(struct work_struct *dummy) { @@ -112,18 +116,18 @@ static void eeh_thread_launcher(struct work_struct *dummy) } /** - * eeh_send_failure_event - generate a PCI error event - * @dev pci device + * eeh_send_failure_event - Generate a PCI error event + * @edev: EEH 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 device_node *dn, - struct pci_dev *dev) +int eeh_send_failure_event(struct eeh_dev *edev) { unsigned long flags; struct eeh_event *event; + struct device_node *dn = eeh_dev_to_of_node(edev); const char *location; if (!mem_init_done) { @@ -135,15 +139,14 @@ int eeh_send_failure_event (struct device_node *dn, } 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 (dev) - pci_dev_get(dev); + if (edev->pdev) + pci_dev_get(edev->pdev); - event->dn = dn; - event->dev = dev; + event->edev = edev; /* We may or may not be called in an interrupt context */ spin_lock_irqsave(&eeh_eventlist_lock, flags); @@ -154,5 +157,3 @@ int eeh_send_failure_event (struct device_node *dn, return 0; } - -/********************** END OF FILE ******************************/ diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c new file mode 100644 index 000000000000..8752f79a6af8 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c @@ -0,0 +1,565 @@ +/* + * 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 <linux/atomic.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/of.h> +#include <linux/pci.h> +#include <linux/proc_fs.h> +#include <linux/rbtree.h> +#include <linux/sched.h> +#include <linux/seq_file.h> +#include <linux/spinlock.h> + +#include <asm/eeh.h> +#include <asm/eeh_event.h> +#include <asm/io.h> +#include <asm/machdep.h> +#include <asm/ppc-pci.h> +#include <asm/rtas.h> + +/* 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 <ibm,set-eeh-option> invalid\n", + __func__); + return -EINVAL; + } else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: RTAS service <ibm, set-slot-reset> 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 <ibm,read-slot-reset-state2> and " + "<ibm,read-slot-reset-state> invalid\n", + __func__); + return -EINVAL; + } else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: RTAS service <ibm,slot-error-detail> 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 <ibm,get-config-addr-info2> and " + "<ibm,get-config-addr-info> invalid\n", + __func__); + return -EINVAL; + } else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE && + ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) { + pr_warning("%s: RTAS service <ibm,configure-pe> and " + "<ibm,configure-bridge> 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/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c index eb744ee234da..243b3510d70f 100644 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c @@ -28,7 +28,7 @@ #include <asm/pci-bridge.h> /** - * 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,24 +41,21 @@ static ssize_t eeh_show_##_name(struct device *dev, \ struct device_attribute *attr, char *buf) \ { \ struct pci_dev *pdev = to_pci_dev(dev); \ - struct device_node *dn = pci_device_to_OF_node(pdev); \ - struct pci_dn *pdn; \ + struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev); \ \ - if (!dn || PCI_DN(dn) == NULL) \ - return 0; \ + if (!edev) \ + return 0; \ \ - pdn = PCI_DN(dn); \ - return sprintf(buf, _format "\n", pdn->_memb); \ + return sprintf(buf, _format "\n", edev->_memb); \ } \ static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); - -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"); +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" ); void eeh_sysfs_add_device(struct pci_dev *pdev) { diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 7bc73af6c7b9..5f3ef876ded2 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -41,6 +41,7 @@ #include <asm/udbg.h> #include <asm/smp.h> #include <asm/trace.h> +#include <asm/firmware.h> #include "plpar_wrappers.h" #include "pseries.h" diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 38d24e7e7bb1..109fdb75578d 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/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 = find_device_pe(dn); + dn = eeh_find_device_pe(dn); if (!dn) return NULL; diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 55d4ec1bd1ac..fbb21fc3080b 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -147,6 +147,9 @@ 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/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c deleted file mode 100644 index 6e7742da0072..000000000000 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * 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 <linux/gfp.h> -#include <linux/init.h> -#include <linux/kobject.h> -#include <linux/mm.h> -#include <linux/of.h> -#include <linux/pfn.h> -#include <linux/swap.h> -#include <linux/sysfs.h> - -#include <asm/page.h> -#include <asm/phyp_dump.h> -#include <asm/machdep.h> -#include <asm/prom.h> -#include <asm/rtas.h> - -/* 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 <start addr> <length> > /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/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 085fd3f45ad2..a12e95af6933 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c @@ -96,6 +96,20 @@ out: 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) @@ -108,7 +122,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, ppc64_runlatch_off(); HMT_medium(); - cede_processor(); + check_and_cede_processor(); get_lppaca()->donate_dedicated_cpu = 0; dev->last_residency = @@ -132,7 +146,7 @@ static int shared_cede_loop(struct cpuidle_device *dev, * processor. When returning here, external interrupts * are enabled. */ - cede_processor(); + check_and_cede_processor(); dev->last_residency = (int)idle_loop_epilog(in_purr, kt_before); diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index f79f1278dfca..8f137af616af 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -190,9 +190,8 @@ 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, 0, - 16, 250, /* isu size, irq count */ - " MPIC "); + mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, + MPIC_NO_RESET, 16, 0, " MPIC "); BUG_ON(mpic == NULL); /* Add ISUs */ @@ -261,8 +260,12 @@ 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; @@ -382,6 +385,7 @@ 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/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 7b4df37ac381..a84fecf63c4d 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig @@ -29,3 +29,7 @@ config SCOM_DEBUGFS bool "Expose SCOM controllers via debugfs" depends on PPC_SCOM default n + +config GE_FPGA + bool + default n diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 5e37b4717864..1bd7ecb24620 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile @@ -4,6 +4,8 @@ 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 @@ -65,3 +67,5 @@ 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/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c index 116415899176..37a69097e022 100644 --- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c +++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c @@ -24,6 +24,7 @@ */ #include <linux/kernel.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/err.h> #include <linux/of_platform.h> diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c index 5f88797dce73..cedabd0f4bfe 100644 --- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c +++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c @@ -21,6 +21,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/of_platform.h> #include <asm/io.h> @@ -200,6 +201,9 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = { { .compatible = "fsl,p1022-l2-cache-controller", }, + { + .compatible = "fsl,mpc8548-l2-cache-controller", + }, {}, }; diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 0c01debe963b..6e097de00e09 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c @@ -410,6 +410,7 @@ 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/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index a4c4f4a932d8..5b6f556094dd 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c @@ -66,8 +66,8 @@ " li %0,%3\n" \ " b 2b\n" \ ".section __ex_table,\"a\"\n" \ - " .align 2\n" \ - " .long 1b,3b\n" \ + PPC_LONG_ALIGN "\n" \ + PPC_LONG "1b,3b\n" \ ".text" \ : "=r" (err), "=r" (x) \ : "b" (addr), "i" (-EFAULT), "0" (err)) diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c index 15485789e9db..14bd5221f28a 100644 --- a/arch/powerpc/sysdev/fsl_rmu.c +++ b/arch/powerpc/sysdev/fsl_rmu.c @@ -100,14 +100,8 @@ #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; @@ -193,6 +187,13 @@ 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 @@ -311,8 +312,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) /* XXX Need to check/dispatch until queue empty */ if (dsr & DOORBELL_DSR_DIQI) { - u32 dmsg = - (u32) fsl_dbell->dbell_ring.virt + + struct rio_dbell_msg *dmsg = + fsl_dbell->dbell_ring.virt + (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff); struct rio_dbell *dbell; int found = 0; @@ -320,25 +321,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", - DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); + dmsg->sid, dmsg->tid, dmsg->info); 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 - <= DBELL_INF(dmsg)) + <= dmsg->info) && (dbell->res->end - >= DBELL_INF(dmsg))) { + >= dmsg->info)) { found = 1; break; } } if (found && dbell->dinb) { dbell->dinb(fsl_dbell->mport[i], - dbell->dev_id, DBELL_SID(dmsg), - DBELL_TID(dmsg), - DBELL_INF(dmsg)); + dbell->dev_id, dmsg->sid, + dmsg->tid, + dmsg->info); break; } } @@ -348,8 +349,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", - DBELL_SID(dmsg), DBELL_TID(dmsg), - DBELL_INF(dmsg)); + dmsg->sid, dmsg->tid, + dmsg->info); } setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI); out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI); @@ -657,7 +658,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 " \ - "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len); + "%p len %8.8zx\n", rdev->destid, mbox, buffer, len); if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { ret = -EINVAL; goto out; @@ -972,7 +973,8 @@ out: void *fsl_get_inb_message(struct rio_mport *mport, int mbox) { struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); - u32 phys_buf, virt_buf; + u32 phys_buf; + void *virt_buf; void *buf = NULL; int buf_idx; @@ -982,7 +984,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 = (u32) rmu->msg_rx_ring.virt + (phys_buf + virt_buf = 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]; @@ -994,7 +996,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, (void *)virt_buf, RIO_MAX_MSG_SIZE); + memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE); /* Clear the available buffer */ rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL; diff --git a/arch/powerpc/sysdev/ge/Makefile b/arch/powerpc/sysdev/ge/Makefile new file mode 100644 index 000000000000..8731ffcb79b9 --- /dev/null +++ b/arch/powerpc/sysdev/ge/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_GE_FPGA) += ge_pic.o diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c index af3fd697de82..2bcb78bb3a15 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/sysdev/ge/ge_pic.c @@ -22,7 +22,7 @@ #include <asm/prom.h> #include <asm/irq.h> -#include "gef_pic.h" +#include "ge_pic.h" #define DEBUG #undef DEBUG diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h index 6149916da3f4..6149916da3f4 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.h +++ b/arch/powerpc/sysdev/ge/ge_pic.h diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index c83a512fa175..9ac71ebd2c40 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/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->irq_count) + if (src >= mpic->num_sources) 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->irq_count) + if (src >= mpic->num_sources) 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->irq_count) + if (src >= mpic->num_sources) 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->irq_count) + if (hw >= mpic->num_sources) return -EINVAL; mpic_msi_reserve_hwirq(mpic, hw); @@ -1149,6 +1149,7 @@ 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[] = { @@ -1182,6 +1183,16 @@ 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; @@ -1189,15 +1200,16 @@ 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 (!(flags & MPIC_SECONDARY)) + if (!(mpic->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 (!(flags & MPIC_SECONDARY)) + if (!(mpic->flags & MPIC_SECONDARY)) mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; #endif /* CONFIG_MPIC_U3_HT_IRQS */ @@ -1209,12 +1221,9 @@ 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 (flags & MPIC_LARGE_VECTORS) + if (mpic->flags & MPIC_LARGE_VECTORS) intvec_top = 2047; else intvec_top = 255; @@ -1233,12 +1242,6 @@ 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) { @@ -1254,11 +1257,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, } #ifdef CONFIG_MPIC_WEIRD - mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; + mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)]; #endif /* default register type */ - if (flags & MPIC_BIG_ENDIAN) + if (mpic->flags & MPIC_BIG_ENDIAN) mpic->reg_type = mpic_access_mmio_be; else mpic->reg_type = mpic_access_mmio_le; @@ -1268,10 +1271,10 @@ struct mpic * __init mpic_alloc(struct device_node *node, * only if the kernel includes DCR support. */ #ifdef CONFIG_PPC_DCR - if (flags & MPIC_USES_DCR) + if (mpic->flags & MPIC_USES_DCR) mpic->reg_type = mpic_access_dcr; #else - BUG_ON(flags & MPIC_USES_DCR); + BUG_ON(mpic->flags & MPIC_USES_DCR); #endif /* Map the global registers */ @@ -1283,10 +1286,7 @@ 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 (of_get_property(mpic->node, "pic-no-reset", NULL)) - mpic->flags |= MPIC_NO_RESET; - - if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { + if (!(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,31 +1297,17 @@ struct mpic * __init mpic_alloc(struct device_node *node, } /* CoreInt */ - if (flags & MPIC_ENABLE_COREINT) + if (mpic->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 (flags & MPIC_ENABLE_MCK) + if (mpic->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. */ @@ -1336,17 +1322,41 @@ 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 (mpic->isu_size == 0) { - mpic->isu_size = mpic->num_sources; + if (!isu_size) { + isu_size = last_irq + 1; + mpic->num_sources = isu_size; mpic_map(mpic, mpic->paddr, &mpic->isus[0], - MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); + MPIC_INFO(IRQ_BASE), + MPIC_INFO(IRQ_STRIDE) * 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, - isu_size ? isu_size : mpic->num_sources, + last_irq + 1, &mpic_host_ops, mpic); /* @@ -1380,7 +1390,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, mpic->next = mpics; mpics = mpic; - if (!(flags & MPIC_SECONDARY)) { + if (!(mpic->flags & MPIC_SECONDARY)) { mpic_primary = mpic; irq_set_default_host(mpic->irqhost); } @@ -1447,10 +1457,6 @@ 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/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c new file mode 100644 index 000000000000..6e7fa386e76a --- /dev/null +++ b/arch/powerpc/sysdev/mpic_msgr.c @@ -0,0 +1,282 @@ +/* + * 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 <linux/list.h> +#include <linux/of_platform.h> +#include <linux/errno.h> +#include <asm/prom.h> +#include <asm/hw_irq.h> +#include <asm/ppc-pci.h> +#include <asm/mpic_msgr.h> + +#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/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index 0622aa91b18a..bbf342c88314 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/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->irq_count; i++) + for (i = 124; i < mpic->num_sources; 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->irq_count, + rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->num_sources, mpic->irqhost->of_node); if (rc) return rc; diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 4f05f7542346..56e8b3c3c890 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c @@ -1050,6 +1050,74 @@ 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 */ @@ -1362,6 +1430,8 @@ 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/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index cb95eea74d3d..68a9cbbab450 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c @@ -39,7 +39,6 @@ #include <asm/irq_regs.h> #include <asm/spu.h> #include <asm/spu_priv1.h> -#include <asm/firmware.h> #include <asm/setjmp.h> #include <asm/reg.h> @@ -1437,7 +1436,8 @@ static void excprint(struct pt_regs *fp) printf(" current = 0x%lx\n", current); #ifdef CONFIG_PPC64 - printf(" paca = 0x%lx\n", get_paca()); + printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n", + local_paca, local_paca->soft_enabled, local_paca->irq_happened); #endif if (current) { printf(" pid = %ld, comm = %s\n", @@ -1634,25 +1634,6 @@ 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; } @@ -2644,7 +2625,7 @@ static void dump_slb(void) static void dump_stab(void) { int i; - unsigned long *tmp = (unsigned long *)get_paca()->stab_addr; + unsigned long *tmp = (unsigned long *)local_paca->stab_addr; printf("Segment table contents of cpu %x\n", smp_processor_id()); @@ -2855,10 +2836,6 @@ 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; @@ -2895,10 +2872,6 @@ 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/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c index 8a2a887478cc..6a2cb560e968 100644 --- a/arch/s390/hypfs/inode.c +++ b/arch/s390/hypfs/inode.c @@ -293,11 +293,9 @@ 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_alloc_root(root_inode); - if (!root_dentry) { - iput(root_inode); + sb->s_root = root_dentry = d_make_root(root_inode); + if (!root_dentry) return -ENOMEM; - } if (MACHINE_IS_VM) rc = hypfs_vm_create_files(sb, root_dentry); else diff --git a/arch/um/include/asm/mmu.h b/arch/um/include/asm/mmu.h index 30509b9f37fd..53e8b498ebba 100644 --- a/arch/um/include/asm/mmu.h +++ b/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; + struct page *stub_pages[2]; } mm_context_t; extern void __switch_mm(struct mm_id * mm_idp); diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h index 591b3d8d7614..aa4a743dc4ab 100644 --- a/arch/um/include/asm/mmu_context.h +++ b/arch/um/include/asm/mmu_context.h @@ -9,7 +9,7 @@ #include <linux/sched.h> #include <asm/mmu.h> -extern void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm); +extern void uml_setup_stubs(struct mm_struct *mm); extern void arch_exit_mmap(struct mm_struct *mm); #define deactivate_mm(tsk,mm) do { } while (0) @@ -23,7 +23,9 @@ 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); - arch_dup_mmap(old, new); + down_write(&new->mmap_sem); + uml_setup_stubs(new); + up_write(&new->mmap_sem); } static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, @@ -39,6 +41,11 @@ 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/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c index 1aee587e9c5d..4947b319f53a 100644 --- a/arch/um/kernel/skas/mmu.c +++ b/arch/um/kernel/skas/mmu.c @@ -92,8 +92,6 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) goto out_free; } - to_mm->stub_pages = NULL; - return 0; out_free: @@ -103,7 +101,7 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm) return ret; } -void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) +void uml_setup_stubs(struct mm_struct *mm) { struct page **pages; int err, ret; @@ -120,29 +118,20 @@ void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm) if (ret) goto out; - 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; + mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start); + mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack); /* 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, pages); + VM_MAYEXEC | VM_DONTCOPY, + mm->context.stub_pages); if (err) { printk(KERN_ERR "install_special_mapping returned %d\n", err); - goto out_free; + goto out; } return; -out_free: - kfree(pages); out: force_sigsegv(SIGSEGV, current); } @@ -151,8 +140,6 @@ 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/arch/x86/crypto/Makefile b/arch/x86/crypto/Makefile index 2b0b9631474b..e191ac048b59 100644 --- a/arch/x86/crypto/Makefile +++ b/arch/x86/crypto/Makefile @@ -8,6 +8,7 @@ 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 @@ -25,6 +26,7 @@ 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/arch/x86/crypto/blowfish_glue.c b/arch/x86/crypto/blowfish_glue.c index b05aa163d55a..7967474de8f7 100644 --- a/arch/x86/crypto/blowfish_glue.c +++ b/arch/x86/crypto/blowfish_glue.c @@ -25,6 +25,7 @@ * */ +#include <asm/processor.h> #include <crypto/blowfish.h> #include <linux/crypto.h> #include <linux/init.h> @@ -76,27 +77,6 @@ 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 *)) @@ -160,28 +140,6 @@ 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) { @@ -307,29 +265,6 @@ 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; @@ -423,7 +358,67 @@ static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, return err; } -static struct crypto_alg blk_ctr_alg = { +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, + }, + }, +}, { .cra_name = "ctr(blowfish)", .cra_driver_name = "ctr-blowfish-asm", .cra_priority = 300, @@ -433,7 +428,7 @@ static struct crypto_alg blk_ctr_alg = { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), + .cra_list = LIST_HEAD_INIT(bf_algs[3].cra_list), .cra_u = { .blkcipher = { .min_keysize = BF_MIN_KEY_SIZE, @@ -444,43 +439,45 @@ static struct crypto_alg blk_ctr_alg = { .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) { - int err; + 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; + } - 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; + return crypto_register_algs(bf_algs, ARRAY_SIZE(bf_algs)); } static void __exit fini(void) { - crypto_unregister_alg(&blk_ctr_alg); - crypto_unregister_alg(&blk_cbc_alg); - crypto_unregister_alg(&blk_ecb_alg); - crypto_unregister_alg(&bf_alg); + crypto_unregister_algs(bf_algs, ARRAY_SIZE(bf_algs)); } module_init(init); diff --git a/arch/x86/crypto/camellia-x86_64-asm_64.S b/arch/x86/crypto/camellia-x86_64-asm_64.S new file mode 100644 index 000000000000..0b3374335fdc --- /dev/null +++ b/arch/x86/crypto/camellia-x86_64-asm_64.S @@ -0,0 +1,520 @@ +/* + * Camellia Cipher Algorithm (x86_64) + * + * Copyright (C) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> + * + * 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/arch/x86/crypto/camellia_glue.c b/arch/x86/crypto/camellia_glue.c new file mode 100644 index 000000000000..1ca36a93fd2f --- /dev/null +++ b/arch/x86/crypto/camellia_glue.c @@ -0,0 +1,1952 @@ +/* + * Glue Code for assembler optimized version of Camellia + * + * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> + * + * 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 <herbert@gondor.apana.org.au> + * CTR part based on code (crypto/ctr.c) by: + * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@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 + * + */ + +#include <asm/processor.h> +#include <asm/unaligned.h> +#include <linux/crypto.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/types.h> +#include <crypto/algapi.h> +#include <crypto/b128ops.h> +#include <crypto/lrw.h> +#include <crypto/xts.h> + +#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/arch/x86/crypto/serpent-sse2-i586-asm_32.S b/arch/x86/crypto/serpent-sse2-i586-asm_32.S index 4e37677ca851..c00053d42f99 100644 --- a/arch/x86/crypto/serpent-sse2-i586-asm_32.S +++ b/arch/x86/crypto/serpent-sse2-i586-asm_32.S @@ -463,23 +463,20 @@ pand x0, x4; \ pxor x2, x4; -#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ - movdqa x2, t3; \ - movdqa x0, t1; \ - unpcklps x3, t3; \ +#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ movdqa x0, t2; \ - 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; + 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; #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \ movdqu (0*4*4)(in), x0; \ diff --git a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S index 7f24a1540821..3ee1ff04d3e9 100644 --- a/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S +++ b/arch/x86/crypto/serpent-sse2-x86_64-asm_64.S @@ -585,23 +585,20 @@ get_key(i, 1, RK1); \ SBOX ## _2(x0 ## 2, x1 ## 2, x2 ## 2, x3 ## 2, x4 ## 2); \ -#define transpose_4x4(x0, x1, x2, x3, t1, t2, t3) \ - movdqa x2, t3; \ - movdqa x0, t1; \ - unpcklps x3, t3; \ +#define transpose_4x4(x0, x1, x2, x3, t0, t1, t2) \ movdqa x0, t2; \ - 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; + 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; #define read_blocks(in, x0, x1, x2, x3, t0, t1, t2) \ movdqu (0*4*4)(in), x0; \ diff --git a/arch/x86/crypto/serpent_sse2_glue.c b/arch/x86/crypto/serpent_sse2_glue.c index 7955a9b76b91..4b21be85e0a1 100644 --- a/arch/x86/crypto/serpent_sse2_glue.c +++ b/arch/x86/crypto/serpent_sse2_glue.c @@ -145,28 +145,6 @@ 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) { @@ -295,28 +273,6 @@ 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); @@ -439,29 +395,6 @@ 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; @@ -580,32 +513,6 @@ 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; @@ -689,29 +596,6 @@ 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) { @@ -792,28 +676,133 @@ static void ablk_exit(struct crypto_tfm *tfm) cryptd_free_ablkcipher(ctx->cryptd_tfm); } -static void ablk_init_common(struct crypto_tfm *tfm, - struct cryptd_ablkcipher *cryptd_tfm) +static int ablk_init(struct crypto_tfm *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 ablk_ecb_alg = { +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, + }, + }, +}, { .cra_name = "ecb(serpent)", .cra_driver_name = "ecb-serpent-sse2", .cra_priority = 400, @@ -823,8 +812,8 @@ static struct crypto_alg ablk_ecb_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list), - .cra_init = ablk_ecb_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -835,20 +824,7 @@ static struct crypto_alg ablk_ecb_alg = { .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, @@ -858,8 +834,8 @@ static struct crypto_alg ablk_cbc_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list), - .cra_init = ablk_cbc_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -871,20 +847,7 @@ static struct crypto_alg ablk_cbc_alg = { .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, @@ -894,8 +857,8 @@ static struct crypto_alg ablk_ctr_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list), - .cra_init = ablk_ctr_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -908,20 +871,7 @@ static struct crypto_alg ablk_ctr_alg = { .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, @@ -931,8 +881,8 @@ static struct crypto_alg ablk_lrw_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list), - .cra_init = ablk_lrw_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -946,20 +896,7 @@ static struct crypto_alg ablk_lrw_alg = { .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, @@ -969,8 +906,8 @@ static struct crypto_alg ablk_xts_alg = { .cra_alignmask = 0, .cra_type = &crypto_ablkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list), - .cra_init = ablk_xts_init, + .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), + .cra_init = ablk_init, .cra_exit = ablk_exit, .cra_u = { .ablkcipher = { @@ -982,84 +919,21 @@ static struct crypto_alg ablk_xts_alg = { .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; } - 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; + return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); } static void __exit serpent_sse2_exit(void) { - 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); + crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); } module_init(serpent_sse2_init); diff --git a/arch/x86/crypto/twofish_glue.c b/arch/x86/crypto/twofish_glue.c index dc6b3fb817fc..359ae084275c 100644 --- a/arch/x86/crypto/twofish_glue.c +++ b/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 = 3, + .cra_alignmask = 0, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(alg.cra_list), .cra_u = { diff --git a/arch/x86/crypto/twofish_glue_3way.c b/arch/x86/crypto/twofish_glue_3way.c index 7fee8c152f93..408fc0c5814e 100644 --- a/arch/x86/crypto/twofish_glue_3way.c +++ b/arch/x86/crypto/twofish_glue_3way.c @@ -25,6 +25,7 @@ * */ +#include <asm/processor.h> #include <linux/crypto.h> #include <linux/init.h> #include <linux/module.h> @@ -122,28 +123,6 @@ 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) { @@ -267,29 +246,6 @@ 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); @@ -411,29 +367,6 @@ 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; @@ -524,30 +457,6 @@ 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; @@ -614,7 +523,91 @@ static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, return xts_crypt(desc, dst, src, nbytes, &req); } -static struct crypto_alg blk_xts_alg = { +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, + }, + }, +}, { .cra_name = "xts(twofish)", .cra_driver_name = "xts-twofish-3way", .cra_priority = 300, @@ -624,7 +617,7 @@ static struct crypto_alg blk_xts_alg = { .cra_alignmask = 0, .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, - .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), + .cra_list = LIST_HEAD_INIT(tf_algs[4].cra_list), .cra_u = { .blkcipher = { .min_keysize = TF_MIN_KEY_SIZE * 2, @@ -635,50 +628,62 @@ static struct crypto_alg blk_xts_alg = { .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) { - int err; + 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; + } - 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; + return crypto_register_algs(tf_algs, ARRAY_SIZE(tf_algs)); } void __exit fini(void) { - 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); + crypto_unregister_algs(tf_algs, ARRAY_SIZE(tf_algs)); } module_init(init); diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index 39e49091f648..4c2e59a420b9 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c @@ -323,7 +323,6 @@ 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; @@ -519,7 +518,8 @@ out: static int __init init_aout_binfmt(void) { - return register_binfmt(&aout_format); + register_binfmt(&aout_format); + return 0; } static void __exit exit_aout_binfmt(void) diff --git a/crypto/Kconfig b/crypto/Kconfig index e6cfe1a25137..6318edd6a457 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -654,6 +654,24 @@ config CRYPTO_CAMELLIA See also: <https://info.isl.ntt.co.jp/crypt/eng/camellia/index_s.html> +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: + <https://info.isl.ntt.co.jp/crypt/eng/camellia/index_s.html> + config CRYPTO_CAST5 tristate "CAST5 (CAST-128) cipher algorithm" select CRYPTO_ALGAPI diff --git a/crypto/Makefile b/crypto/Makefile index f638063f4ea9..30f33d675330 100644 --- a/crypto/Makefile +++ b/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.o +obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o obj-$(CONFIG_CRYPTO_CAST5) += cast5.o obj-$(CONFIG_CRYPTO_CAST6) += cast6.o obj-$(CONFIG_CRYPTO_ARC4) += arc4.o diff --git a/crypto/algapi.c b/crypto/algapi.c index 9d4a9fe913f8..056571b85445 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -405,6 +405,41 @@ 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/crypto/camellia.c b/crypto/camellia_generic.c index 64cff46ea5e4..f7aaaaf86982 100644 --- a/crypto/camellia.c +++ b/crypto/camellia_generic.c @@ -337,43 +337,40 @@ static const u32 camellia_sp4404[256] = { /* * macros */ -#define ROLDQ(ll, lr, rl, rr, w0, w1, bits) \ - do { \ +#define ROLDQ(ll, lr, rl, rr, w0, w1, bits) ({ \ 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) \ - do { \ +#define ROLDQo32(ll, lr, rl, rr, w0, w1, bits) ({ \ 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) \ - do { \ +#define CAMELLIA_F(xl, xr, kl, kr, yl, yr, il, ir, t0, t1) ({ \ il = xl ^ kl; \ ir = xr ^ kr; \ t0 = il >> 16; \ t1 = ir >> 16; \ - yl = camellia_sp1110[(u8)(ir )] \ - ^ camellia_sp0222[ (t1 >> 8)] \ - ^ camellia_sp3033[(u8)(t1 )] \ + yl = camellia_sp1110[(u8)(ir)] \ + ^ camellia_sp0222[(u8)(t1 >> 8)] \ + ^ camellia_sp3033[(u8)(t1)] \ ^ camellia_sp4404[(u8)(ir >> 8)]; \ - yr = camellia_sp1110[ (t0 >> 8)] \ - ^ camellia_sp0222[(u8)(t0 )] \ + yr = camellia_sp1110[(u8)(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]) @@ -382,7 +379,6 @@ 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 */ @@ -557,24 +553,6 @@ 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) @@ -851,8 +829,7 @@ 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) \ - do { \ +#define CAMELLIA_FLS(ll, lr, rl, rr, kll, klr, krl, krr, t0, t1, t2, t3) ({ \ t0 = kll; \ t2 = krr; \ t0 &= ll; \ @@ -865,23 +842,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) \ - do { \ +#define CAMELLIA_ROUNDSM(xl, xr, kl, kr, yl, yr, il, ir) ({ \ + yl ^= kl; \ + yr ^= kr; \ ir = camellia_sp1110[(u8)xr]; \ - il = camellia_sp1110[ (xl >> 24)]; \ - ir ^= camellia_sp0222[ (xr >> 24)]; \ + il = camellia_sp1110[(u8)(xl >> 24)]; \ + ir ^= camellia_sp0222[(u8)(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]; \ - il ^= kl; \ - ir ^= il ^ kr; \ + ir ^= il; \ yl ^= ir; \ - yr ^= ror32(il, 8) ^ ir; \ - } while (0) + yr ^= ror32(il, 8) ^ ir; \ +}) /* max = 24: 128bit encrypt, max = 32: 256bit encrypt */ static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max) @@ -893,7 +870,7 @@ static void camellia_do_encrypt(const u32 *subkey, u32 *io, unsigned max) io[1] ^= SUBKEY_R(0); /* main iteration */ -#define ROUNDS(i) do { \ +#define ROUNDS(i) ({ \ CAMELLIA_ROUNDSM(io[0], io[1], \ SUBKEY_L(i + 2), SUBKEY_R(i + 2), \ io[2], io[3], il, ir); \ @@ -912,13 +889,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); \ -} while (0) -#define FLS(i) do { \ +}) +#define FLS(i) ({ \ 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); @@ -948,7 +925,7 @@ static void camellia_do_decrypt(const u32 *subkey, u32 *io, unsigned i) io[1] ^= SUBKEY_R(i); /* main iteration */ -#define ROUNDS(i) do { \ +#define ROUNDS(i) ({ \ CAMELLIA_ROUNDSM(io[0], io[1], \ SUBKEY_L(i + 7), SUBKEY_R(i + 7), \ io[2], io[3], il, ir); \ @@ -967,13 +944,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); \ -} while (0) -#define FLS(i) do { \ +}) +#define FLS(i) ({ \ 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); @@ -1035,6 +1012,7 @@ 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]; @@ -1043,9 +1021,12 @@ 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]); - camellia_do_encrypt(cctx->key_table, tmp, - cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */ - ); + 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); /* do_encrypt returns 0,1 swapped with 2,3 */ dst[0] = cpu_to_be32(tmp[2]); @@ -1059,6 +1040,7 @@ 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]; @@ -1067,9 +1049,12 @@ 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]); - camellia_do_decrypt(cctx->key_table, tmp, - cctx->key_length == 16 ? 24 : 32 /* for key lengths of 24 and 32 */ - ); + 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); /* do_decrypt returns 0,1 swapped with 2,3 */ dst[0] = cpu_to_be32(tmp[2]); @@ -1114,3 +1099,4 @@ module_exit(camellia_fini); MODULE_DESCRIPTION("Camellia Cipher Algorithm"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("camellia"); diff --git a/crypto/crypto_user.c b/crypto/crypto_user.c index b6ac1387770c..f76e42bcc6e7 100644 --- a/crypto/crypto_user.c +++ b/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; + int exact = 0; const char *name; struct crypto_alg *alg; struct crypto_user_alg *p = nlmsg_data(nlh); diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c index 7736a9f05aba..8f147bff0980 100644 --- a/crypto/tcrypt.c +++ b/crypto/tcrypt.c @@ -1297,6 +1297,18 @@ 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/crypto/testmgr.c b/crypto/testmgr.c index bb54b882d738..5674878ff6c1 100644 --- a/crypto/testmgr.c +++ b/crypto/testmgr.c @@ -1846,6 +1846,21 @@ 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, .suite = { @@ -2297,6 +2312,21 @@ 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, .suite = { @@ -2634,6 +2664,21 @@ 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, .suite = { diff --git a/crypto/testmgr.h b/crypto/testmgr.h index 43e84d32b341..36e5a8ee0e1e 100644 --- a/crypto/testmgr.h +++ b/crypto/testmgr.h @@ -11332,10 +11332,16 @@ static struct cipher_testvec fcrypt_pcbc_dec_tv_template[] = { /* * CAMELLIA test vectors. */ -#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 +#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 static struct cipher_testvec camellia_enc_tv_template[] = { { @@ -11372,6 +11378,27 @@ 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[] = { @@ -11409,6 +11436,27 @@ 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[] = { @@ -11440,6 +11488,29 @@ 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[] = { @@ -11471,6 +11542,1310 @@ 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/drivers/base/driver.c b/drivers/base/driver.c index 60e4f77ca662..3ec3896c83a6 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -123,36 +123,6 @@ 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/drivers/block/viodasd.c b/drivers/block/viodasd.c deleted file mode 100644 index 9a5b2a2d616d..000000000000 --- a/drivers/block/viodasd.c +++ /dev/null @@ -1,809 +0,0 @@ -/* -*- linux-c -*- - * viodasd.c - * Authors: Dave Boutcher <boutcher@us.ibm.com> - * Ryan Arnold <ryanarn@us.ibm.com> - * Colin Devilbiss <devilbis@us.ibm.com> - * 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 <linux/major.h> -#include <linux/fs.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/blkdev.h> -#include <linux/genhd.h> -#include <linux/hdreg.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/mutex.h> -#include <linux/dma-mapping.h> -#include <linux/completion.h> -#include <linux/device.h> -#include <linux/scatterlist.h> - -#include <asm/uaccess.h> -#include <asm/vio.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/vio.h> -#include <asm/firmware.h> - -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/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c deleted file mode 100644 index 7878da89d29e..000000000000 --- a/drivers/cdrom/viocd.c +++ /dev/null @@ -1,739 +0,0 @@ -/* -*- linux-c -*- - * drivers/cdrom/viocd.c - * - * iSeries Virtual CD Rom - * - * Authors: Dave Boutcher <boutcher@us.ibm.com> - * Ryan Arnold <ryanarn@us.ibm.com> - * Colin Devilbiss <devilbis@us.ibm.com> - * 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 <linux/major.h> -#include <linux/blkdev.h> -#include <linux/cdrom.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/dma-mapping.h> -#include <linux/module.h> -#include <linux/completion.h> -#include <linux/proc_fs.h> -#include <linux/mutex.h> -#include <linux/seq_file.h> -#include <linux/scatterlist.h> - -#include <asm/vio.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/vio.h> -#include <asm/firmware.h> - -#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/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c index 0bc0cb70210b..de473ef3882b 100644 --- a/drivers/char/hw_random/tx4939-rng.c +++ b/drivers/char/hw_random/tx4939-rng.c @@ -115,10 +115,7 @@ static int __init tx4939_rng_probe(struct platform_device *dev) rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL); if (!rngdev) return -ENOMEM; - 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)); + rngdev->base = devm_request_and_ioremap(&dev->dev, r); if (!rngdev->base) return -EBUSY; diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 7fc75e47e6d0..a048199ce866 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -5,7 +5,6 @@ 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/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 32362cf35b8d..ad7c7320dd1b 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1221,12 +1221,13 @@ 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, ret_size); + memset(chip->data_buffer, 0, orig_ret_size); if (rc) ret_size = -EFAULT; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 010547138281..b1c5280ac159 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -99,6 +99,8 @@ 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/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 70fac9abb0e2..d2a70cae76df 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -367,7 +367,12 @@ static int probe_itpm(struct tpm_chip *chip) 0x00, 0x00, 0x00, 0xf1 }; size_t len = sizeof(cmd_getticks); - int rem_itpm = itpm; + bool rem_itpm = itpm; + u16 vendor = ioread16(chip->vendor.iobase + TPM_DID_VID(0)); + + /* probe only iTPMS */ + if (vendor != TPM_VID_INTEL) + return 0; itpm = 0; @@ -390,9 +395,6 @@ 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; @@ -508,7 +510,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; + int rc, i, irq_s, irq_e, probe; struct tpm_chip *chip; if (!(chip = tpm_register_hardware(dev, &tpm_tis))) @@ -538,11 +540,12 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0))); if (!itpm) { - itpm = probe_itpm(chip); - if (itpm < 0) { + probe = probe_itpm(chip); + if (probe < 0) { rc = -ENODEV; goto out_err; } + itpm = (probe == 0) ? 0 : 1; } if (itpm) diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c deleted file mode 100644 index 8b34c65511eb..000000000000 --- a/drivers/char/viotape.c +++ /dev/null @@ -1,1041 +0,0 @@ -/* -*- linux-c -*- - * drivers/char/viotape.c - * - * iSeries Virtual Tape - * - * Authors: Dave Boutcher <boutcher@us.ibm.com> - * Ryan Arnold <ryanarn@us.ibm.com> - * Colin Devilbiss <devilbis@us.ibm.com> - * 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 <linux/module.h> -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/wait.h> -#include <linux/spinlock.h> -#include <linux/mtio.h> -#include <linux/device.h> -#include <linux/dma-mapping.h> -#include <linux/fs.h> -#include <linux/cdev.h> -#include <linux/major.h> -#include <linux/completion.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/mutex.h> -#include <linux/slab.h> - -#include <asm/uaccess.h> -#include <asm/ioctls.h> -#include <asm/firmware.h> -#include <asm/vio.h> -#include <asm/iseries/vio.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_call_event.h> -#include <asm/iseries/hv_lp_config.h> - -#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/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 6d16b4b0d7a0..e707979767fb 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -293,4 +293,15 @@ 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/drivers/crypto/Makefile b/drivers/crypto/Makefile index 53ea50155319..f3e64eadd7af 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -13,3 +13,4 @@ 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/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index e73cf2e8110a..534a36469d57 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1844,6 +1844,25 @@ static struct caam_alg_template driver_algs[] = { .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 = "<built-in>", + .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", .blocksize = AES_BLOCK_SIZE, @@ -1864,6 +1883,26 @@ static struct caam_alg_template driver_algs[] = { .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 = "<built-in>", + .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", .blocksize = AES_BLOCK_SIZE, @@ -1922,6 +1961,25 @@ static struct caam_alg_template driver_algs[] = { .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 = "<built-in>", + .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", .blocksize = DES3_EDE_BLOCK_SIZE, @@ -1942,6 +2000,25 @@ static struct caam_alg_template driver_algs[] = { .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 = "<built-in>", + .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", .blocksize = DES3_EDE_BLOCK_SIZE, @@ -2000,6 +2077,25 @@ static struct caam_alg_template driver_algs[] = { .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 = "<built-in>", + .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", .blocksize = DES_BLOCK_SIZE, @@ -2020,6 +2116,25 @@ static struct caam_alg_template driver_algs[] = { .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 = "<built-in>", + .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", .blocksize = DES_BLOCK_SIZE, @@ -2205,7 +2320,8 @@ 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 | template->type; + alg->cra_flags = CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | + template->type; switch (template->type) { case CRYPTO_ALG_TYPE_ABLKCIPHER: alg->cra_type = &crypto_ablkcipher_type; @@ -2285,12 +2401,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/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 8ae3ba2a160d..c5f61c55d923 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/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 d, ring, rspec; + int ring, rspec; struct device *dev; struct device_node *nprop, *np; struct caam_ctrl __iomem *ctrl; diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 219d09cbb0d1..f3e36c86b6c3 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c @@ -393,7 +393,8 @@ static struct crypto_alg geode_cbc_alg = { .cra_driver_name = "cbc-aes-geode", .cra_priority = 400, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | - CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_NEED_FALLBACK, .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, @@ -479,7 +480,8 @@ static struct crypto_alg geode_ecb_alg = { .cra_driver_name = "ecb-aes-geode", .cra_priority = 400, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | - CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_NEED_FALLBACK, .cra_init = fallback_init_blk, .cra_exit = fallback_exit_blk, .cra_blocksize = AES_MIN_BLOCK_SIZE, diff --git a/drivers/crypto/hifn_795x.c b/drivers/crypto/hifn_795x.c index 76368f984023..c9c4befb5a8d 100644 --- a/drivers/crypto/hifn_795x.c +++ b/drivers/crypto/hifn_795x.c @@ -2494,7 +2494,8 @@ 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_ASYNC; + alg->alg.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | 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/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 4c20c5bf6058..0053d7ebb5ca 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/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_KERNEL); + &crypt_phys, GFP_ATOMIC); if (!crypt_virt) return -ENOMEM; memset(crypt_virt, 0, NPE_QLEN * sizeof(struct crypt_ctl)); @@ -1449,6 +1449,7 @@ 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; @@ -1461,6 +1462,7 @@ 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/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 0d40cf66b3cc..e6ecc5f23943 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -899,7 +899,8 @@ 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_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC, .cra_blocksize = 16, .cra_ctxsize = sizeof(struct mv_ctx), .cra_alignmask = 0, @@ -921,7 +922,8 @@ 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_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct mv_ctx), .cra_alignmask = 0, @@ -953,7 +955,8 @@ struct ahash_alg mv_sha1_alg = { .cra_driver_name = "mv-sha1", .cra_priority = 300, .cra_flags = - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct mv_tfm_hash_ctx), .cra_init = mv_cra_hash_sha1_init, @@ -977,7 +980,8 @@ struct ahash_alg mv_hmac_sha1_alg = { .cra_driver_name = "mv-hmac-sha1", .cra_priority = 300, .cra_flags = - CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK, + CRYPTO_ALG_ASYNC | CRYPTO_ALG_KERN_DRIVER_ONLY | + 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/drivers/crypto/n2_core.c b/drivers/crypto/n2_core.c index 8944dabc0e3c..67b97c5fd859 100644 --- a/drivers/crypto/n2_core.c +++ b/drivers/crypto/n2_core.c @@ -1402,7 +1402,8 @@ 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_ASYNC; + alg->cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | CRYPTO_ALG_ASYNC; alg->cra_blocksize = tmpl->block_size; p->enc_type = tmpl->enc_type; alg->cra_ctxsize = sizeof(struct n2_cipher_context); @@ -1493,7 +1494,9 @@ 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_NEED_FALLBACK; + base->cra_flags = CRYPTO_ALG_TYPE_AHASH | + CRYPTO_ALG_KERN_DRIVER_ONLY | + 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/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 5b970d9e9956..63e57b57a12c 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -756,7 +756,9 @@ 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_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), .cra_alignmask = 0, @@ -776,7 +778,9 @@ 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_ASYNC, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_KERN_DRIVER_ONLY | + CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct omap_aes_ctx), .cra_alignmask = 0, diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index 6399a8f1938a..a3fd6fc504b1 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -953,6 +953,7 @@ 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, @@ -975,6 +976,7 @@ 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, @@ -998,6 +1000,7 @@ 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, @@ -1022,6 +1025,7 @@ 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/drivers/crypto/picoxcell_crypto.c b/drivers/crypto/picoxcell_crypto.c index 58480d009324..410a03c01ca4 100644 --- a/drivers/crypto/picoxcell_crypto.c +++ b/drivers/crypto/picoxcell_crypto.c @@ -1322,6 +1322,7 @@ 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, @@ -1349,6 +1350,7 @@ 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), @@ -1373,7 +1375,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1398,7 +1402,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1422,7 +1428,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1447,7 +1455,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, @@ -1472,7 +1482,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1500,7 +1512,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1527,7 +1541,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1554,7 +1570,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1582,7 +1600,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1609,7 +1629,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = DES3_EDE_BLOCK_SIZE, .cra_ctxsize = sizeof(struct spacc_aead_ctx), .cra_type = &crypto_aead_type, @@ -1639,7 +1661,9 @@ 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, + .cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER | + CRYPTO_ALG_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = 8, .cra_ctxsize = sizeof(struct spacc_ablk_ctx), .cra_type = &crypto_ablkcipher_type, diff --git a/drivers/crypto/s5p-sss.c b/drivers/crypto/s5p-sss.c index 3376bca200fc..bc986f806086 100644 --- a/drivers/crypto/s5p-sss.c +++ b/drivers/crypto/s5p-sss.c @@ -518,7 +518,8 @@ 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_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s5p_aes_ctx), .cra_alignmask = 0x0f, @@ -538,7 +539,8 @@ 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_ASYNC | + CRYPTO_ALG_KERN_DRIVER_ONLY, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct s5p_aes_ctx), .cra_alignmask = 0x0f, diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 2d8c78901686..dc641c796526 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -2648,6 +2648,7 @@ 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/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c new file mode 100644 index 000000000000..422a9766c7c9 --- /dev/null +++ b/drivers/crypto/tegra-aes.c @@ -0,0 +1,1096 @@ +/* + * 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 <linux/module.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/scatterlist.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/mutex.h> +#include <linux/interrupt.h> +#include <linux/completion.h> +#include <linux/workqueue.h> + +#include <mach/clk.h> + +#include <crypto/scatterwalk.h> +#include <crypto/aes.h> +#include <crypto/internal/rng.h> + +#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/drivers/crypto/tegra-aes.h b/drivers/crypto/tegra-aes.h new file mode 100644 index 000000000000..6006333a8934 --- /dev/null +++ b/drivers/crypto/tegra-aes.h @@ -0,0 +1,103 @@ +/* + * 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/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d0c41188d4e5..0409cf35adda 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -190,6 +190,17 @@ 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/drivers/gpio/Makefile b/drivers/gpio/Makefile index fa10df604c01..9a8fb54ae462 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -16,6 +16,7 @@ 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/arch/powerpc/platforms/86xx/gef_gpio.c b/drivers/gpio/gpio-ge.c index 2a703365e664..7b95a4a8318c 100644 --- a/arch/powerpc/platforms/86xx/gef_gpio.c +++ b/drivers/gpio/gpio-ge.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 <linux/kernel.h> @@ -162,6 +162,34 @@ 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/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c index 366bc156e34d..8c279da07410 100644 --- a/drivers/misc/carma/carma-fpga.c +++ b/drivers/misc/carma/carma-fpga.c @@ -560,6 +560,9 @@ 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); @@ -591,8 +594,12 @@ static void data_dma_cb(void *data) list_move_tail(&priv->inflight->entry, &priv->used); priv->inflight = NULL; - /* clear the FPGA status and re-enable interrupts */ - data_enable_interrupts(priv); + /* + * If data dumping is still enabled, then clear the FPGA + * status registers and re-enable FPGA interrupts + */ + if (priv->enabled) + data_enable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -708,6 +715,15 @@ 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); @@ -762,11 +778,15 @@ out: */ static int data_device_enable(struct fpga_device *priv) { + bool enabled; u32 val; int ret; /* multiple enables are safe: they do nothing */ - if (priv->enabled) + spin_lock_irq(&priv->lock); + enabled = priv->enabled; + spin_unlock_irq(&priv->lock); + if (enabled) return 0; /* check that the FPGAs are programmed */ @@ -797,6 +817,9 @@ 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) { @@ -804,11 +827,13 @@ static int data_device_enable(struct fpga_device *priv) goto out_error; } - /* switch to the external FPGA IRQ line */ - data_enable_interrupts(priv); - - /* success, we're enabled */ + /* 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 */ + data_enable_interrupts(priv); return 0; out_error: @@ -834,41 +859,40 @@ out_error: */ static int data_device_disable(struct fpga_device *priv) { - int ret; + spin_lock_irq(&priv->lock); /* allow multiple disable */ - if (!priv->enabled) + if (!priv->enabled) { + spin_unlock_irq(&priv->lock); return 0; + } + + /* + * Mark the device disabled + * + * This stops DMA callbacks from re-enabling interrupts + */ + priv->enabled = false; - /* switch to the internal GPIO IRQ line */ + /* prevent the FPGAs from generating interrupts */ 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; @@ -896,15 +920,6 @@ 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); @@ -917,7 +932,6 @@ 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; } @@ -970,7 +984,13 @@ static ssize_t data_en_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fpga_device *priv = dev_get_drvdata(dev); - return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); + int ret; + + spin_lock_irq(&priv->lock); + ret = snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); + spin_unlock_irq(&priv->lock); + + return ret; } static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, @@ -986,6 +1006,7 @@ 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; @@ -1079,6 +1100,7 @@ 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; @@ -1166,10 +1188,12 @@ have_buffer: * 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) { - videobuf_dma_unmap(priv->dev, &dbuf->vb); - data_free_buffer(dbuf); + drop_buffer = true; goto out_unlock; } @@ -1178,6 +1202,12 @@ have_buffer: 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/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 35361753b487..1c034b80d408 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/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, struct dentry *root); +static void ibmasmfs_create_files (struct super_block *sb); static int ibmasmfs_fill_super (struct super_block *sb, void *data, int silent); @@ -114,7 +114,6 @@ 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; @@ -129,14 +128,11 @@ 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; - root_dentry = d_alloc_root(root); - if (!root_dentry) { - iput(root); + sb->s_root = d_make_root(root); + if (!sb->s_root) return -ENOMEM; - } - sb->s_root = root_dentry; - ibmasmfs_create_files(sb, root_dentry); + ibmasmfs_create_files(sb); return 0; } @@ -612,7 +608,7 @@ static const struct file_operations remote_settings_fops = { }; -static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root) +static void ibmasmfs_create_files (struct super_block *sb) { struct list_head *entry; struct service_processor *sp; @@ -621,7 +617,7 @@ static void ibmasmfs_create_files (struct super_block *sb, struct dentry *root) struct dentry *dir; struct dentry *remote_dir; sp = list_entry(entry, struct service_processor, node); - dir = ibmasmfs_create_dir(sb, root, sp->dirname); + dir = ibmasmfs_create_dir(sb, sb->s_root, sp->dirname); if (!dir) continue; diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 1ccedb71e728..168d8008f460 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -211,18 +211,17 @@ static void __exit ibmasm_exit (void) static int __init ibmasm_init(void) { - int result; + int result = pci_register_driver(&ibmasm_driver); + if (result) + return 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/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index c6a383d0244d..e5a3c7b6dedb 100644 --- a/drivers/mmc/card/block.c +++ b/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) { - mode_t mode; + umode_t mode; if (card->ext_csd.boot_ro_lock & EXT_CSD_BOOT_WP_B_PWR_WP_DIS) mode = S_IRUGO; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 31b034b7eba3..3b1d6da874e0 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -462,6 +462,16 @@ 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/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 618f4ba23699..19bc8cb1d187 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -37,6 +37,7 @@ 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/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c new file mode 100644 index 000000000000..c30ac7b83d28 --- /dev/null +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -0,0 +1,1072 @@ +/* + * Freescale Integrated Flash Controller NAND driver + * + * Copyright 2011-2012 Freescale Semiconductor, Inc + * + * Author: Dipen Dudhat <Dipen.Dudhat@freescale.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 + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/nand_ecc.h> +#include <asm/fsl_ifc.h> + +#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/drivers/net/ethernet/brocade/bna/bnad_debugfs.c b/drivers/net/ethernet/brocade/bna/bnad_debugfs.c index c9fdceb135f3..6e8bc9d88c41 100644 --- a/drivers/net/ethernet/brocade/bna/bnad_debugfs.c +++ b/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; - mode_t mode; + umode_t mode; const struct file_operations *fops; }; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 58dc117a8d78..0427c6561c84 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -13,6 +13,7 @@ #include <linux/init.h> #include <linux/wait.h> #include <linux/cdev.h> +#include <linux/idr.h> #include <linux/fs.h> #include <net/net_namespace.h> diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 2f0aa0f700e6..ee8fd037bb53 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -238,7 +238,6 @@ 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; @@ -251,15 +250,11 @@ 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; - root_dentry = d_alloc_root(root_inode); - if (!root_dentry) { - iput(root_inode); + sb->s_root = d_make_root(root_inode); + if (!sb->s_root) return -ENOMEM; - } - - sb->s_root = root_dentry; - oprofile_create_files(sb, root_dentry); + oprofile_create_files(sb, sb->s_root); // FIXME: verify kill_litter_super removes our dentries return 0; diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d3d18e89cb57..4e89103204dc 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -974,9 +974,8 @@ config SCSI_IPS config SCSI_IBMVSCSI tristate "IBM Virtual SCSI support" - depends on PPC_PSERIES || PPC_ISERIES + depends on PPC_PSERIES select SCSI_SRP_ATTRS - select VIOPATH if PPC_ISERIES help This is the IBM POWER Virtual SCSI Client diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile index a423d9633625..ff5b5c5538ee 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile @@ -1,7 +1,6 @@ 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/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 3d391dc3f11f..e984951baeb6 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -55,13 +55,7 @@ * and sends a CRQ message back to inform the client that the request has * completed. * - * 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 + * TODO: This is currently pretty tied to the IBM pSeries hypervisor * interfaces. It would be really nice to abstract this above an RDMA * layer. */ @@ -2085,9 +2079,7 @@ int __init ibmvscsi_module_init(void) driver_template.can_queue = max_requests; max_events = max_requests + 2; - if (firmware_has_feature(FW_FEATURE_ISERIES)) - ibmvscsi_ops = &iseriesvscsi_ops; - else if (firmware_has_feature(FW_FEATURE_VIO)) + if (firmware_has_feature(FW_FEATURE_VIO)) ibmvscsi_ops = &rpavscsi_ops; else return -ENODEV; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 02197a2b22b9..c503e1776014 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -127,7 +127,6 @@ 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/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c deleted file mode 100644 index f4776451a754..000000000000 --- a/drivers/scsi/ibmvscsi/iseries_vscsi.c +++ /dev/null @@ -1,173 +0,0 @@ -/* ------------------------------------------------------------ - * 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 <asm/iseries/vio.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_types.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/vio.h> -#include <linux/device.h> -#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/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 501b27c18145..1c6f700f5faa 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -23,6 +23,7 @@ #include <linux/crypto.h> #include <linux/completion.h> #include <linux/module.h> +#include <linux/idr.h> #include <asm/unaligned.h> #include <scsi/scsi_device.h> #include <scsi/iscsi_proto.h> diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 38cb7ce8469e..1ee33a8c3fab 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -21,6 +21,7 @@ #include <linux/string.h> #include <linux/kthread.h> #include <linux/crypto.h> +#include <linux/idr.h> #include <scsi/iscsi_proto.h> #include <target/target_core_base.h> #include <target/target_core_fabric.h> diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index 4222035acfb7..48cb8d3d1758 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig @@ -24,16 +24,6 @@ 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 @@ -81,6 +71,10 @@ 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/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index 89abf40bc73d..4ca3723b0a3a 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile @@ -1,7 +1,6 @@ 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/drivers/tty/hvc/hvc_iseries.c b/drivers/tty/hvc/hvc_iseries.c deleted file mode 100644 index 3f4a897bf4d7..000000000000 --- a/drivers/tty/hvc/hvc_iseries.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * 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 <stdarg.h> -#include <linux/types.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/console.h> - -#include <asm/hvconsole.h> -#include <asm/vio.h> -#include <asm/prom.h> -#include <asm/firmware.h> -#include <asm/iseries/vio.h> -#include <asm/iseries/hv_call.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_lp_event.h> - -#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/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c index 4c9b13e7748c..72228276fe31 100644 --- a/drivers/tty/hvc/hvc_udbg.c +++ b/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; i++) + for (i = 0; i < count && udbg_putc; i++) udbg_putc(buf[i]); return i; @@ -67,6 +67,9 @@ 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); @@ -88,6 +91,9 @@ 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/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index fc3c3ad6c072..3a0d53d6368f 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -46,7 +46,6 @@ #include <asm/hvconsole.h> #include <asm/vio.h> #include <asm/prom.h> -#include <asm/firmware.h> #include <asm/hvsi.h> #include <asm/udbg.h> @@ -322,9 +321,6 @@ 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/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 76e7764488e6..665beb68f670 100644 --- a/drivers/tty/serial/Kconfig +++ b/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_ISERIES || PPC_PSERIES) + depends on PCI && PPC_PSERIES select SERIAL_CORE select FW_LOADER help diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 9e186f3da839..cefa0c8b5b6a 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -50,7 +50,6 @@ 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 */ @@ -256,7 +255,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 (ignore_mount) + if (*flags & MS_KERNMOUNT) return 0; if (parse_options(sb, data)) { @@ -454,7 +453,6 @@ 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; @@ -462,19 +460,11 @@ 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); - - if (!inode) { - dbg("%s: could not get inode!",__func__); - return -ENOMEM; - } - - root = d_alloc_root(inode); - if (!root) { + sb->s_root = d_make_root(inode); + if (!sb->s_root) { dbg("%s: could not get root dentry!",__func__); - iput(inode); return -ENOMEM; } - sb->s_root = root; return 0; } @@ -591,11 +581,6 @@ 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) { @@ -603,8 +588,6 @@ 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/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 7f445ec723bc..1cbba70836bc 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1063,13 +1063,9 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) &simple_dir_operations, &simple_dir_inode_operations, &data->perms); - if (unlikely(!inode)) + sb->s_root = d_make_root(inode); + if (unlikely(!sb->s_root)) 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/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 4f18a0e46070..8793f32bab11 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1571,20 +1571,18 @@ delegate: 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); - list_for_each_safe (entry, tmp, &dev->epfiles) { + while (!list_empty(&dev->epfiles)) { struct ep_data *ep; struct inode *parent; struct dentry *dentry; /* break link to FS */ - ep = list_entry (entry, struct ep_data, epfiles); + ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles); list_del_init (&ep->epfiles); dentry = ep->dentry; ep->dentry = NULL; @@ -1607,8 +1605,7 @@ restart: dput (dentry); mutex_unlock (&parent->i_mutex); - /* fds may still be open */ - goto restart; + spin_lock_irq (&dev->lock); } spin_unlock_irq (&dev->lock); } @@ -2061,10 +2058,8 @@ 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_alloc_root (inode))) { - iput(inode); + if (!(sb->s_root = d_make_root (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/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index df9e8f0e327d..7e9e8f4d8f0c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1039,7 +1039,7 @@ config LANTIQ_WDT config GEF_WDT tristate "GE Watchdog Timer" - depends on GEF_SBC610 || GEF_SBC310 || GEF_PPC9A + depends on GE_FPGA ---help--- Watchdog timer found in a number of GE single board computers. diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 1964f98e74be..b85efa773949 100644 --- a/fs/9p/v9fs.c +++ b/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"); - goto out_fs_unreg; + return err; } 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_fs_unreg: - unregister_filesystem(&v9fs_fs_type); +out_cache: + v9fs_cache_unregister(); return err; } diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 7b0cd87b07c2..10b7d3c9dba8 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -155,9 +155,8 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, goto release_sb; } - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) { - iput(inode); retval = -ENOMEM; goto release_sb; } diff --git a/fs/Kconfig b/fs/Kconfig index aa195265362f..f95ae3a027f3 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -214,6 +214,7 @@ 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/fs/Makefile b/fs/Makefile index 93804d4d66e1..2fb977934673 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -102,6 +102,7 @@ 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/fs/adfs/super.c b/fs/adfs/super.c index 8e3b36ace305..06fdcc9382c4 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -483,10 +483,9 @@ 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_alloc_root(root); + sb->s_root = d_make_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/fs/affs/super.c b/fs/affs/super.c index 8ba73fed7964..0782653a05a2 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -473,7 +473,7 @@ got_root: root_inode = affs_iget(sb, root_block); if (IS_ERR(root_inode)) { ret = PTR_ERR(root_inode); - goto out_error_noinode; + goto out_error; } if (AFFS_SB(sb)->s_flags & SF_INTL) @@ -481,7 +481,7 @@ got_root: else sb->s_d_op = &affs_dentry_operations; - sb->s_root = d_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) { printk(KERN_ERR "AFFS: Get root inode failed\n"); goto out_error; @@ -494,9 +494,6 @@ got_root: * 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/fs/afs/super.c b/fs/afs/super.c index 983ec59fc80d..f02b31e7e648 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -301,7 +301,6 @@ 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; @@ -327,18 +326,16 @@ static int afs_fill_super(struct super_block *sb, set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); ret = -ENOMEM; - root = d_alloc_root(inode); - if (!root) + sb->s_root = d_make_root(inode); + if (!sb->s_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; } @@ -199,16 +199,7 @@ 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 @@ -217,13 +208,19 @@ 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(&ctx->wq); - cancel_work_sync(&ctx->wq.work); + cancel_delayed_work_sync(&ctx->wq); 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); } @@ -247,7 +244,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) { struct mm_struct *mm; struct kioctx *ctx; - int did_sync = 0; + int err = -ENOMEM; /* Prevent overflows */ if ((nr_events > (0x10000000U / sizeof(struct io_event))) || @@ -256,7 +253,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) return ERR_PTR(-EINVAL); } - if ((unsigned long)nr_events > aio_max_nr) + if (!nr_events || (unsigned long)nr_events > aio_max_nr) return ERR_PTR(-EAGAIN); ctx = kmem_cache_zalloc(kioctx_cachep, GFP_KERNEL); @@ -280,25 +277,14 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) goto out_freectx; /* limit the number of system wide aios */ - 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) + spin_lock(&aio_nr_lock); + if (aio_nr + nr_events > aio_max_nr || + aio_nr + nr_events < aio_nr) { + spin_unlock(&aio_nr_lock); goto out_cleanup; + } + aio_nr += ctx->max_reqs; + spin_unlock(&aio_nr_lock); /* now link into global list. */ spin_lock(&mm->ioctx_lock); @@ -310,16 +296,13 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) return ctx; out_cleanup: - __put_ioctx(ctx); - return ERR_PTR(-EAGAIN); - + err = -EAGAIN; + aio_free_ring(ctx); out_freectx: mmdrop(mm); kmem_cache_free(kioctx_cachep, ctx); - ctx = ERR_PTR(-ENOMEM); - - dprintk("aio: error allocating ioctx %p\n", ctx); - return ctx; + dprintk("aio: error allocating ioctx %d\n", err); + return ERR_PTR(err); } /* aio_cancel_all @@ -407,10 +390,6 @@ 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 @@ -920,7 +899,7 @@ static void aio_kick_handler(struct work_struct *work) unuse_mm(mm); set_fs(oldfs); /* - * we're in a worker thread already, don't use queue_delayed_work, + * we're in a worker thread already; no point using non-zero delay */ if (requeue) queue_delayed_work(aio_wq, &ctx->wq, 0); diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index f11e43ed907d..28d39fb84ae3 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -39,19 +39,6 @@ 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. @@ -65,6 +52,62 @@ 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" @@ -180,38 +223,6 @@ err_put_unused_fd: } 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; @@ -224,16 +235,8 @@ 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/fs/autofs4/init.c b/fs/autofs4/init.c index c038727b4050..cddc74b9cdb2 100644 --- a/fs/autofs4/init.c +++ b/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) - return err; - - autofs_dev_ioctl_init(); + autofs_dev_ioctl_exit(); return err; } diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 06858d955120..d8dc002e9cc3 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -247,12 +247,9 @@ 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); - if (!root_inode) - goto fail_ino; - - root = d_alloc_root(root_inode); + root = d_make_root(root_inode); if (!root) - goto fail_iput; + goto fail_ino; pipe = NULL; root->d_fsdata = ino; @@ -317,9 +314,6 @@ fail_fput: 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/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 6e6d536767fe..e18da23d42b5 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -852,9 +852,8 @@ befs_fill_super(struct super_block *sb, void *data, int silent) ret = PTR_ERR(root); goto unacquire_priv_sbp; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { - iput(root); befs_error(sb, "get root inode failed"); goto unacquire_priv_sbp; } diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index b0391bc402b1..e23dc7c8b884 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -367,9 +367,8 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) ret = PTR_ERR(inode); goto out2; } - s->s_root = d_alloc_root(inode); + s->s_root = d_make_root(inode); if (!s->s_root) { - iput(inode); ret = -ENOMEM; goto out2; } diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 1ff94054d35a..4d5e6d26578c 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -267,7 +267,6 @@ 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; @@ -454,7 +453,8 @@ out: static int __init init_aout_binfmt(void) { - return register_binfmt(&aout_format); + register_binfmt(&aout_format); + return 0; } static void __exit exit_aout_binfmt(void) diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 07d096c49920..81878b78c9d4 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -712,7 +712,6 @@ 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 @@ -934,7 +933,6 @@ 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) { @@ -2077,7 +2075,8 @@ out: static int __init init_elf_binfmt(void) { - return register_binfmt(&elf_format); + register_binfmt(&elf_format); + return 0; } static void __exit exit_elf_binfmt(void) diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index 30745f459faf..c64bf5ee2df4 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -91,7 +91,8 @@ static struct linux_binfmt elf_fdpic_format = { static int __init init_elf_fdpic_binfmt(void) { - return register_binfmt(&elf_fdpic_format); + register_binfmt(&elf_fdpic_format); + return 0; } static void __exit exit_elf_fdpic_binfmt(void) @@ -334,8 +335,6 @@ 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, @@ -413,7 +412,6 @@ 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/fs/binfmt_em86.c b/fs/binfmt_em86.c index b8e8b0acf9bd..2790c7e1912e 100644 --- a/fs/binfmt_em86.c +++ b/fs/binfmt_em86.c @@ -100,7 +100,8 @@ static struct linux_binfmt em86_format = { static int __init init_em86_binfmt(void) { - return register_binfmt(&em86_format); + register_binfmt(&em86_format); + return 0; } static void __exit exit_em86_binfmt(void) diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index 1bffbe0ed778..04f61f0bdfde 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -902,7 +902,6 @@ 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); @@ -950,7 +949,8 @@ static int load_flat_binary(struct linux_binprm * bprm, struct pt_regs * regs) static int __init init_flat_binfmt(void) { - return register_binfmt(&flat_format); + register_binfmt(&flat_format); + return 0; } /****************************************************************************/ diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index a9198dfd5f85..1ffb60355cae 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -726,11 +726,8 @@ static struct file_system_type bm_fs_type = { static int __init init_misc_binfmt(void) { int err = register_filesystem(&bm_fs_type); - if (!err) { - err = insert_binfmt(&misc_format); - if (err) - unregister_filesystem(&bm_fs_type); - } + if (!err) + insert_binfmt(&misc_format); return err; } diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c index 396a9884591f..d3b8c1f63155 100644 --- a/fs/binfmt_script.c +++ b/fs/binfmt_script.c @@ -105,7 +105,8 @@ static struct linux_binfmt script_format = { static int __init init_script_binfmt(void) { - return register_binfmt(&script_format); + register_binfmt(&script_format); + return 0; } static void __exit exit_script_binfmt(void) diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c index cc8560f6c9b0..e4fc746629a7 100644 --- a/fs/binfmt_som.c +++ b/fs/binfmt_som.c @@ -225,7 +225,6 @@ 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); @@ -289,7 +288,8 @@ static int load_som_library(struct file *f) static int __init init_som_binfmt(void) { - return register_binfmt(&som_format); + register_binfmt(&som_format); + return 0; } static void __exit exit_som_binfmt(void) diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 3ce97b217cbe..81df3fec6a6d 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -629,7 +629,6 @@ 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; @@ -660,15 +659,12 @@ static int btrfs_fill_super(struct super_block *sb, goto fail_close; } - root_dentry = d_alloc_root(inode); - if (!root_dentry) { - iput(inode); + sb->s_root = d_make_root(inode); + if (!sb->s_root) { 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/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index a0358c2189cb..7f0771d3894e 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c @@ -646,7 +646,8 @@ lookup_again: * (this is used to keep track of culling, and atimes are only * updated by read, write and readdir but not lookup or * open) */ - touch_atime(cache->mnt, next); + path.dentry = next; + touch_atime(&path); } /* open a file interface onto a data file */ diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 00de2c9568cd..256f85221926 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -655,9 +655,8 @@ 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_alloc_root(inode); + root = d_make_root(inode); if (!root) { - iput(inode); root = ERR_PTR(-ENOMEM); goto out; } diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index c1b254487388..3cc1b251ca08 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -556,6 +556,7 @@ 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/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index b1fd382d1952..418fc42fb8b2 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -119,12 +119,10 @@ 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_alloc_root(inode); - + sb->s_root = d_make_root(inode); if (!sb->s_root) { rc = -ENOMEM; goto out_no_root; @@ -147,9 +145,6 @@ 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/fs/coda/inode.c b/fs/coda/inode.c index 5e2e1b3f068d..05156c17b551 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -208,13 +208,12 @@ 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_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { error = -EINVAL; goto error; @@ -222,9 +221,6 @@ 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/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index ede857d20a04..b5f0a3b91f18 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -58,12 +58,11 @@ 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 *); +extern struct inode * configfs_new_inode(umode_t mode, struct configfs_dirent *, struct super_block *); 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); @@ -80,15 +79,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 int configfs_pin_fs(void); +extern struct dentry *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/fs/configfs/dir.c b/fs/configfs/dir.c index 5ddd7ebd9dcd..7e6c52d8a207 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -264,11 +264,13 @@ static int init_symlink(struct inode * inode) return 0; } -static int create_dir(struct config_item * k, struct dentry * p, - struct dentry * d) +static int create_dir(struct config_item *k, 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) @@ -304,19 +306,7 @@ static int create_dir(struct config_item * k, struct dentry * p, static int configfs_create_dir(struct config_item * item, struct dentry *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); + int error = create_dir(item, dentry); if (!error) item->ci_dentry = dentry; return error; @@ -1079,23 +1069,24 @@ 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. */ - ret = configfs_pin_fs(); - if (ret) - return ret; + root = configfs_pin_fs(); + if (IS_ERR(root)) + return PTR_ERR(root); /* * 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(&configfs_sb->s_root->d_inode->i_mutex); + mutex_lock(&root->d_inode->i_mutex); - root_sd = configfs_sb->s_root->d_fsdata; + root_sd = root->d_fsdata; list_for_each_entry(p, &root_sd->s_children, s_sibling) { if (p->s_type & CONFIGFS_DIR) { @@ -1129,7 +1120,7 @@ int configfs_depend_item(struct configfs_subsystem *subsys, out_unlock_dirent_lock: spin_unlock(&configfs_dirent_lock); out_unlock_fs: - mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex); + mutex_unlock(&root->d_inode->i_mutex); /* * If we succeeded, the fs is pinned via other methods. If not, @@ -1183,11 +1174,6 @@ 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; /* @@ -1359,9 +1345,6 @@ 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; @@ -1459,6 +1442,11 @@ 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) { @@ -1546,6 +1534,7 @@ 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; @@ -1608,7 +1597,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(configfs_sb, 2); + ino = iunique(sb, 2); if (filldir(dirent, name, len, filp->f_pos, ino, dt_type(next)) < 0) @@ -1680,27 +1669,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; - err = configfs_pin_fs(); - if (err) - return err; + root = configfs_pin_fs(); + if (IS_ERR(root)) + return PTR_ERR(root); if (!group->cg_item.ci_name) group->cg_item.ci_name = group->cg_item.ci_namebuf; - sd = configfs_sb->s_root->d_fsdata; + sd = root->d_fsdata; link_group(to_config_group(sd->s_element), group); - mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, - I_MUTEX_PARENT); + mutex_lock_nested(&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(configfs_sb->s_root, &name); + dentry = d_alloc(root, &name); if (dentry) { d_add(dentry, NULL); @@ -1717,7 +1706,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) } } - mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex); + mutex_unlock(&root->d_inode->i_mutex); if (err) { unlink_group(group); @@ -1731,13 +1720,14 @@ 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 != configfs_sb->s_root) { + if (dentry->d_parent != root) { printk(KERN_ERR "configfs: Tried to unregister non-subsystem!\n"); return; } - mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, + mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT); mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); mutex_lock(&configfs_symlink_mutex); @@ -1754,7 +1744,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) d_delete(dentry); - mutex_unlock(&configfs_sb->s_root->d_inode->i_mutex); + mutex_unlock(&root->d_inode->i_mutex); dput(dentry); diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index 3ee36d418863..0074362d9f7f 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -44,8 +44,6 @@ 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, @@ -132,9 +130,10 @@ 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 inode *configfs_new_inode(umode_t mode, struct configfs_dirent *sd, + struct super_block *s) { - struct inode * inode = new_inode(configfs_sb); + struct inode * inode = new_inode(s); if (inode) { inode->i_ino = get_next_ino(); inode->i_mapping->a_ops = &configfs_aops; @@ -188,36 +187,35 @@ 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; - 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; + struct inode *inode = NULL; + struct configfs_dirent *sd; + struct inode *p_inode; + + if (!dentry) + return -ENOENT; + + if (dentry->d_inode) + return -EEXIST; - Proceed: - if (init) + 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); + + if (init) { error = init(inode); - 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: + 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 */ return error; } diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 276e15cafd58..aee0a7ebbd8e 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -37,8 +37,7 @@ /* Random magic number */ #define CONFIGFS_MAGIC 0x62656570 -struct vfsmount * configfs_mount = NULL; -struct super_block * configfs_sb = NULL; +static struct vfsmount *configfs_mount = NULL; struct kmem_cache *configfs_dir_cachep; static int configfs_mnt_count = 0; @@ -77,12 +76,11 @@ 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); + &configfs_root, sb); if (inode) { - inode->i_op = &configfs_dir_inode_operations; + inode->i_op = &configfs_root_inode_operations; inode->i_fop = &configfs_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); @@ -91,10 +89,9 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; } - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) { pr_debug("%s: could not get root dentry!\n",__func__); - iput(inode); return -ENOMEM; } config_group_init(&configfs_root_group); @@ -118,10 +115,11 @@ static struct file_system_type configfs_fs_type = { .kill_sb = kill_litter_super, }; -int configfs_pin_fs(void) +struct dentry *configfs_pin_fs(void) { - return simple_pin_fs(&configfs_fs_type, &configfs_mount, + int err = 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/fs/configfs/symlink.c b/fs/configfs/symlink.c index 0f3eb41d9201..cc9f2546ea4a 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c @@ -110,13 +110,13 @@ out: static int get_target(const char *symname, struct path *path, - struct config_item **target) + struct config_item **target, struct super_block *sb) { int ret; ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path); if (!ret) { - if (path->dentry->d_sb == configfs_sb) { + if (path->dentry->d_sb == sb) { *target = configfs_get_config_item(path->dentry); if (!*target) { ret = -ENOENT; @@ -141,10 +141,6 @@ 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 @@ -162,7 +158,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); + ret = get_target(symname, &path, &target_item, dentry->d_sb); if (ret) goto out_put; @@ -198,8 +194,6 @@ 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/fs/cramfs/inode.c b/fs/cramfs/inode.c index 04d51f9333d7..d013c46402ed 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -318,11 +318,9 @@ 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_alloc_root(root); - if (!sb->s_root) { - iput(root); + sb->s_root = d_make_root(root); + if (!sb->s_root) goto out; - } return 0; out: kfree(sbi); diff --git a/fs/dcache.c b/fs/dcache.c index 11828de68dce..e441941c834d 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1466,30 +1466,6 @@ 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/fs/debugfs/file.c b/fs/debugfs/file.c index ef023eef0464..21e93605161c 100644 --- a/fs/debugfs/file.c +++ b/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, mode_t mode, +struct dentry *debugfs_create_regset32(const char *name, umode_t mode, struct dentry *parent, struct debugfs_regset32 *regset) { diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 1c6f908e38ca..10f5e0b484db 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -374,12 +374,11 @@ 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_alloc_root(inode); + s->s_root = d_make_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/fs/dlm/dir.c b/fs/dlm/dir.c index 83641574b016..dc5eb598b81f 100644 --- a/fs/dlm/dir.c +++ b/fs/dlm/dir.c @@ -351,11 +351,28 @@ 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/fs/dlm/lock.c b/fs/dlm/lock.c index d47183043c59..fa5c07d51dcc 100644 --- a/fs/dlm/lock.c +++ b/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); } -static int search_rsb_tree(struct rb_root *tree, char *name, int len, - unsigned int flags, struct dlm_rsb **r_ret) +int dlm_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 = search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r); + error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].keep, name, len, flags, &r); if (!error) { kref_get(&r->res_ref); goto out; } - error = search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r); + error = dlm_search_rsb_tree(&ls->ls_rsbtbl[b].toss, name, len, flags, &r); if (error) goto out; diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h index 265017a7c3e7..1a255307f6ff 100644 --- a/fs/dlm/lock.h +++ b/fs/dlm/lock.h @@ -28,6 +28,9 @@ 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/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index ca0c59a4246c..133ef6dc7cb7 100644 --- a/fs/dlm/lowcomms.c +++ b/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 - 1; i++) { + for (i = 0; i < DLM_MAX_ADDR_COUNT; i++) { if (dlm_our_addr(&sas, i)) break; diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index d3f95f941c47..2b17f2f9b121 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -48,8 +48,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb, unsigned long nr_segs, loff_t pos) { ssize_t rc; - struct dentry *lower_dentry; - struct vfsmount *lower_vfsmount; + struct path lower; struct file *file = iocb->ki_filp; rc = generic_file_aio_read(iocb, iov, nr_segs, pos); @@ -60,9 +59,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_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry); - touch_atime(lower_vfsmount, lower_dentry); + lower.dentry = ecryptfs_dentry_to_lower(file->f_path.dentry); + lower.mnt = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry); + touch_atime(&lower); } return rc; } diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index b4a6befb1216..68954937a071 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -550,9 +550,8 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags if (IS_ERR(inode)) goto out_free; - s->s_root = d_alloc_root(inode); + s->s_root = d_make_root(inode); if (!s->s_root) { - iput(inode); rc = -ENOMEM; goto out_free; } @@ -795,15 +794,10 @@ 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_unregister_filesystem; + goto out_free_kmem_caches; } rc = ecryptfs_init_kthread(); if (rc) { @@ -824,19 +818,24 @@ 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/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index cf152823bbf4..2dd946b636d2 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -184,7 +184,6 @@ 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/fs/efs/super.c b/fs/efs/super.c index 981106429a9f..e755ec746c69 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -317,10 +317,9 @@ static int efs_fill_super(struct super_block *s, void *d, int silent) goto out_no_fs; } - s->s_root = d_alloc_root(root); + s->s_root = d_make_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/fs/exec.c b/fs/exec.c index 6ed164d20d7d..23559c227d9c 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -81,15 +81,13 @@ static atomic_t call_count = ATOMIC_INIT(1); static LIST_HEAD(formats); static DEFINE_RWLOCK(binfmt_lock); -int __register_binfmt(struct linux_binfmt * fmt, int insert) +void __register_binfmt(struct linux_binfmt * fmt, int insert) { - if (!fmt) - return -EINVAL; + BUG_ON(!fmt); 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); @@ -1115,7 +1113,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_KTHREAD); + current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD); flush_thread(); current->personality &= ~bprm->per_clear; diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c index 9dbf0c301030..fc7161d6bf6b 100644 --- a/fs/exofs/namei.c +++ b/fs/exofs/namei.c @@ -143,9 +143,6 @@ 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); @@ -156,10 +153,7 @@ 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 = -EMLINK; - - if (dir->i_nlink >= EXOFS_LINK_MAX) - goto out; + int err; inode_inc_link_count(dir); @@ -275,11 +269,6 @@ 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/fs/exofs/super.c b/fs/exofs/super.c index d22cd168c6ee..7f2b590a36b7 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -754,6 +754,7 @@ 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; @@ -818,9 +819,8 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) ret = PTR_ERR(root); goto free_sbi; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { - iput(root); EXOFS_ERR("ERROR: get root inode failed\n"); ret = -ENOMEM; goto free_sbi; diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 080419814bae..dffb86536285 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -195,9 +195,6 @@ 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; @@ -217,10 +214,7 @@ 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 = -EMLINK; - - if (dir->i_nlink >= EXT2_LINK_MAX) - goto out; + int err; dquot_initialize(dir); @@ -346,11 +340,6 @@ 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/fs/ext2/super.c b/fs/ext2/super.c index 0090595beb28..e1025c7a437a 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -919,6 +919,7 @@ 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; @@ -1087,9 +1088,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) goto failed_mount3; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_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/fs/ext3/super.c b/fs/ext3/super.c index 726c7ef6cdf1..e0b45b93327b 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2046,10 +2046,9 @@ 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_alloc_root(root); + sb->s_root = d_make_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/fs/ext4/super.c b/fs/ext4/super.c index 502c61fd7392..933900909ed0 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3735,9 +3735,8 @@ no_journal: iput(root); goto failed_mount4; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { - iput(root); ext4_msg(sb, KERN_ERR, "get root dentry failed"); ret = -ENOMEM; goto failed_mount4; @@ -5056,6 +5055,9 @@ 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++) { @@ -5094,8 +5096,6 @@ 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/fs/fat/inode.c b/fs/fat/inode.c index 3ab841054d53..21687e31acc0 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1496,11 +1496,13 @@ 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) + if (error < 0) { + iput(root_inode); goto out_fail; + } error = -ENOMEM; insert_inode_hash(root_inode); - sb->s_root = d_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) { fat_msg(sb, KERN_ERR, "get root inode failed"); goto out_fail; @@ -1516,8 +1518,6 @@ out_invalid: 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/fs/file_table.c b/fs/file_table.c index 20002e39754d..70f2a0fd6aec 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -204,7 +204,7 @@ EXPORT_SYMBOL(alloc_file); * to write to @file, along with access to write through * its vfsmount. */ -void drop_file_write_access(struct file *file) +static void drop_file_write_access(struct file *file) { struct vfsmount *mnt = file->f_path.mnt; struct dentry *dentry = file->f_path.dentry; @@ -219,7 +219,6 @@ 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/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 9d1c99558389..d4fabd26084e 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -224,9 +224,8 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent) ret = PTR_ERR(root); goto out; } - sbp->s_root = d_alloc_root(root); + sbp->s_root = d_make_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/fs/fs_struct.c b/fs/fs_struct.c index 78b519c13536..6324c4274959 100644 --- a/fs/fs_struct.c +++ b/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,6 +57,14 @@ 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; @@ -68,21 +76,16 @@ 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); - if (fs->root.dentry == old_root->dentry - && fs->root.mnt == old_root->mnt) { - path_get_longterm(new_root); - fs->root = *new_root; + 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--) { 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); @@ -107,10 +110,8 @@ 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/fs/fuse/inode.c b/fs/fuse/inode.c index 64cf8d07393e..4aec5995867e 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -988,14 +988,9 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) err = -ENOMEM; root = fuse_get_root_inode(sb, d.rootmode); - if (!root) + root_dentry = d_make_root(root); + if (!root_dentry) 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/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 14a704015970..197c5c47e577 100644 --- a/fs/gfs2/bmap.c +++ b/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 = grab_cache_page(inode->i_mapping, 0); + page = find_or_create_page(inode->i_mapping, 0, GFP_NOFS); 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 = grab_cache_page(mapping, index); + page = find_or_create_page(mapping, index, GFP_NOFS); if (!page) return 0; diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c index c5fb3597f696..76834587a8a4 100644 --- a/fs/gfs2/file.c +++ b/fs/gfs2/file.c @@ -313,6 +313,8 @@ 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; } @@ -674,6 +676,7 @@ 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; @@ -707,8 +710,8 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len, goto out; } } - if (offset + len > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE)) - i_size_write(inode, offset + len); + if (offset + size > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE)) + i_size_write(inode, offset + size); mark_inode_dirty(inode); @@ -777,12 +780,14 @@ 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/fs/gfs2/glock.c b/fs/gfs2/glock.c index 351a3e797789..dab2526071cc 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -29,6 +29,7 @@ #include <linux/rcupdate.h> #include <linux/rculist_bl.h> #include <linux/bit_spinlock.h> +#include <linux/percpu.h> #include "gfs2.h" #include "incore.h" @@ -543,6 +544,11 @@ __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); @@ -744,6 +750,7 @@ 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); @@ -752,12 +759,17 @@ 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; - snprintf(gl->gl_strname, GDLM_STRNAME_BYTES, "%8x%16llx", name.ln_type, (unsigned long long)number); + 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; 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); @@ -999,6 +1011,8 @@ fail: } 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)) @@ -1658,6 +1672,8 @@ 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; } @@ -1714,8 +1730,78 @@ out: 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) { @@ -1828,6 +1914,35 @@ 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, @@ -1835,7 +1950,21 @@ static const struct seq_operations gfs2_glock_seq_ops = { .show = gfs2_glock_seq_show, }; -static int gfs2_debugfs_open(struct inode *inode, struct file *file) +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) { int ret = seq_open_private(file, &gfs2_glock_seq_ops, sizeof(struct gfs2_glock_iter)); @@ -1847,9 +1976,49 @@ static int gfs2_debugfs_open(struct inode *inode, struct file *file) return ret; } -static const struct file_operations gfs2_debug_fops = { +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 = { .owner = THIS_MODULE, - .open = gfs2_debugfs_open, + .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, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private, @@ -1863,20 +2032,45 @@ 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_debug_fops); + &gfs2_glocks_fops); if (!sdp->debugfs_dentry_glocks) - return -ENOMEM; + 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 0; +fail: + gfs2_delete_debugfs_file(sdp); + return -ENOMEM; } void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp) { - if (sdp && sdp->debugfs_dir) { + if (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/fs/gfs2/incore.h b/fs/gfs2/incore.h index 97742a7ea9cc..47d0bda5ac2b 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -19,6 +19,8 @@ #include <linux/rculist_bl.h> #include <linux/completion.h> #include <linux/rbtree.h> +#include <linux/ktime.h> +#include <linux/percpu.h> #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 @@ -205,6 +207,22 @@ struct gfs2_glock_operations { }; 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 */ HIF_FIRST = 7, @@ -238,10 +256,12 @@ 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; @@ -261,16 +281,14 @@ struct gfs2_glock { struct list_head gl_holders; const struct gfs2_glock_operations *gl_ops; - char gl_strname[GDLM_STRNAME_BYTES]; + ktime_t gl_dstamp; + struct gfs2_lkstats gl_stats; 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; @@ -560,8 +578,14 @@ 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; @@ -620,7 +644,6 @@ 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; @@ -725,8 +748,23 @@ struct gfs2_sbd { unsigned long sd_last_warning; struct dentry *debugfs_dir; /* debugfs directory */ - struct dentry *debugfs_dentry_glocks; /* for debugfs */ + struct dentry *debugfs_dentry_glocks; + struct dentry *debugfs_dentry_glstats; + struct dentry *debugfs_dentry_sbstats; }; +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/fs/gfs2/inode.c b/fs/gfs2/inode.c index 56987460cdae..c98a60ee6dfd 100644 --- a/fs/gfs2/inode.c +++ b/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); + rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1); 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); + nrgd = gfs2_blk2rgrpd(sdp, nip->i_no_addr, 1); if (nrgd) gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++); } diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index 8944d1e32ab5..f8411bd1b805 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -18,14 +18,106 @@ #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) @@ -111,7 +203,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 = 0; + u32 lkf = DLM_LKF_VALBLK; if (gfs_flags & LM_FLAG_TRY) lkf |= DLM_LKF_NOQUEUE; @@ -138,26 +230,43 @@ static u32 make_flags(const u32 lkid, const unsigned int gfs_flags, if (lkid != 0) lkf |= DLM_LKF_CONVERT; - lkf |= DLM_LKF_VALBLK; - return lkf; } +static void gfs2_reverse_hex(char *c, u64 value) +{ + while (value) { + *c-- = hex_asc[value & 0x0f]; + value >>= 4; + } +} + static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, unsigned int flags) { 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, gl->gl_strname, + return dlm_lock(ls->ls_dlm, req, &gl->gl_lksb, lkf, strname, GDLM_STRNAME_BYTES - 1, 0, gdlm_ast, gl, gdlm_bast); } @@ -172,6 +281,10 @@ 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/fs/gfs2/log.c b/fs/gfs2/log.c index 756fae9eaf8f..4752eadc7f6e 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c @@ -19,6 +19,7 @@ #include <linux/freezer.h> #include <linux/bio.h> #include <linux/writeback.h> +#include <linux/list_sort.h> #include "gfs2.h" #include "incore.h" @@ -358,7 +359,7 @@ retry: return 0; } -static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) +u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn) { struct gfs2_journal_extent *je; @@ -467,8 +468,8 @@ static unsigned int current_tail(struct gfs2_sbd *sdp) void gfs2_log_incr_head(struct gfs2_sbd *sdp) { - if (sdp->sd_log_flush_head == sdp->sd_log_tail) - BUG_ON(sdp->sd_log_flush_head != sdp->sd_log_head); + 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_jdesc->jd_blocks) { sdp->sd_log_flush_head = 0; @@ -476,99 +477,6 @@ 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); @@ -583,66 +491,8 @@ 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_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) +static void log_flush_wait(struct gfs2_sbd *sdp) { DEFINE_WAIT(wait); @@ -655,8 +505,20 @@ static void log_flush_commit(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; - log_write_header(sdp, 0, 0); + 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; } static void gfs2_ordered_write(struct gfs2_sbd *sdp) @@ -666,6 +528,7 @@ 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); @@ -711,6 +574,68 @@ static void gfs2_ordered_wait(struct gfs2_sbd *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 * @gl: The glock structure to flush. If NULL, flush the whole incore log @@ -753,11 +678,10 @@ 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_flush_commit(sdp); - else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle){ + 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){ gfs2_log_lock(sdp); atomic_dec(&sdp->sd_log_blks_free); /* Adjust for unreserved buffer */ trace_gfs2_log_blocks(sdp, -1); diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index ab0621698b73..ff07454b582c 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h @@ -53,10 +53,7 @@ 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 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 u64 gfs2_log_bmap(struct gfs2_sbd *sdp, unsigned int lbn); 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/fs/gfs2/lops.c b/fs/gfs2/lops.c index df7c6e8d0764..6b1efb594d90 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -12,6 +12,7 @@ #include <linux/spinlock.h> #include <linux/completion.h> #include <linux/buffer_head.h> +#include <linux/mempool.h> #include <linux/gfs2_ondisk.h> #include <linux/bio.h> #include <linux/fs.h> @@ -76,7 +77,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); + gfs2_rgrp_send_discards(sdp, rgd->rd_data0, bd->bd_bh, bi, 1, NULL); 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); @@ -143,6 +144,98 @@ 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/fs/gfs2/main.c b/fs/gfs2/main.c index a8d9bcd0e19c..754426b1e52c 100644 --- a/fs/gfs2/main.c +++ b/fs/gfs2/main.c @@ -17,6 +17,7 @@ #include <linux/rcupdate.h> #include <linux/rculist_bl.h> #include <linux/atomic.h> +#include <linux/mempool.h> #include "gfs2.h" #include "incore.h" @@ -69,6 +70,16 @@ 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 * @@ -151,6 +162,10 @@ 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(); @@ -160,6 +175,8 @@ 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); @@ -208,6 +225,7 @@ 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/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 24f609c9ef91..6f3a18f9e176 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -68,6 +68,12 @@ 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); @@ -77,7 +83,6 @@ 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); @@ -431,10 +436,9 @@ 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_alloc_root(inode); + dentry = d_make_root(inode); if (!dentry) { fs_err(sdp, "can't alloc %s dentry\n", name); - iput(inode); return -ENOMEM; } *dptr = dentry; @@ -1221,6 +1225,7 @@ fail_sys: 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; @@ -1393,6 +1398,7 @@ 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/fs/gfs2/quota.c b/fs/gfs2/quota.c index c0f8904f0860..6019da3dcaed 100644 --- a/fs/gfs2/quota.c +++ b/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 = grab_cache_page(mapping, index); + page = find_or_create_page(mapping, index, GFP_NOFS); if (!page) return -ENOMEM; diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 49ada95209d0..19bde40b4864 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -327,23 +327,34 @@ 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) +struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact) { - struct rb_node **newn; + struct rb_node *n, *next; struct gfs2_rgrpd *cur; + if (gfs2_rindex_update(sdp)) + return NULL; + spin_lock(&sdp->sd_rindex_spin); - newn = &sdp->sd_rindex_tree.rb_node; - while (*newn) { - cur = rb_entry(*newn, struct gfs2_rgrpd, rd_node); + n = sdp->sd_rindex_tree.rb_node; + while (n) { + cur = rb_entry(n, struct gfs2_rgrpd, rd_node); + next = NULL; if (blk < cur->rd_addr) - newn = &((*newn)->rb_left); + next = n->rb_left; else if (blk >= cur->rd_data0 + cur->rd_data) - newn = &((*newn)->rb_right); - else { + next = n->rb_right; + if (next == NULL) { 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); @@ -532,7 +543,6 @@ 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); @@ -545,11 +555,10 @@ 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 void rgd_insert(struct gfs2_rgrpd *rgd) +static int 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; @@ -565,11 +574,13 @@ static void rgd_insert(struct gfs2_rgrpd *rgd) else if (rgd->rd_addr > cur->rd_addr) newn = &((*newn)->rb_right); else - return; + return -EEXIST; } rb_link_node(&rgd->rd_node, parent, newn); rb_insert_color(&rgd->rd_node, &sdp->sd_rindex_tree); + sdp->sd_rgrps++; + return 0; } /** @@ -623,10 +634,12 @@ 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); - rgd_insert(rgd); - sdp->sd_rgrps++; + error = rgd_insert(rgd); spin_unlock(&sdp->sd_rindex_spin); - return error; + if (!error) + return 0; + + error = 0; /* someone else read in the rgrp; free it and ignore it */ fail: kfree(rgd->rd_bits); @@ -687,7 +700,6 @@ 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) @@ -698,10 +710,8 @@ 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; } @@ -810,9 +820,9 @@ void gfs2_rgrp_go_unlock(struct gfs2_holder *gh) } -void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, +int gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, struct buffer_head *bh, - const struct gfs2_bitmap *bi) + const struct gfs2_bitmap *bi, unsigned minlen, u64 *ptrimmed) { struct super_block *sb = sdp->sd_vfs; struct block_device *bdev = sb->s_bdev; @@ -823,11 +833,19 @@ void 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 *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)); + 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)); + } diff &= 0x55; if (diff == 0) continue; @@ -838,11 +856,14 @@ void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, if (nr_sects == 0) goto start_new_extent; if ((start + nr_sects) != blk) { - rv = blkdev_issue_discard(bdev, start, - nr_sects, GFP_NOFS, - 0); - if (rv) - goto fail; + if (nr_sects >= minlen) { + rv = blkdev_issue_discard(bdev, + start, nr_sects, + GFP_NOFS, 0); + if (rv) + goto fail; + trimmed += nr_sects; + } nr_sects = 0; start_new_extent: start = blk; @@ -853,15 +874,104 @@ start_new_extent: blk += sects_per_blk; } } - if (nr_sects) { + if (nr_sects >= minlen) { rv = blkdev_issue_discard(bdev, start, nr_sects, GFP_NOFS, 0); if (rv) goto fail; + trimmed += nr_sects; } - return; + if (ptrimmed) + *ptrimmed = trimmed; + return 0; + fail: - fs_warn(sdp, "error %d on discard request, turning discards off for this filesystem", rv); + if (sdp->sd_args.ar_discard) + 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; } /** @@ -1008,7 +1118,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); + rgd = begin = gfs2_blk2rgrpd(sdp, ip->i_goal, 1); if (rgd == NULL) return -EBADSLT; @@ -1293,7 +1403,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); + rgd = gfs2_blk2rgrpd(sdp, bstart, 1); if (!rgd) { if (gfs2_consist(sdp)) fs_err(sdp, "block = %llu\n", (unsigned long long)bstart); @@ -1474,7 +1584,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); @@ -1560,14 +1670,9 @@ 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; - - error = gfs2_rindex_update(sdp); - if (error) - return error; + int error = -EINVAL; - error = -EINVAL; - rgd = gfs2_blk2rgrpd(sdp, no_addr); + rgd = gfs2_blk2rgrpd(sdp, no_addr, 1); if (!rgd) goto fail; @@ -1610,7 +1715,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); + rgd = gfs2_blk2rgrpd(sdp, block, 1); if (!rgd) { fs_err(sdp, "rlist_add: no rgrp for block %llu\n", (unsigned long long)block); return; diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h index ceec9106cdf4..b4b10f4de25f 100644 --- a/fs/gfs2/rgrp.h +++ b/fs/gfs2/rgrp.h @@ -11,6 +11,7 @@ #define __RGRP_DOT_H__ #include <linux/slab.h> +#include <linux/uaccess.h> struct gfs2_rgrpd; struct gfs2_sbd; @@ -18,7 +19,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); +extern struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk, bool exact); extern struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp); extern struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd); @@ -62,8 +63,9 @@ 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 void gfs2_rgrp_send_discards(struct gfs2_sbd *sdp, u64 offset, - struct buffer_head *bh, - const struct gfs2_bitmap *bi); +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); #endif /* __RGRP_DOT_H__ */ diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 4553ce515f62..6172fa77ad59 100644 --- a/fs/gfs2/super.c +++ b/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); + rgd = gfs2_blk2rgrpd(sdp, ip->i_no_addr, 1); if (!rgd) { gfs2_consist_inode(ip); error = -EIO; @@ -1557,6 +1557,7 @@ out: 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/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index 5d07609ec57d..dfa89cd75534 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h @@ -11,6 +11,7 @@ #include <linux/dlmconstants.h> #include <linux/gfs2_ondisk.h> #include <linux/writeback.h> +#include <linux/ktime.h> #include "incore.h" #include "glock.h" @@ -43,7 +44,8 @@ {(1UL << GLF_FROZEN), "F" }, \ {(1UL << GLF_QUEUED), "q" }, \ {(1UL << GLF_LRU), "L" }, \ - {(1UL << GLF_OBJECT), "o" }) + {(1UL << GLF_OBJECT), "o" }, \ + {(1UL << GLF_BLOCKING), "b" }) #ifndef NUMPTY #define NUMPTY @@ -236,6 +238,62 @@ 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/fs/gfs2/util.c b/fs/gfs2/util.c index 53511291fe36..9e7765e8e7b0 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -25,6 +25,7 @@ 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/fs/gfs2/util.h b/fs/gfs2/util.h index b432e04600de..a4ce76c67dbb 100644 --- a/fs/gfs2/util.h +++ b/fs/gfs2/util.h @@ -10,6 +10,8 @@ #ifndef __UTIL_DOT_H__ #define __UTIL_DOT_H__ +#include <linux/mempool.h> + #include "incore.h" #define fs_printk(level, fs, fmt, arg...) \ @@ -150,6 +152,7 @@ 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/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index e9636591b5d5..2e5ba425cae7 100644 --- a/fs/gfs2/xattr.c +++ b/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); + rgd = gfs2_blk2rgrpd(sdp, bn, 1); 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); + rgd = gfs2_blk2rgrpd(sdp, ip->i_eattr, 1); if (!rgd) { gfs2_consist_inode(ip); return -EIO; diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 8137fb3e6780..7b4c537d6e13 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -430,15 +430,13 @@ 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_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) - goto bail_iput; + goto bail_no_root; /* 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/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 21a5b7fc6db4..4e75ac646fea 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h @@ -317,6 +317,11 @@ static inline unsigned short hfsplus_min_io_size(struct super_block *sb) /* + * 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/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index 927cdd6d5bf5..921967e5abb1 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h @@ -117,7 +117,7 @@ struct hfsplus_vh { __be32 write_count; __be64 encodings_bmp; - u8 finder_info[32]; + u32 finder_info[8]; struct hfsplus_fork_raw alloc_file; struct hfsplus_fork_raw ext_file; diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 6643b242bdd7..82b69ee4dacc 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -193,6 +193,7 @@ 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); @@ -400,6 +401,7 @@ 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/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c index f66c7655b3f7..c640ba57074b 100644 --- a/fs/hfsplus/ioctl.c +++ b/fs/hfsplus/ioctl.c @@ -20,6 +20,38 @@ #include <asm/uaccess.h> #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; @@ -108,6 +140,8 @@ 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/fs/hfsplus/super.c b/fs/hfsplus/super.c index 427682ca9e48..ceb1c281eefb 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -465,6 +465,13 @@ 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); @@ -515,13 +522,6 @@ 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,7 +529,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) out_put_hidden_dir: iput(sbi->hidden_dir); out_put_root: - iput(root); + dput(sb->s_root); + sb->s_root = NULL; out_put_alloc_file: iput(sbi->alloc_file); out_close_cat_tree: diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index e130bd46d671..588d45885a6f 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/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_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (sb->s_root == NULL) - goto out_put; + goto out; return 0; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 3690467c944e..54f6eccb79d9 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -625,11 +625,9 @@ 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_alloc_root(root); - if (!s->s_root) { - iput(root); + s->s_root = d_make_root(root); + if (!s->s_root) goto bail0; - } /* * find the root directory's . pointer & finish filling in the inode diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index d92f4ce80925..a80e45a690ac 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c @@ -726,17 +726,12 @@ 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)); - if (!root_inode) - goto out_mntput; - - sb->s_root = d_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) - goto out_iput; + goto out_mntput; return 0; - out_iput: - iput(root_inode); out_mntput: mntput(proc_mnt); out: diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 269163324b73..ea251749d9d5 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -860,8 +860,6 @@ bad_val: 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; @@ -898,16 +896,9 @@ 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; - inode = hugetlbfs_get_root(sb, &config); - if (!inode) - goto out_free; - - root = d_alloc_root(inode); - if (!root) { - iput(inode); + sb->s_root = d_make_root(hugetlbfs_get_root(sb, &config)); + if (!sb->s_root) goto out_free; - } - sb->s_root = root; return 0; out_free: if (sbinfo->spool) diff --git a/fs/inode.c b/fs/inode.c index 83ab215baab1..9f4f5fecc096 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -2,29 +2,19 @@ * (C) 1997 Linus Torvalds * (C) 1999 Andrea Arcangeli <andrea@suse.de> (dynamic inode allocation) */ +#include <linux/export.h> #include <linux/fs.h> #include <linux/mm.h> -#include <linux/dcache.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/writeback.h> -#include <linux/module.h> #include <linux/backing-dev.h> -#include <linux/wait.h> -#include <linux/rwsem.h> #include <linux/hash.h> #include <linux/swap.h> #include <linux/security.h> -#include <linux/pagemap.h> #include <linux/cdev.h> #include <linux/bootmem.h> #include <linux/fsnotify.h> #include <linux/mount.h> -#include <linux/async.h> #include <linux/posix_acl.h> #include <linux/prefetch.h> -#include <linux/ima.h> -#include <linux/cred.h> #include <linux/buffer_head.h> /* for inode_has_buffers */ #include <linux/ratelimit.h> #include "internal.h" @@ -1369,17 +1359,6 @@ 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. * @@ -1510,9 +1489,10 @@ 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 vfsmount *mnt, struct dentry *dentry) +void touch_atime(struct path *path) { - struct inode *inode = dentry->d_inode; + struct vfsmount *mnt = path->mnt; + struct inode *inode = path->dentry->d_inode; struct timespec now; if (inode->i_flags & S_NOATIME) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index bd62c76fb5df..29037c365ba4 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -947,9 +947,8 @@ root_found: s->s_d_op = &isofs_dentry_ops[table]; /* get the root dentry */ - s->s_root = d_alloc_root(inode); + s->s_root = d_make_root(inode); if (!(s->s_root)) { - iput(inode); error = -ENOMEM; goto out_no_inode; } diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 2e0123867cb1..c0d5c9d770da 100644 --- a/fs/jffs2/fs.c +++ b/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_alloc_root(root_i); + sb->s_root = d_make_root(root_i); if (!sb->s_root) - goto out_root_i; + goto out_root; sb->s_maxbytes = 0xFFFFFFFF; sb->s_blocksize = PAGE_CACHE_SIZE; @@ -573,8 +573,6 @@ 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/fs/jfs/namei.c b/fs/jfs/namei.c index 5f7c160ea64f..07c91ca6017d 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -220,12 +220,6 @@ 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) @@ -806,9 +800,6 @@ 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); @@ -1138,10 +1129,6 @@ 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/fs/jfs/super.c b/fs/jfs/super.c index 682bca642f38..4a82950f412f 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -441,6 +441,7 @@ 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; @@ -521,7 +522,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_alloc_root(inode); + sb->s_root = d_make_root(inode); if (!sb->s_root) goto out_no_root; @@ -539,7 +540,6 @@ 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,8 +860,14 @@ static int __init init_jfs_fs(void) jfs_proc_init(); #endif - return register_filesystem(&jfs_fs_type); + rc = register_filesystem(&jfs_fs_type); + if (!rc) + return 0; +#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/fs/libfs.c b/fs/libfs.c index 5b2dbb3ba4fc..722e0d5ba182 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -491,11 +491,9 @@ 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_alloc_root(inode); - if (!root) { - iput(inode); + root = d_make_root(inode); + if (!root) return -ENOMEM; - } for (i = 0; !files->name || files->name[0]; i++, files++) { if (!files->name) continue; @@ -536,7 +534,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, 0, type->name, NULL); + mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, NULL); if (IS_ERR(mnt)) return PTR_ERR(mnt); spin_lock(&pin_fs_lock); diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index 1b6e21dda286..bea5d1b9954b 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c @@ -558,9 +558,6 @@ 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/fs/logfs/super.c b/fs/logfs/super.c index c9ee7f5d1caf..97bca623d893 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c @@ -315,11 +315,9 @@ static int logfs_get_sb_final(struct super_block *sb) if (IS_ERR(rootdir)) goto fail; - sb->s_root = d_alloc_root(rootdir); - if (!sb->s_root) { - iput(rootdir); + sb->s_root = d_make_root(rootdir); + if (!sb->s_root) goto fail; - } /* at that point we know that ->put_super() will be called */ super->s_erase_page = alloc_pages(GFP_KERNEL, 0); @@ -542,6 +540,7 @@ 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; @@ -627,7 +626,10 @@ static int __init logfs_init(void) if (ret) goto out2; - return register_filesystem(&logfs_fs_type); + ret = register_filesystem(&logfs_fs_type); + if (!ret) + return 0; + logfs_destroy_inode_cache(); out2: logfs_compr_exit(); out1: diff --git a/fs/minix/inode.c b/fs/minix/inode.c index fa8b612b8ce2..fcb05d2c6b5f 100644 --- a/fs/minix/inode.c +++ b/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; - sbi->s_link_max = MINIX_LINK_MAX; + s->s_max_links = MINIX_LINK_MAX; } else if (s->s_magic == MINIX_SUPER_MAGIC2) { sbi->s_version = MINIX_V1; sbi->s_dirsize = 32; sbi->s_namelen = 30; - sbi->s_link_max = MINIX_LINK_MAX; + s->s_max_links = 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; - sbi->s_link_max = MINIX2_LINK_MAX; + s->s_max_links = 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; - sbi->s_link_max = MINIX2_LINK_MAX; + s->s_max_links = 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,14 +254,6 @@ 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. @@ -270,7 +262,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_iput; + goto out_no_bitmap; } block = minix_blocks_needed( @@ -279,13 +271,21 @@ 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_iput; + 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; } ret = -ENOMEM; - s->s_root = d_alloc_root(root_inode); + s->s_root = d_make_root(root_inode); if (!s->s_root) - goto out_iput; + goto out_no_root; if (!(s->s_flags & MS_RDONLY)) { if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ @@ -301,10 +301,6 @@ 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/fs/minix/minix.h b/fs/minix/minix.h index c889ef0aa571..1ebd11854622 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h @@ -34,7 +34,6 @@ 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/fs/minix/namei.c b/fs/minix/namei.c index 2f76e38c2065..2d0ee1786305 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -94,9 +94,6 @@ 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); @@ -106,10 +103,7 @@ 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 = -EMLINK; - - if (dir->i_nlink >= minix_sb(dir->i_sb)->s_link_max) - goto out; + int err; inode_inc_link_count(dir); @@ -181,7 +175,6 @@ 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; @@ -219,11 +212,6 @@ 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/fs/namei.c b/fs/namei.c index 561db47ae041..a94a7f9a03ea 100644 --- a/fs/namei.c +++ b/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->mnt, dentry); + touch_atime(link); nd_set_link(nd, NULL); error = security_inode_follow_link(link->dentry, nd); @@ -2697,6 +2697,7 @@ 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; @@ -2709,6 +2710,9 @@ 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); @@ -3039,6 +3043,7 @@ 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) @@ -3069,6 +3074,8 @@ 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); @@ -3178,6 +3185,7 @@ 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, @@ -3201,6 +3209,11 @@ 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/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 3d1e34f8a68e..49df0e7f8379 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -716,13 +716,11 @@ 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_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) - goto out_no_root; + goto out_disconnect; return 0; -out_no_root: - iput(root_inode); out_disconnect: ncp_lock_server(server); ncp_disconnect(server); diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 31778f74357d..d4f772ebd1ef 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -36,6 +36,7 @@ #include <linux/inet.h> #include <linux/in6.h> #include <linux/slab.h> +#include <linux/idr.h> #include <net/ipv6.h> #include <linux/nfs_xdr.h> #include <linux/sunrpc/bc_xprt.h> diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index dcb61548887f..801d6d830787 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -49,11 +49,9 @@ 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_alloc_root(inode); - if (sb->s_root == NULL) { - iput(inode); + sb->s_root = d_make_root(inode); + if (sb->s_root == NULL) return -ENOMEM; - } ihold(inode); /* * Ensure that this dentry is invisible to d_find_alias(). diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 2c05f1991e1e..a1bbf7780dfc 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c @@ -198,6 +198,7 @@ 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/fs/nfsd/fault_inject.c b/fs/nfsd/fault_inject.c index ce7f0758d84c..9559ce468732 100644 --- a/fs/nfsd/fault_inject.c +++ b/fs/nfsd/fault_inject.c @@ -72,7 +72,7 @@ int nfsd_fault_inject_init(void) { unsigned int i; struct nfsd_fault_inject_op *op; - mode_t mode = S_IFREG | S_IRUSR | S_IWUSR; + umode_t mode = S_IFREG | S_IRUSR | S_IWUSR; debug_dir = debugfs_create_dir("nfsd", NULL); if (!debug_dir) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index edf6d3ed8777..e59f71d0cf73 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1541,30 +1541,31 @@ 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; - dentry = fhp->fh_dentry; - inode = dentry->d_inode; + path.mnt = fhp->fh_export->ex_path.mnt; + path.dentry = fhp->fh_dentry; + inode = path.dentry->d_inode; err = nfserr_inval; if (!inode->i_op->readlink) goto out; - touch_atime(fhp->fh_export->ex_path.mnt, dentry); + touch_atime(&path); /* 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(dentry, buf, *lenp); + host_err = inode->i_op->readlink(path.dentry, buf, *lenp); set_fs(oldfs); if (host_err < 0) diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 1cd3f624dffc..fce2bbee66d4 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -193,9 +193,6 @@ 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; @@ -219,9 +216,6 @@ 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; @@ -400,11 +394,6 @@ 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/fs/nilfs2/super.c b/fs/nilfs2/super.c index 08e3d4f9df18..1099a76cee59 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c @@ -917,9 +917,8 @@ 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_alloc_root(inode); + dentry = d_make_root(inode); if (!dentry) { - iput(inode); ret = -ENOMEM; goto failed_dentry; } @@ -1059,6 +1058,7 @@ 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/fs/ntfs/super.c b/fs/ntfs/super.c index 28d4e6ab6634..b341492542ca 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -2908,9 +2908,10 @@ 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; } - if ((sb->s_root = d_alloc_root(vol->root_ino))) { - /* We grab a reference, simulating an ntfs_iget(). */ - ihold(vol->root_ino); + + /* We grab a reference, simulating an ntfs_iget(). */ + ihold(vol->root_ino); + if ((sb->s_root = d_make_root(vol->root_ino))) { ntfs_debug("Exiting, status successful."); /* Release the default upcase if it has no users. */ mutex_lock(&ntfs_lock); @@ -3158,6 +3159,8 @@ 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/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index abfac0d7ae9c..3b5825ef3193 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c @@ -582,24 +582,14 @@ 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; - inode = dlmfs_get_root_inode(sb); - if (!inode) - return -ENOMEM; - - root = d_alloc_root(inode); - if (!root) { - iput(inode); + sb->s_root = d_make_root(dlmfs_get_root_inode(sb)); + if (!sb->s_root) return -ENOMEM; - } - sb->s_root = root; return 0; } diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 604e12c4e979..68f4541c2db9 100644 --- a/fs/ocfs2/super.c +++ b/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 (osb->root_inode) - inode = igrab(osb->root_inode); - if (status < 0) goto read_super_error; + if (osb->root_inode) + inode = igrab(osb->root_inode); + if (!inode) { status = -EIO; mlog_errno(status); goto read_super_error; } - root = d_alloc_root(inode); + root = d_make_root(inode); if (!root) { status = -ENOMEM; mlog_errno(status); @@ -1220,9 +1220,6 @@ 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); @@ -1627,21 +1624,17 @@ static int __init ocfs2_init(void) init_waitqueue_head(&ocfs2__ioend_wq[i]); status = init_ocfs2_uptodate_cache(); - if (status < 0) { - mlog_errno(status); - goto leave; - } + if (status < 0) + goto out1; status = ocfs2_initialize_mem_caches(); - if (status < 0) { - mlog_errno(status); - goto leave; - } + if (status < 0) + goto out2; ocfs2_wq = create_singlethread_workqueue("ocfs2_wq"); if (!ocfs2_wq) { status = -ENOMEM; - goto leave; + goto out3; } ocfs2_debugfs_root = debugfs_create_dir("ocfs2", NULL); @@ -1653,17 +1646,23 @@ static int __init ocfs2_init(void) ocfs2_set_locking_protocol(); status = register_quota_format(&ocfs2_quota_format); -leave: - if (status < 0) { - ocfs2_free_mem_caches(); - exit_ocfs2_uptodate_cache(); - mlog_errno(status); - } + if (status < 0) + goto out4; + status = register_filesystem(&ocfs2_fs_type); + if (!status) + return 0; - if (status >= 0) { - return register_filesystem(&ocfs2_fs_type); - } else - return -1; + 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; } static void __exit ocfs2_exit(void) diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 6065bb0ba207..dbc842222589 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c @@ -539,11 +539,9 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) goto out_brelse_bh2; } - sb->s_root = d_alloc_root(root); - if (!sb->s_root) { - iput(root); + sb->s_root = d_make_root(root); + if (!sb->s_root) goto out_brelse_bh2; - } printk(KERN_DEBUG "omfs: Mounted volume %s\n", omfs_rb->r_name); ret = 0; diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index a88c03bc749d..bc49c975d501 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -408,13 +408,12 @@ 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_alloc_root(root_inode); + s->s_root = d_make_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/fs/proc/inode.c b/fs/proc/inode.c index 84fd3235a590..8461a7b82fdb 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -486,8 +486,6 @@ 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; @@ -496,19 +494,11 @@ int proc_fill_super(struct super_block *s) s->s_time_gran = 1; pde_get(&proc_root); - 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; + s->s_root = d_make_root(proc_get_inode(s, &proc_root)); + if (s->s_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/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index a6b62173d4c3..67bbf6e4e197 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -6,7 +6,9 @@ #include <linux/poll.h> #include <linux/proc_fs.h> #include <linux/security.h> +#include <linux/sched.h> #include <linux/namei.h> +#include <linux/mm.h> #include "internal.h" static const struct dentry_operations proc_sys_dentry_operations; diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index b0f450a2bb7c..0d5071d29985 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -700,3 +700,26 @@ 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/fs/pstore/inode.c b/fs/pstore/inode.c index b3b426edb2fd..f37c32b94525 100644 --- a/fs/pstore/inode.c +++ b/fs/pstore/inode.c @@ -278,9 +278,7 @@ fail: int pstore_fill_super(struct super_block *sb, void *data, int silent) { - struct inode *inode = NULL; - struct dentry *root; - int err; + struct inode *inode; save_mount_options(sb, data); @@ -296,26 +294,17 @@ 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) { - 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; + if (inode) { + /* override ramfs "dir" options so we catch unlink(2) */ + inode->i_op = &pstore_dir_inode_operations; } + 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/fs/qnx4/inode.c b/fs/qnx4/inode.c index 6b009548d2e0..552e994e3aa1 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -52,38 +52,6 @@ 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; @@ -98,23 +66,31 @@ 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 offset, i_xblk; - unsigned long block = 0; + long i_xblk; 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 ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) { + if (block) { // 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 ) { @@ -130,12 +106,11 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock ) return -EIO; } } - if ( offset < le32_to_cpu(xblk->xblk_xtnts[ix].xtnt_size) ) { + block = try_extent(&xblk->xblk_xtnts[ix], &offset); + if (block) { // 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; @@ -260,15 +235,13 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent) } ret = -ENOMEM; - s->s_root = d_alloc_root(root); + s->s_root = d_make_root(root); if (s->s_root == NULL) - goto outi; + goto outb; brelse(bh); return 0; - outi: - iput(root); outb: kfree(qs->BitMap); out: @@ -288,44 +261,17 @@ 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/fs/qnx4/namei.c b/fs/qnx4/namei.c index 275327b5615e..a512c0b30e8e 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c @@ -39,10 +39,6 @@ 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; @@ -72,7 +68,9 @@ 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) { - bh = qnx4_bread(dir, blkofs, 0); + block = qnx4_block_map(dir, blkofs); + if (block) + bh = sb_bread(dir->i_sb, block); if (!bh) { blkofs++; continue; @@ -80,7 +78,6 @@ 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/fs/qnx4/qnx4.h b/fs/qnx4/qnx4.h index 33a60858203b..244d4620189b 100644 --- a/fs/qnx4/qnx4.h +++ b/fs/qnx4/qnx4.h @@ -27,8 +27,6 @@ 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/fs/qnx6/Kconfig b/fs/qnx6/Kconfig new file mode 100644 index 000000000000..edbba5c17cc8 --- /dev/null +++ b/fs/qnx6/Kconfig @@ -0,0 +1,26 @@ +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 <http://www.qnx.com/>. + 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/fs/qnx6/Makefile b/fs/qnx6/Makefile new file mode 100644 index 000000000000..9dd06199afc9 --- /dev/null +++ b/fs/qnx6/Makefile @@ -0,0 +1,7 @@ +# +# 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/fs/qnx6/README b/fs/qnx6/README new file mode 100644 index 000000000000..116d622026cc --- /dev/null +++ b/fs/qnx6/README @@ -0,0 +1,8 @@ + + This is a snapshot of the QNX6 filesystem for Linux. + Please send diffs and remarks to <chaosman@ontika.net> . + +Credits : + +Al Viro <viro@ZenIV.linux.org.uk> (endless patience with me & support ;)) +Kai Bankett <chaosman@ontika.net> (Maintainer) diff --git a/fs/qnx6/dir.c b/fs/qnx6/dir.c new file mode 100644 index 000000000000..dc597353db3b --- /dev/null +++ b/fs/qnx6/dir.c @@ -0,0 +1,291 @@ +/* + * 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/fs/qnx6/inode.c b/fs/qnx6/inode.c new file mode 100644 index 000000000000..e44012dc5645 --- /dev/null +++ b/fs/qnx6/inode.c @@ -0,0 +1,698 @@ +/* + * 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 <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/highuid.h> +#include <linux/pagemap.h> +#include <linux/buffer_head.h> +#include <linux/writeback.h> +#include <linux/statfs.h> +#include <linux/parser.h> +#include <linux/seq_file.h> +#include <linux/mount.h> +#include <linux/crc32.h> +#include <linux/mpage.h> +#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/fs/qnx6/namei.c b/fs/qnx6/namei.c new file mode 100644 index 000000000000..8a97289e04ad --- /dev/null +++ b/fs/qnx6/namei.c @@ -0,0 +1,42 @@ +/* + * 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/fs/qnx6/qnx6.h b/fs/qnx6/qnx6.h new file mode 100644 index 000000000000..6c5e02a0b6a8 --- /dev/null +++ b/fs/qnx6/qnx6.h @@ -0,0 +1,135 @@ +/* + * 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 <linux/fs.h> +#include <linux/pagemap.h> + +typedef __u16 __bitwise __fs16; +typedef __u32 __bitwise __fs32; +typedef __u64 __bitwise __fs64; + +#include <linux/qnx6_fs.h> + +#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/fs/qnx6/super_mmi.c b/fs/qnx6/super_mmi.c new file mode 100644 index 000000000000..29c32cba62d6 --- /dev/null +++ b/fs/qnx6/super_mmi.c @@ -0,0 +1,150 @@ +/* + * QNX6 file system, Linux implementation. + * + * Version : 1.0.0 + * + * History : + * + * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release. + * + */ + +#include <linux/buffer_head.h> +#include <linux/slab.h> +#include <linux/crc32.h> +#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/fs/quota/dquot.c b/fs/quota/dquot.c index 46741970371b..8b4f12b33f57 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -71,6 +71,7 @@ #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/security.h> +#include <linux/sched.h> #include <linux/kmod.h> #include <linux/namei.h> #include <linux/capability.h> diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index aec766abe3af..a1fdabe21dec 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -209,22 +209,19 @@ 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 = NULL; - struct dentry *root; + struct inode *inode; int err; save_mount_options(sb, data); fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL); sb->s_fs_info = fsi; - if (!fsi) { - err = -ENOMEM; - goto fail; - } + if (!fsi) + return -ENOMEM; err = ramfs_parse_options(data, &fsi->mount_opts); if (err) - goto fail; + return err; sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = PAGE_CACHE_SIZE; @@ -234,24 +231,11 @@ 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); - if (!inode) { - err = -ENOMEM; - goto fail; - } - - 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; 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/include/linux/reiserfs_acl.h b/fs/reiserfs/acl.h index f096b80e73d8..f096b80e73d8 100644 --- a/include/linux/reiserfs_acl.h +++ b/fs/reiserfs/acl.h diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c index 70de42f09f1d..4c0c7d163d15 100644 --- a/fs/reiserfs/bitmap.c +++ b/fs/reiserfs/bitmap.c @@ -4,14 +4,12 @@ /* Reiserfs block (de)allocator, bitmap-based. */ #include <linux/time.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/errno.h> #include <linux/buffer_head.h> #include <linux/kernel.h> #include <linux/pagemap.h> #include <linux/vmalloc.h> -#include <linux/reiserfs_fs_sb.h> -#include <linux/reiserfs_fs_i.h> #include <linux/quotaops.h> #include <linux/seq_file.h> diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index 133e9355dc6f..66c53b642a88 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c @@ -5,7 +5,7 @@ #include <linux/string.h> #include <linux/errno.h> #include <linux/fs.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/stat.h> #include <linux/buffer_head.h> #include <linux/slab.h> diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index 60c080440661..2b7882b508db 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c @@ -17,7 +17,7 @@ #include <asm/uaccess.h> #include <linux/time.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/buffer_head.h> #include <linux/kernel.h> diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index ace635053a36..8375c922c0d5 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -3,9 +3,9 @@ */ #include <linux/time.h> -#include <linux/reiserfs_fs.h> -#include <linux/reiserfs_acl.h> -#include <linux/reiserfs_xattr.h> +#include "reiserfs.h" +#include "acl.h" +#include "xattr.h" #include <asm/uaccess.h> #include <linux/pagemap.h> #include <linux/swap.h> diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c index 1e4250bc3a6f..430e0658704c 100644 --- a/fs/reiserfs/fix_node.c +++ b/fs/reiserfs/fix_node.c @@ -37,7 +37,7 @@ #include <linux/time.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/buffer_head.h> /* To make any changes in the tree we find a node, that contains item diff --git a/fs/reiserfs/hashes.c b/fs/reiserfs/hashes.c index 6471c670743e..91b0cc1242a2 100644 --- a/fs/reiserfs/hashes.c +++ b/fs/reiserfs/hashes.c @@ -19,7 +19,7 @@ // #include <linux/kernel.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <asm/types.h> #define DELTA 0x9E3779B9 diff --git a/fs/reiserfs/ibalance.c b/fs/reiserfs/ibalance.c index 2074fd95046b..e1978fd895f5 100644 --- a/fs/reiserfs/ibalance.c +++ b/fs/reiserfs/ibalance.c @@ -5,7 +5,7 @@ #include <asm/uaccess.h> #include <linux/string.h> #include <linux/time.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/buffer_head.h> /* this is one and only function that is used outside (do_balance.c) */ diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 9e8cd5acd79c..494c315c7417 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -4,9 +4,9 @@ #include <linux/time.h> #include <linux/fs.h> -#include <linux/reiserfs_fs.h> -#include <linux/reiserfs_acl.h> -#include <linux/reiserfs_xattr.h> +#include "reiserfs.h" +#include "acl.h" +#include "xattr.h" #include <linux/exportfs.h> #include <linux/pagemap.h> #include <linux/highmem.h> diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c index 950e3d1b5c9e..0c2185042d5f 100644 --- a/fs/reiserfs/ioctl.c +++ b/fs/reiserfs/ioctl.c @@ -5,7 +5,7 @@ #include <linux/capability.h> #include <linux/fs.h> #include <linux/mount.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/time.h> #include <asm/uaccess.h> #include <linux/pagemap.h> diff --git a/fs/reiserfs/item_ops.c b/fs/reiserfs/item_ops.c index 72cb1cc51b87..ee382ef3d300 100644 --- a/fs/reiserfs/item_ops.c +++ b/fs/reiserfs/item_ops.c @@ -3,7 +3,7 @@ */ #include <linux/time.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" // this contains item handlers for old item types: sd, direct, // indirect, directory diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index c3cf54fd4de3..cf9f4de00a95 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c @@ -37,7 +37,7 @@ #include <linux/time.h> #include <linux/semaphore.h> #include <linux/vmalloc.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/kernel.h> #include <linux/errno.h> #include <linux/fcntl.h> diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c index b43d01556313..79e5a8b4c226 100644 --- a/fs/reiserfs/lbalance.c +++ b/fs/reiserfs/lbalance.c @@ -5,7 +5,7 @@ #include <asm/uaccess.h> #include <linux/string.h> #include <linux/time.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/buffer_head.h> /* these are used in do_balance.c */ diff --git a/fs/reiserfs/lock.c b/fs/reiserfs/lock.c index 7df1ce48203a..d735bc8470e3 100644 --- a/fs/reiserfs/lock.c +++ b/fs/reiserfs/lock.c @@ -1,4 +1,4 @@ -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/mutex.h> /* diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 146378865239..84e8a69cee9d 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -14,9 +14,9 @@ #include <linux/time.h> #include <linux/bitops.h> #include <linux/slab.h> -#include <linux/reiserfs_fs.h> -#include <linux/reiserfs_acl.h> -#include <linux/reiserfs_xattr.h> +#include "reiserfs.h" +#include "acl.h" +#include "xattr.h" #include <linux/quotaops.h> #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/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c index 3a6de810bd61..f732d6a5251d 100644 --- a/fs/reiserfs/objectid.c +++ b/fs/reiserfs/objectid.c @@ -5,8 +5,7 @@ #include <linux/string.h> #include <linux/random.h> #include <linux/time.h> -#include <linux/reiserfs_fs.h> -#include <linux/reiserfs_fs_sb.h> +#include "reiserfs.h" // find where objectid map starts #define objectid_map(s,rs) (old_format_only (s) ? \ diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index 45de98b59466..c0b1112ab7e3 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c @@ -4,7 +4,7 @@ #include <linux/time.h> #include <linux/fs.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/string.h> #include <linux/buffer_head.h> @@ -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_fs.h have numbers from 1000 to 1999 + panics in reiserfs.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/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c index 7a9981196c1c..2c1ade692cc8 100644 --- a/fs/reiserfs/procfs.c +++ b/fs/reiserfs/procfs.c @@ -12,8 +12,7 @@ #include <linux/time.h> #include <linux/seq_file.h> #include <asm/uaccess.h> -#include <linux/reiserfs_fs.h> -#include <linux/reiserfs_fs_sb.h> +#include "reiserfs.h" #include <linux/init.h> #include <linux/proc_fs.h> diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h new file mode 100644 index 000000000000..445d768eea44 --- /dev/null +++ b/fs/reiserfs/reiserfs.h @@ -0,0 +1,2922 @@ +/* + * Copyright 1996, 1997, 1998 Hans Reiser, see reiserfs/README for licensing and copyright details + */ + +#include <linux/reiserfs_fs.h> + +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/workqueue.h> +#include <asm/unaligned.h> +#include <linux/bitops.h> +#include <linux/proc_fs.h> +#include <linux/buffer_head.h> + +/* 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/fs/reiserfs/resize.c b/fs/reiserfs/resize.c index 7483279b482d..9a17f63c3fd7 100644 --- a/fs/reiserfs/resize.c +++ b/fs/reiserfs/resize.c @@ -13,8 +13,7 @@ #include <linux/vmalloc.h> #include <linux/string.h> #include <linux/errno.h> -#include <linux/reiserfs_fs.h> -#include <linux/reiserfs_fs_sb.h> +#include "reiserfs.h" #include <linux/buffer_head.h> int reiserfs_resize(struct super_block *s, unsigned long block_count_new) diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c index 77df82f9e70a..f8afa4b162b8 100644 --- a/fs/reiserfs/stree.c +++ b/fs/reiserfs/stree.c @@ -51,7 +51,7 @@ #include <linux/time.h> #include <linux/string.h> #include <linux/pagemap.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/buffer_head.h> #include <linux/quotaops.h> diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index e12d8b97cd4d..8b7616ef06d8 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -16,9 +16,9 @@ #include <linux/vmalloc.h> #include <linux/time.h> #include <asm/uaccess.h> -#include <linux/reiserfs_fs.h> -#include <linux/reiserfs_acl.h> -#include <linux/reiserfs_xattr.h> +#include "reiserfs.h" +#include "acl.h" +#include "xattr.h" #include <linux/init.h> #include <linux/blkdev.h> #include <linux/buffer_head.h> @@ -1874,11 +1874,9 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent) unlock_new_inode(root_inode); } - s->s_root = d_alloc_root(root_inode); - if (!s->s_root) { - iput(root_inode); + s->s_root = d_make_root(root_inode); + if (!s->s_root) goto error; - } // define and initialize hash function sbi->s_hash_function = hash_function(s); if (sbi->s_hash_function == NULL) { diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c index 8f546bd473b8..5e2624d12f70 100644 --- a/fs/reiserfs/tail_conversion.c +++ b/fs/reiserfs/tail_conversion.c @@ -5,7 +5,7 @@ #include <linux/time.h> #include <linux/pagemap.h> #include <linux/buffer_head.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" /* 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/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index c24deda8a8bc..46fc1c20a6b1 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -33,7 +33,7 @@ * The xattrs themselves are protected by the xattr_sem. */ -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/capability.h> #include <linux/dcache.h> #include <linux/namei.h> @@ -43,8 +43,8 @@ #include <linux/file.h> #include <linux/pagemap.h> #include <linux/xattr.h> -#include <linux/reiserfs_xattr.h> -#include <linux/reiserfs_acl.h> +#include "xattr.h" +#include "acl.h" #include <asm/uaccess.h> #include <net/checksum.h> #include <linux/stat.h> diff --git a/fs/reiserfs/xattr.h b/fs/reiserfs/xattr.h new file mode 100644 index 000000000000..f59626c5d33b --- /dev/null +++ b/fs/reiserfs/xattr.h @@ -0,0 +1,122 @@ +#include <linux/reiserfs_xattr.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/rwsem.h> + +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/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c index 6da0396e5052..44474f9b990d 100644 --- a/fs/reiserfs/xattr_acl.c +++ b/fs/reiserfs/xattr_acl.c @@ -1,14 +1,14 @@ #include <linux/capability.h> #include <linux/fs.h> #include <linux/posix_acl.h> -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/errno.h> #include <linux/pagemap.h> #include <linux/xattr.h> #include <linux/slab.h> #include <linux/posix_acl_xattr.h> -#include <linux/reiserfs_xattr.h> -#include <linux/reiserfs_acl.h> +#include "xattr.h" +#include "acl.h" #include <asm/uaccess.h> static int reiserfs_set_acl(struct reiserfs_transaction_handle *th, diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c index 534668fa41be..800a3cef6f62 100644 --- a/fs/reiserfs/xattr_security.c +++ b/fs/reiserfs/xattr_security.c @@ -1,10 +1,10 @@ -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/errno.h> #include <linux/fs.h> #include <linux/pagemap.h> #include <linux/xattr.h> #include <linux/slab.h> -#include <linux/reiserfs_xattr.h> +#include "xattr.h" #include <linux/security.h> #include <asm/uaccess.h> diff --git a/fs/reiserfs/xattr_trusted.c b/fs/reiserfs/xattr_trusted.c index 9883736ce3ec..a0035719f66b 100644 --- a/fs/reiserfs/xattr_trusted.c +++ b/fs/reiserfs/xattr_trusted.c @@ -1,10 +1,10 @@ -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/capability.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/pagemap.h> #include <linux/xattr.h> -#include <linux/reiserfs_xattr.h> +#include "xattr.h" #include <asm/uaccess.h> static int diff --git a/fs/reiserfs/xattr_user.c b/fs/reiserfs/xattr_user.c index 45ae1a00013a..8667491ae7c3 100644 --- a/fs/reiserfs/xattr_user.c +++ b/fs/reiserfs/xattr_user.c @@ -1,9 +1,9 @@ -#include <linux/reiserfs_fs.h> +#include "reiserfs.h" #include <linux/errno.h> #include <linux/fs.h> #include <linux/pagemap.h> #include <linux/xattr.h> -#include <linux/reiserfs_xattr.h> +#include "xattr.h" #include <asm/uaccess.h> static int diff --git a/fs/romfs/super.c b/fs/romfs/super.c index bb36ab74eb45..e64f6b5f7ae5 100644 --- a/fs/romfs/super.c +++ b/fs/romfs/super.c @@ -538,14 +538,12 @@ static int romfs_fill_super(struct super_block *sb, void *data, int silent) if (IS_ERR(root)) goto error; - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) - goto error_i; + goto error; return 0; -error_i: - iput(root); error: return -EINVAL; error_rsb_inval: diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index ecaa2f7bdb8f..970b1167e7cb 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c @@ -316,11 +316,10 @@ check_directory_table: } insert_inode_hash(root); - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (sb->s_root == NULL) { ERROR("Root inode create failed\n"); err = -ENOMEM; - iput(root); goto failed_mount; } diff --git a/fs/stat.c b/fs/stat.c index 8806b8997d2e..86f13563a463 100644 --- a/fs/stat.c +++ b/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.mnt, path.dentry); + touch_atime(&path); error = inode->i_op->readlink(path.dentry, buf, bufsiz); } diff --git a/fs/super.c b/fs/super.c index 6277ec6cb60a..d90e900a8a0e 100644 --- a/fs/super.c +++ b/fs/super.c @@ -32,6 +32,7 @@ #include <linux/backing-dev.h> #include <linux/rculist_bl.h> #include <linux/cleancache.h> +#include <linux/fsnotify.h> #include "internal.h" diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 140f26a34288..52c3bdb66a84 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -61,10 +61,9 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent) } /* instantiate and link root dentry */ - root = d_alloc_root(inode); + root = d_make_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/fs/sysv/namei.c b/fs/sysv/namei.c index b217797e621b..d7466e293614 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -121,9 +121,6 @@ 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); @@ -134,10 +131,8 @@ 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 = -EMLINK; + int err; - 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); @@ -251,11 +246,6 @@ 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/fs/sysv/super.c b/fs/sysv/super.c index f60c196913ea..7491c33b6468 100644 --- a/fs/sysv/super.c +++ b/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) +static void detected_xenix(struct sysv_sb_info *sbi, unsigned *max_links) { 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) sbd2 = (struct xenix_super_block *) (bh2->b_data - 512); } - sbi->s_link_max = XENIX_LINK_MAX; + *max_links = 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) sbi->s_nzones = fs32_to_cpu(sbi, sbd1->s_fsize); } -static void detected_sysv4(struct sysv_sb_info *sbi) +static void detected_sysv4(struct sysv_sb_info *sbi, unsigned *max_links) { 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) else sbd = (struct sysv4_super_block *) bh2->b_data; - sbi->s_link_max = SYSV_LINK_MAX; + *max_links = 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) sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); } -static void detected_sysv2(struct sysv_sb_info *sbi) +static void detected_sysv2(struct sysv_sb_info *sbi, unsigned *max_links) { 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) else sbd = (struct sysv2_super_block *) bh2->b_data; - sbi->s_link_max = SYSV_LINK_MAX; + *max_links = 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) sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); } -static void detected_coherent(struct sysv_sb_info *sbi) +static void detected_coherent(struct sysv_sb_info *sbi, unsigned *max_links) { struct coh_super_block * sbd; struct buffer_head *bh1 = sbi->s_bh1; sbd = (struct coh_super_block *) bh1->b_data; - sbi->s_link_max = COH_LINK_MAX; + *max_links = 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) sbi->s_nzones = fs32_to_cpu(sbi, sbd->s_fsize); } -static void detected_v7(struct sysv_sb_info *sbi) +static void detected_v7(struct sysv_sb_info *sbi, unsigned *max_links) { struct buffer_head *bh2 = sbi->s_bh2; struct v7_super_block *sbd = (struct v7_super_block *)bh2->b_data; - sbi->s_link_max = V7_LINK_MAX; + *max_links = 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 *) = { +static void (*flavour_setup[])(struct sysv_sb_info *, unsigned *) = { [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); + flavour_setup[sbi->s_type](sbi, &sb->s_max_links); sbi->s_truncate = 1; sbi->s_ndatazones = sbi->s_nzones - sbi->s_firstdatazone; @@ -341,9 +341,8 @@ 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_alloc_root(root_inode); + sb->s_root = d_make_root(root_inode); if (!sb->s_root) { - iput(root_inode); printk("SysV FS: get root dentry failed\n"); return 0; } diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index 0e4b821c5691..11b07672f6c5 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h @@ -24,7 +24,6 @@ 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/fs/ubifs/super.c b/fs/ubifs/super.c index 63765d58445b..76e4e0566ad6 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -2076,15 +2076,13 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) goto out_umount; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) - goto out_iput; + goto out_umount; mutex_unlock(&c->umount_mutex); return 0; -out_iput: - iput(root); out_umount: ubifs_umount(c); out_unlock: diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 08bf46edf9c4..38de8f234b94 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -32,8 +32,6 @@ #include <linux/crc-itu-t.h> #include <linux/exportfs.h> -enum { UDF_MAX_LINKS = 0xffff }; - static inline int udf_match(int len1, const unsigned char *name1, int len2, const unsigned char *name2) { @@ -649,10 +647,6 @@ 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) @@ -1032,9 +1026,6 @@ 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; @@ -1126,10 +1117,6 @@ 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/fs/udf/super.c b/fs/udf/super.c index c09a84daaf50..85067b4c7e14 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -75,6 +75,8 @@ #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 *); @@ -2035,13 +2037,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_alloc_root(inode); + sb->s_root = d_make_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/fs/ufs/namei.c b/fs/ufs/namei.c index 38cac199edff..a2281cadefa1 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -166,10 +166,6 @@ 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); @@ -183,10 +179,7 @@ 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 = -EMLINK; - - if (dir->i_nlink >= UFS_LINK_MAX) - goto out; + int err; lock_ufs(dir->i_sb); inode_inc_link_count(dir); @@ -305,11 +298,6 @@ 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/fs/ufs/super.c b/fs/ufs/super.c index 5246ee3e5607..f636f6b460d0 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1157,16 +1157,17 @@ magic_found: "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_alloc_root(inode); + sb->s_root = d_make_root(inode); if (!sb->s_root) { ret = -ENOMEM; - goto dalloc_failed; + goto failed; } ufs_setup_cstotal(sb); @@ -1180,8 +1181,6 @@ magic_found: UFSD("EXIT\n"); return 0; -dalloc_failed: - iput(inode); failed: if (ubh) ubh_brelse_uspi (uspi); diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index 866de277079a..e44ef7ee8ce8 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c @@ -118,17 +118,6 @@ 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/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index ee5b695c99a7..baf40e378d35 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -1341,6 +1341,7 @@ 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); @@ -1361,10 +1362,10 @@ xfs_fs_fill_super( error = EINVAL; goto out_syncd_stop; } - sb->s_root = d_alloc_root(root); + sb->s_root = d_make_root(root); if (!sb->s_root) { error = ENOMEM; - goto out_iput; + goto out_syncd_stop; } return 0; @@ -1383,8 +1384,6 @@ xfs_fs_fill_super( out: return -error; - out_iput: - iput(root); out_syncd_stop: xfs_syncd_stop(mp); out_unmount: diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index 89dbb4a50872..79c05ac85bfe 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c @@ -296,8 +296,6 @@ 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/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index ebdb88840a47..64981d7e7375 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -917,14 +917,6 @@ 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); /* @@ -1429,14 +1421,6 @@ xfs_link( 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 * the tree quota mechanism could be circumvented. diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 42b77b5446d2..70cfcb2d63c4 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -24,7 +24,9 @@ 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/include/linux/audit.h b/include/linux/audit.h index 9ff7a2c48b50..ed3ef1972496 100644 --- a/include/linux/audit.h +++ b/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, - struct path *path); + const 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/include/linux/binfmts.h b/include/linux/binfmts.h index 0092102db2de..366422bc1633 100644 --- a/include/linux/binfmts.h +++ b/include/linux/binfmts.h @@ -92,17 +92,17 @@ struct linux_binfmt { unsigned long min_coredump; /* minimal dump size */ }; -extern int __register_binfmt(struct linux_binfmt *fmt, int insert); +extern void __register_binfmt(struct linux_binfmt *fmt, int insert); /* Registration of default binfmt handlers */ -static inline int register_binfmt(struct linux_binfmt *fmt) +static inline void register_binfmt(struct linux_binfmt *fmt) { - return __register_binfmt(fmt, 0); + __register_binfmt(fmt, 0); } /* Same as above, but adds a new binfmt at the top of the list */ -static inline int insert_binfmt(struct linux_binfmt *fmt) +static inline void insert_binfmt(struct linux_binfmt *fmt) { - return __register_binfmt(fmt, 1); + __register_binfmt(fmt, 1); } extern void unregister_binfmt(struct linux_binfmt *); diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 8a94217b298e..48ce5479386c 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h @@ -75,6 +75,11 @@ */ #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). */ @@ -309,6 +314,8 @@ 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/include/linux/dcache.h b/include/linux/dcache.h index ff5f5256d175..7e11f1418203 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -222,7 +222,6 @@ 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 *); /* <clickety>-<click> the ramfs-type tree */ diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 6169c26fd8c8..ae36b72c22f3 100644 --- a/include/linux/debugfs.h +++ b/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, mode_t mode, +struct dentry *debugfs_create_regset32(const char *name, umode_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, - mode_t mode, struct dentry *parent, + umode_t mode, struct dentry *parent, struct debugfs_regset32 *regset) { return ERR_PTR(-ENODEV); diff --git a/include/linux/device.h b/include/linux/device.h index 7c46bc32fcbf..5ad17cccdd71 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -262,10 +262,6 @@ 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/include/linux/file.h b/include/linux/file.h index 21a79958541c..58bf158c53d9 100644 --- a/include/linux/file.h +++ b/include/linux/file.h @@ -12,7 +12,6 @@ struct file; extern void fput(struct file *); -extern void drop_file_write_access(struct file *file); struct file_operations; struct vfsmount; diff --git a/include/linux/fs.h b/include/linux/fs.h index 69cd5bb640f5..9bbe1a9ac432 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1459,6 +1459,7 @@ 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. @@ -1811,11 +1812,11 @@ static inline void inode_inc_iversion(struct inode *inode) spin_unlock(&inode->i_lock); } -extern void touch_atime(struct vfsmount *mnt, struct dentry *dentry); +extern void touch_atime(struct path *); static inline void file_accessed(struct file *file) { if (!(file->f_flags & O_NOATIME)) - touch_atime(file->f_path.mnt, file->f_path.dentry); + touch_atime(&file->f_path); } int sync_inode(struct inode *inode, struct writeback_control *wbc); @@ -2304,7 +2305,10 @@ 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); -extern int generic_drop_inode(struct inode *inode); +static inline int generic_drop_inode(struct inode *inode) +{ + return !inode->i_nlink || inode_unhashed(inode); +} extern struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval, int (*test)(struct inode *, void *), diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h index b148087f49a6..fa98bdb073b9 100644 --- a/include/linux/gfs2_ondisk.h +++ b/include/linux/gfs2_ondisk.h @@ -168,6 +168,7 @@ 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/include/linux/key.h b/include/linux/key.h index 5253471cd2ea..1600ebf717a7 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -155,6 +155,7 @@ 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/include/linux/magic.h b/include/linux/magic.h index 2d4beab0d5b7..b7ed4759dbb2 100644 --- a/include/linux/magic.h +++ b/include/linux/magic.h @@ -42,6 +42,7 @@ #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/include/linux/mm.h b/include/linux/mm.h index b1c8318e32b8..ee67e326b6f8 100644 --- a/include/linux/mm.h +++ b/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); -unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, +void zap_page_range(struct vm_area_struct *vma, unsigned long address, unsigned long size, struct zap_details *); -unsigned long unmap_vmas(struct mmu_gather *tlb, +void 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/include/linux/of.h b/include/linux/of.h index f02d8b2f799d..d46a18ffbebb 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -58,6 +58,9 @@ 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; @@ -72,6 +75,13 @@ 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/include/linux/padata.h b/include/linux/padata.h index 4633b2f726b6..86292beebfe2 100644 --- a/include/linux/padata.h +++ b/include/linux/padata.h @@ -46,7 +46,6 @@ 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); @@ -116,7 +115,6 @@ 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. @@ -129,12 +127,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/include/linux/pci.h b/include/linux/pci.h index b843fe79583b..27bf521bcebd 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1660,6 +1660,13 @@ 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/include/linux/prctl.h b/include/linux/prctl.h index 7ddc7f1b480f..a0413ac3abe8 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -114,4 +114,11 @@ # 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/include/linux/qnx6_fs.h b/include/linux/qnx6_fs.h new file mode 100644 index 000000000000..26049eab9010 --- /dev/null +++ b/include/linux/qnx6_fs.h @@ -0,0 +1,134 @@ +/* + * 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 <linux/types.h> +#include <linux/magic.h> + +#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/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h index 2213ddcce20c..ea3700cd7367 100644 --- a/include/linux/reiserfs_fs.h +++ b/include/linux/reiserfs_fs.h @@ -1,32 +1,12 @@ /* * 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 <linux/types.h> #include <linux/magic.h> -#ifdef __KERNEL__ -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/sched.h> -#include <linux/workqueue.h> -#include <asm/unaligned.h> -#include <linux/bitops.h> -#include <linux/proc_fs.h> -#include <linux/buffer_head.h> -#include <linux/reiserfs_fs_i.h> -#include <linux/reiserfs_fs_sb.h> -#endif - /* * include/linux/reiser_fs.h * @@ -43,2318 +23,4 @@ #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/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h deleted file mode 100644 index 97959bdfe214..000000000000 --- a/include/linux/reiserfs_fs_i.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _REISER_FS_I -#define _REISER_FS_I - -#include <linux/list.h> - -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/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h deleted file mode 100644 index 8c9e85c64b46..000000000000 --- a/include/linux/reiserfs_fs_sb.h +++ /dev/null @@ -1,554 +0,0 @@ -/* 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 <linux/workqueue.h> -#include <linux/rwsem.h> -#include <linux/mutex.h> -#include <linux/sched.h> -#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/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h index c2b71473266e..d8ce17c2459a 100644 --- a/include/linux/reiserfs_xattr.h +++ b/include/linux/reiserfs_xattr.h @@ -21,132 +21,4 @@ struct reiserfs_security_handle { size_t length; }; -#ifdef __KERNEL__ - -#include <linux/init.h> -#include <linux/list.h> -#include <linux/rwsem.h> -#include <linux/reiserfs_fs_i.h> -#include <linux/reiserfs_fs.h> - -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/include/linux/security.h b/include/linux/security.h index c8949385e56e..673afbb8238a 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -22,22 +22,36 @@ #ifndef __LINUX_SECURITY_H #define __LINUX_SECURITY_H -#include <linux/fs.h> -#include <linux/fsnotify.h> -#include <linux/binfmts.h> -#include <linux/dcache.h> -#include <linux/signal.h> -#include <linux/resource.h> -#include <linux/sem.h> -#include <linux/shm.h> -#include <linux/mm.h> /* PAGE_ALIGN */ -#include <linux/msg.h> -#include <linux/sched.h> #include <linux/key.h> -#include <linux/xfrm.h> +#include <linux/capability.h> #include <linux/slab.h> -#include <linux/xattr.h> -#include <net/flow.h> +#include <linux/err.h> + +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; /* Maximum number of letters for an LSM name string */ #define SECURITY_NAME_MAX 10 @@ -49,6 +63,7 @@ struct ctl_table; struct audit_krule; struct user_namespace; +struct timezone; /* * These functions are in security/capability.c and are used @@ -131,18 +146,6 @@ 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 @@ -651,6 +654,10 @@ 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. @@ -1493,6 +1500,7 @@ 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, @@ -1674,9 +1682,7 @@ 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); @@ -1752,6 +1758,7 @@ 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); @@ -1896,25 +1903,11 @@ 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); @@ -2245,6 +2238,9 @@ 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/include/linux/trace_seq.h b/include/linux/trace_seq.h index 7dadc3df0c77..a32d86ec8bf2 100644 --- a/include/linux/trace_seq.h +++ b/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, struct path *path); +extern int trace_seq_path(struct trace_seq *s, const 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, struct path *path) +static inline int trace_seq_path(struct trace_seq *s, const struct path *path) { return 0; } diff --git a/include/net/af_unix.h b/include/net/af_unix.h index 5a4e29b168c9..ca68e2cef230 100644 --- a/include/net/af_unix.h +++ b/include/net/af_unix.h @@ -49,8 +49,7 @@ struct unix_sock { /* WARNING: sk has to be the first member */ struct sock sk; struct unix_address *addr; - struct dentry *dentry; - struct vfsmount *mnt; + struct path path; struct mutex readlock; struct sock *peer; struct sock *other; diff --git a/include/net/sock.h b/include/net/sock.h index f84be9ed6110..04bc0b30e9e9 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -56,6 +56,8 @@ #include <linux/memcontrol.h> #include <linux/res_counter.h> #include <linux/static_key.h> +#include <linux/aio.h> +#include <linux/sched.h> #include <linux/filter.h> #include <linux/rculist_nulls.h> diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c index 887629e24c54..01f1306aa26e 100644 --- a/init/do_mounts_rd.c +++ b/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) && !defined(CONFIG_PPC_ISERIES) +#if !defined(CONFIG_S390) 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) && !defined(CONFIG_PPC_ISERIES) +#if !defined(CONFIG_S390) if (!(i % 16)) { printk("%c\b", rotator[rotate & 0x3]); rotate++; diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 86ee272de210..28bd64ddeda3 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -188,30 +188,20 @@ 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)) { - error = PTR_ERR(inode); - goto out; - } + inode = mqueue_get_inode(sb, ns, S_IFDIR | S_ISVTX | S_IRWXUGO, NULL); + if (IS_ERR(inode)) + return PTR_ERR(inode); - sb->s_root = d_alloc_root(inode); - if (!sb->s_root) { - iput(inode); - error = -ENOMEM; - goto out; - } - error = 0; - -out: - return error; + sb->s_root = d_make_root(inode); + if (!sb->s_root) + return -ENOMEM; + return 0; } static struct dentry *mqueue_mount(struct file_system_type *fs_type, diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 5652101cdac0..26143d377c95 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -13,7 +13,9 @@ #include <linux/security.h> #include <linux/slab.h> #include <linux/ipc.h> +#include <linux/msg.h> #include <linux/ipc_namespace.h> +#include <linux/utsname.h> #include <asm/uaccess.h> #include "util.h" diff --git a/kernel/audit.c b/kernel/audit.c index bb0eb5bb9a0a..1c7f2c61416b 100644 --- a/kernel/audit.c +++ b/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, - struct path *path) + const struct path *path) { char *p, *pathname; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 391d5e991e5f..f4ea4b6f3cf1 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1472,7 +1472,6 @@ 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; @@ -1481,12 +1480,9 @@ 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); - dentry = d_alloc_root(inode); - if (!dentry) { - iput(inode); + sb->s_root = d_make_root(inode); + if (!sb->s_root) 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/kernel/cred.c b/kernel/cred.c index 5791612a4045..97b36eeca4c9 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -16,6 +16,7 @@ #include <linux/keyctl.h> #include <linux/init_task.h> #include <linux/security.h> +#include <linux/binfmts.h> #include <linux/cn_proc.h> #if 0 diff --git a/kernel/exit.c b/kernel/exit.c index d26acd3c1e2e..16b07bfac224 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -52,6 +52,7 @@ #include <linux/hw_breakpoint.h> #include <linux/oom.h> #include <linux/writeback.h> +#include <linux/shm.h> #include <asm/uaccess.h> #include <asm/unistd.h> diff --git a/kernel/fork.c b/kernel/fork.c index 9cc227d54102..37674ec55cde 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -193,6 +193,7 @@ 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); @@ -355,7 +356,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(len)) + if (security_vm_enough_memory_mm(oldmm, len)) /* sic */ goto fail_nomem; charge = len; } diff --git a/kernel/padata.c b/kernel/padata.c index b45259931512..6f10eb285ece 100644 --- a/kernel/padata.c +++ b/kernel/padata.c @@ -29,7 +29,6 @@ #include <linux/sysfs.h> #include <linux/rcupdate.h> -#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) @@ -43,18 +42,19 @@ static int padata_index_to_cpu(struct parallel_data *pd, int cpu_index) return target_cpu; } -static int padata_cpu_hash(struct padata_priv *padata) +static int padata_cpu_hash(struct parallel_data *pd) { 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. */ - cpu_index = padata->seq_nr % cpumask_weight(pd->cpumask.pcpu); + + spin_lock(&pd->seq_lock); + cpu_index = pd->seq_nr % cpumask_weight(pd->cpumask.pcpu); + pd->seq_nr++; + spin_unlock(&pd->seq_lock); return padata_index_to_cpu(pd, cpu_index); } @@ -132,12 +132,7 @@ int padata_do_parallel(struct padata_instance *pinst, padata->pd = pd; padata->cb_cpu = cb_cpu; - 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); + target_cpu = padata_cpu_hash(pd); queue = per_cpu_ptr(pd->pqueue, target_cpu); spin_lock(&queue->parallel.lock); @@ -173,7 +168,7 @@ EXPORT_SYMBOL(padata_do_parallel); static struct padata_priv *padata_get_next(struct parallel_data *pd) { int cpu, num_cpus; - int next_nr, next_index; + unsigned int next_nr, next_index; struct padata_parallel_queue *queue, *next_queue; struct padata_priv *padata; struct padata_list *reorder; @@ -189,14 +184,6 @@ 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; @@ -205,8 +192,6 @@ 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); @@ -230,6 +215,7 @@ out: 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; @@ -270,13 +256,14 @@ static void padata_reorder(struct parallel_data *pd) return; } - squeue = per_cpu_ptr(pd->squeue, padata->cb_cpu); + cb_cpu = padata->cb_cpu; + squeue = per_cpu_ptr(pd->squeue, cb_cpu); spin_lock(&squeue->serial.lock); list_add_tail(&padata->list, &squeue->serial.list); spin_unlock(&squeue->serial.lock); - queue_work_on(padata->cb_cpu, pinst->wq, &squeue->work); + queue_work_on(cb_cpu, pinst->wq, &squeue->work); } spin_unlock_bh(&pd->lock); @@ -400,7 +387,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, num_cpus, cpu; + int cpu_index, cpu; struct padata_parallel_queue *pqueue; cpu_index = 0; @@ -415,9 +402,6 @@ 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. */ @@ -444,7 +428,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); - atomic_set(&pd->seq_nr, -1); + pd->seq_nr = 0; atomic_set(&pd->reorder_objects, 0); atomic_set(&pd->refcnt, 0); pd->pinst = pinst; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index a35cb8dbd8c4..503d6426126d 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -71,6 +71,7 @@ #include <linux/ftrace.h> #include <linux/slab.h> #include <linux/init_task.h> +#include <linux/binfmts.h> #include <asm/tlb.h> #include <asm/irq_regs.h> diff --git a/kernel/sysctl.c b/kernel/sysctl.c index f487f257e05e..11d53046b905 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -58,6 +58,7 @@ #include <linux/oom.h> #include <linux/kmod.h> #include <linux/capability.h> +#include <linux/binfmts.h> #include <asm/uaccess.h> #include <asm/processor.h> diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index c5a01873567d..859fae6b1825 100644 --- a/kernel/trace/trace_output.c +++ b/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, struct path *path) +int trace_seq_path(struct trace_seq *s, const struct path *path) { unsigned char *p; diff --git a/mm/memory.c b/mm/memory.c index 1e0561e1f190..3416b6e018d6 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -1267,10 +1267,10 @@ static inline unsigned long zap_pud_range(struct mmu_gather *tlb, return addr; } -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) +static void 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; @@ -1290,8 +1290,47 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb, } while (pgd++, addr = next, addr != end); tlb_end_vma(tlb, vma); mem_cgroup_uncharge_end(); +} - return addr; + +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); + } } /** @@ -1303,8 +1342,6 @@ static unsigned long unmap_page_range(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. @@ -1316,55 +1353,18 @@ static unsigned long unmap_page_range(struct mmu_gather *tlb, * ensure that any thus-far unmapped pages are flushed before unmap_vmas() * drops the lock and schedules. */ -unsigned long unmap_vmas(struct mmu_gather *tlb, +void 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) { - unsigned long end; - - 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; - - 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); - } - } - + 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); - return start; /* which is now the end (or restart) address */ } /** @@ -1373,8 +1373,34 @@ unsigned long unmap_vmas(struct mmu_gather *tlb, * @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; + + 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); +} + +/** + * zap_page_range_single - 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. */ -unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, +static void zap_page_range_single(struct vm_area_struct *vma, unsigned long address, unsigned long size, struct zap_details *details) { struct mm_struct *mm = vma->vm_mm; @@ -1385,9 +1411,10 @@ unsigned long zap_page_range(struct vm_area_struct *vma, unsigned long address, lru_add_drain(); tlb_gather_mmu(&tlb, mm, 0); update_hiwater_rss(mm); - end = unmap_vmas(&tlb, vma, address, end, &nr_accounted, details); + 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); tlb_finish_mmu(&tlb, address, end); - return end; } /** @@ -1408,7 +1435,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(vma, address, size, NULL); + zap_page_range_single(vma, address, size, NULL); return 0; } EXPORT_SYMBOL_GPL(zap_vma_ptes); @@ -2755,7 +2782,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(vma, start_addr, end_addr - start_addr, details); + zap_page_range_single(vma, start_addr, end_addr - start_addr, details); } static inline void unmap_mapping_range_tree(struct prio_tree_root *root, diff --git a/mm/mmap.c b/mm/mmap.c index 230f0bac06b6..a7bf6a31c9f6 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -935,6 +935,19 @@ 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). */ @@ -1234,7 +1247,7 @@ munmap_back: */ if (accountable_mapping(file, vm_flags)) { charged = len >> PAGE_SHIFT; - if (security_vm_enough_memory(charged)) + if (security_vm_enough_memory_mm(mm, charged)) return -ENOMEM; vm_flags |= VM_ACCOUNT; } @@ -2183,7 +2196,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(len >> PAGE_SHIFT)) + if (security_vm_enough_memory_mm(mm, len >> PAGE_SHIFT)) return -ENOMEM; /* Can we just expand an old private anonymous mapping? */ @@ -2227,7 +2240,6 @@ 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); @@ -2252,11 +2264,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 */ - end = unmap_vmas(&tlb, vma, 0, -1, &nr_accounted, NULL); + 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, end); + tlb_finish_mmu(&tlb, 0, -1); /* * Walk the list again, actually closing and freeing it, diff --git a/mm/mprotect.c b/mm/mprotect.c index c621e999cbf7..a40992610ab6 100644 --- a/mm/mprotect.c +++ b/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(charged)) + if (security_vm_enough_memory_mm(mm, charged)) return -ENOMEM; newflags |= VM_ACCOUNT; } diff --git a/mm/mremap.c b/mm/mremap.c index 87bb8393e7d2..db8d983b5a7d 100644 --- a/mm/mremap.c +++ b/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(charged)) + if (security_vm_enough_memory_mm(mm, charged)) goto Efault; *p = charged; } diff --git a/mm/shmem.c b/mm/shmem.c index 7cc80833b74a..f99ff3e50bd6 100644 --- a/mm/shmem.c +++ b/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_kern(VM_ACCT(size)); + 0 : security_vm_enough_memory_mm(current->mm, 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_kern(VM_ACCT(PAGE_CACHE_SIZE)) : 0; + security_vm_enough_memory_mm(current->mm, VM_ACCT(PAGE_CACHE_SIZE)) : 0; } static inline void shmem_unacct_blocks(unsigned long flags, long pages) @@ -2231,7 +2231,6 @@ 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; @@ -2288,14 +2287,11 @@ int shmem_fill_super(struct super_block *sb, void *data, int silent) goto failed; inode->i_uid = sbinfo->uid; inode->i_gid = sbinfo->gid; - root = d_alloc_root(inode); - if (!root) - goto failed_iput; - sb->s_root = root; + sb->s_root = d_make_root(inode); + if (!sb->s_root) + goto failed; return 0; -failed_iput: - iput(inode); failed: shmem_put_super(sb); return err; diff --git a/mm/swapfile.c b/mm/swapfile.c index 21b56945c5d2..dae42f380d6e 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -1561,6 +1561,8 @@ 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)) @@ -1588,7 +1590,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) spin_unlock(&swap_lock); goto out_dput; } - if (!security_vm_enough_memory(p->pages)) + if (!security_vm_enough_memory_mm(current->mm, p->pages)) vm_unacct_memory(p->pages); else { err = -ENOMEM; diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index fa000d26dc60..c73bba326d70 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c @@ -281,6 +281,7 @@ 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/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 63a7a7add21e..7d6dd6efbdbe 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -1033,13 +1033,9 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) sb->s_time_gran = 1; inode = rpc_get_inode(sb, S_IFDIR | 0755); - if (!inode) - return -ENOMEM; - sb->s_root = root = d_alloc_root(inode); - if (!root) { - iput(inode); + sb->s_root = root = d_make_root(inode); + if (!root) return -ENOMEM; - } if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) return -ENOMEM; return 0; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 8ee85aa79fa7..eb4277c33188 100644 --- a/net/unix/af_unix.c +++ b/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)->dentry; + struct dentry *dentry = unix_sk(s)->path.dentry; if (dentry && dentry->d_inode == i) { sock_hold(s); @@ -377,8 +377,7 @@ 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 dentry *dentry; - struct vfsmount *mnt; + struct path path; struct sock *skpair; struct sk_buff *skb; int state; @@ -389,10 +388,9 @@ static int unix_release_sock(struct sock *sk, int embrion) unix_state_lock(sk); sock_orphan(sk); sk->sk_shutdown = SHUTDOWN_MASK; - dentry = u->dentry; - u->dentry = NULL; - mnt = u->mnt; - u->mnt = NULL; + path = u->path; + u->path.dentry = NULL; + u->path.mnt = NULL; state = sk->sk_state; sk->sk_state = TCP_CLOSE; unix_state_unlock(sk); @@ -425,10 +423,8 @@ static int unix_release_sock(struct sock *sk, int embrion) kfree_skb(skb); } - if (dentry) { - dput(dentry); - mntput(mnt); - } + if (path.dentry) + path_put(&path); sock_put(sk); @@ -641,8 +637,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->dentry = NULL; - u->mnt = NULL; + u->path.dentry = NULL; + u->path.mnt = NULL; spin_lock_init(&u->lock); atomic_long_set(&u->inflight, 0); INIT_LIST_HEAD(&u->link); @@ -788,7 +784,7 @@ static struct sock *unix_find_other(struct net *net, goto put_fail; if (u->sk_type == type) - touch_atime(path.mnt, path.dentry); + touch_atime(&path); path_put(&path); @@ -802,9 +798,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)->dentry; + dentry = unix_sk(u)->path.dentry; if (dentry) - touch_atime(unix_sk(u)->mnt, dentry); + touch_atime(&unix_sk(u)->path); } else goto fail; } @@ -910,8 +906,7 @@ out_mknod_drop_write: list = &unix_socket_table[addr->hash]; } else { list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; - u->dentry = path.dentry; - u->mnt = path.mnt; + u->path = path; } err = 0; @@ -1193,9 +1188,9 @@ restart: atomic_inc(&otheru->addr->refcnt); newu->addr = otheru->addr; } - if (otheru->dentry) { - newu->dentry = dget(otheru->dentry); - newu->mnt = mntget(otheru->mnt); + if (otheru->path.dentry) { + path_get(&otheru->path); + newu->path = otheru->path; } /* Set credentials */ diff --git a/net/unix/diag.c b/net/unix/diag.c index 4195555aea65..f0486ae9ebe6 100644 --- a/net/unix/diag.c +++ b/net/unix/diag.c @@ -29,7 +29,7 @@ rtattr_failure: static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb) { - struct dentry *dentry = unix_sk(sk)->dentry; + struct dentry *dentry = unix_sk(sk)->path.dentry; struct unix_diag_vfs *uv; if (dentry) { diff --git a/security/Kconfig b/security/Kconfig index 51bd5a0b69ae..ccc61f8006b2 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -187,6 +187,7 @@ source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig source security/apparmor/Kconfig +source security/yama/Kconfig source security/integrity/Kconfig @@ -196,6 +197,7 @@ 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 @@ -214,6 +216,9 @@ 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" @@ -225,6 +230,7 @@ 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/security/Makefile b/security/Makefile index a5e502f8a05b..c26c81e92571 100644 --- a/security/Makefile +++ b/security/Makefile @@ -7,6 +7,7 @@ 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 @@ -21,6 +22,7 @@ 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/security/apparmor/Makefile b/security/apparmor/Makefile index 2dafe50a2e25..806bd19af7f2 100644 --- a/security/apparmor/Makefile +++ b/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 *capability_names[] = {" > $@ ;\ +cmd_make-caps = echo "static const char *const 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,25 +28,38 @@ cmd_make-caps = echo "static const char *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 Thi is +# RLIMIT defines to the order defined in asm-generic/resource.h This 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 *rlim_names[] = {" > $@ ;\ +cmd_make-rlim = echo "static const char *const rlim_names[RLIM_NLIMITS] = {" \ + > $@ ;\ sed $< >> $@ -r -n \ -e 's/^\# ?define[ \t]+(RLIMIT_([A-Z0-9_]+)).*/[\1] = "\L\2",/p';\ echo "};" >> $@ ;\ - echo "static const int rlim_map[] = {" >> $@ ;\ + echo "static const int rlim_map[RLIM_NLIMITS] = {" >> $@ ;\ sed -r -n "s/^\# ?define[ \t]+(RLIMIT_[A-Z0-9_]+).*/\1,/p" $< >> $@ ;\ - echo "};" >> $@ + 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/' >> $@ $(obj)/capability.o : $(obj)/capability_names.h $(obj)/resource.o : $(obj)/rlim_names.h -$(obj)/capability_names.h : $(srctree)/include/linux/capability.h +$(obj)/capability_names.h : $(srctree)/include/linux/capability.h \ + $(src)/Makefile $(call cmd,make-caps) -$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h +$(obj)/rlim_names.h : $(srctree)/include/asm-generic/resource.h \ + $(src)/Makefile $(call cmd,make-rlim) diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index e39df6d43779..16c15ec6f670 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c @@ -18,12 +18,14 @@ #include <linux/seq_file.h> #include <linux/uaccess.h> #include <linux/namei.h> +#include <linux/capability.h> #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 @@ -142,38 +144,166 @@ static const struct file_operations aa_fs_profile_remove = { .llseek = default_llseek, }; -/** Base file system setup **/ +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; -static struct dentry *aa_fs_dentry __initdata; + 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 void __init aafs_remove(const char *name) +static int aa_fs_seq_open(struct inode *inode, struct file *file) { - struct dentry *dentry; + 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"), + { } +}; - dentry = lookup_one_len(name, aa_fs_dentry, strlen(name)); - if (!IS_ERR(dentry)) { - securityfs_remove(dentry); - dput(dentry); +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) +{ + 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; } /** - * 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) + * 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 * - * Used aafs_remove to remove entries created with this fn. + * Use aafs_remove_dir to remove entries created with this fn. */ -static int __init aafs_create(const char *name, umode_t mask, - const struct file_operations *fops) +static int __init aafs_create_dir(struct aa_fs_entry *fs_dir, + struct dentry *parent) { - struct dentry *dentry; + int error; + struct aa_fs_entry *fs_file; - dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry, - NULL, fops); + 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; + } - return IS_ERR(dentry) ? PTR_ERR(dentry) : 0; + 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; + } + + 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) + */ +static void __init aafs_remove_dir(struct aa_fs_entry *fs_dir) +{ + struct aa_fs_entry *fs_file; + + 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); + } + + aafs_remove_file(fs_dir); } /** @@ -183,14 +313,7 @@ static int __init aafs_create(const char *name, umode_t mask, */ void __init aa_destroy_aafs(void) { - if (aa_fs_dentry) { - aafs_remove(".remove"); - aafs_remove(".replace"); - aafs_remove(".load"); - - securityfs_remove(aa_fs_dentry); - aa_fs_dentry = NULL; - } + aafs_remove_dir(&aa_fs_entry); } /** @@ -207,25 +330,13 @@ static int __init aa_create_aafs(void) if (!apparmor_initialized) return 0; - if (aa_fs_dentry) { + if (aa_fs_entry.dentry) { AA_ERROR("%s: AppArmor securityfs already exists\n", __func__); return -EEXIST; } - 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); + /* Populate fs tree. */ + error = aafs_create_dir(&aa_fs_entry, NULL); if (error) goto error; diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index f3fafedd798a..5ff67776a5ad 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c @@ -19,7 +19,7 @@ #include "include/audit.h" #include "include/policy.h" -const char *op_table[] = { +const char *const op_table[] = { "null", "sysctl", @@ -73,7 +73,7 @@ const char *op_table[] = { "profile_remove" }; -const char *audit_mode_names[] = { +const char *const audit_mode_names[] = { "normal", "quiet_denied", "quiet", @@ -81,7 +81,7 @@ const char *audit_mode_names[] = { "all" }; -static char *aa_audit_type[] = { +static const char *const aa_audit_type[] = { "AUDIT", "ALLOWED", "DENIED", @@ -89,6 +89,7 @@ static char *aa_audit_type[] = { "STATUS", "ERROR", "KILLED" + "AUTO" }; /* diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index c1e18ba5bdc0..7c69599a69e1 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c @@ -372,13 +372,12 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) state = profile->file.start; /* buffer freed below, name is pointer into buffer */ - error = aa_get_name(&bprm->file->f_path, profile->path_flags, &buffer, - &name); + error = aa_path_name(&bprm->file->f_path, profile->path_flags, &buffer, + &name, &info); 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/security/apparmor/file.c b/security/apparmor/file.c index 7312db741219..3022c0f4f0db 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c @@ -173,8 +173,6 @@ static u32 map_old_perms(u32 old) if (old & 0x40) /* AA_EXEC_MMAP */ new |= AA_EXEC_MMAP; - new |= AA_MAY_META_READ; - return new; } @@ -212,6 +210,7 @@ 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) @@ -279,22 +278,16 @@ 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_get_name(path, flags, &buffer, &name); + error = aa_path_name(path, flags, &buffer, &name, &info); 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); @@ -365,12 +358,14 @@ int aa_path_link(struct aa_profile *profile, struct dentry *old_dentry, lperms = nullperms; /* buffer freed below, lname is pointer in buffer */ - error = aa_get_name(&link, profile->path_flags, &buffer, &lname); + error = aa_path_name(&link, profile->path_flags, &buffer, &lname, + &info); if (error) goto audit; /* buffer2 freed below, tname is pointer in buffer2 */ - error = aa_get_name(&target, profile->path_flags, &buffer2, &tname); + error = aa_path_name(&target, profile->path_flags, &buffer2, &tname, + &info); if (error) goto audit; diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h index df3649560818..40aedd9f73ea 100644 --- a/security/apparmor/include/apparmor.h +++ b/security/apparmor/include/apparmor.h @@ -19,6 +19,19 @@ #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; @@ -81,7 +94,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_match_len(dfa, start, "", 1); + return aa_dfa_next(dfa, start, 0); } static inline bool mediated_filesystem(struct inode *inode) diff --git a/security/apparmor/include/apparmorfs.h b/security/apparmor/include/apparmorfs.h index cb1e93a114d7..7ea4769fab3f 100644 --- a/security/apparmor/include/apparmorfs.h +++ b/security/apparmor/include/apparmorfs.h @@ -15,6 +15,50 @@ #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/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 1951786d32e9..4ba78c203af1 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h @@ -25,11 +25,9 @@ struct aa_profile; -extern const char *audit_mode_names[]; +extern const char *const 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 */ @@ -45,10 +43,11 @@ enum audit_type { AUDIT_APPARMOR_HINT, AUDIT_APPARMOR_STATUS, AUDIT_APPARMOR_ERROR, - AUDIT_APPARMOR_KILL + AUDIT_APPARMOR_KILL, + AUDIT_APPARMOR_AUTO }; -extern const char *op_table[]; +extern const char *const op_table[]; enum aa_ops { OP_NULL, diff --git a/security/apparmor/include/file.h b/security/apparmor/include/file.h index ab8c6d87f758..f98fd4701d80 100644 --- a/security/apparmor/include/file.h +++ b/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 { + } else if (old_index) { index |= AA_X_TABLE; index |= old_index - 4; } diff --git a/security/apparmor/include/match.h b/security/apparmor/include/match.h index a4a863997bd5..775843e7f984 100644 --- a/security/apparmor/include/match.h +++ b/security/apparmor/include/match.h @@ -116,6 +116,9 @@ 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/security/apparmor/include/path.h b/security/apparmor/include/path.h index 27b327a7fae5..286ac75dc88b 100644 --- a/security/apparmor/include/path.h +++ b/security/apparmor/include/path.h @@ -26,6 +26,7 @@ enum path_flags { PATH_MEDIATE_DELETED = 0x10000, /* mediate deleted paths */ }; -int aa_get_name(struct path *path, int flags, char **buffer, const char **name); +int aa_path_name(struct path *path, int flags, char **buffer, + const char **name, const char **info); #endif /* __AA_PATH_H */ diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index aeda5cf56904..bda4569fdd83 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h @@ -29,7 +29,7 @@ #include "file.h" #include "resource.h" -extern const char *profile_mode_names[]; +extern const char *const profile_mode_names[]; #define APPARMOR_NAMES_MAX_INDEX 3 #define COMPLAIN_MODE(_profile) \ @@ -129,6 +129,17 @@ 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 @@ -143,6 +154,7 @@ struct aa_namespace { * @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 @@ -179,6 +191,7 @@ 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/security/apparmor/include/resource.h b/security/apparmor/include/resource.h index 02baec732bb5..d3f4cf027957 100644 --- a/security/apparmor/include/resource.h +++ b/security/apparmor/include/resource.h @@ -18,6 +18,8 @@ #include <linux/resource.h> #include <linux/sched.h> +#include "apparmorfs.h" + struct aa_profile; /* struct aa_rlimit - rlimit settings for the profile @@ -32,6 +34,8 @@ 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/security/apparmor/match.c b/security/apparmor/match.c index 94de6b4907c8..90971a8c3789 100644 --- a/security/apparmor/match.c +++ b/security/apparmor/match.c @@ -335,12 +335,12 @@ unsigned int aa_dfa_match_len(struct aa_dfa *dfa, unsigned int start, } /** - * aa_dfa_next_state - traverse @dfa to find state @str stops at + * aa_dfa_match - 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_next_state will match @str against the dfa and return the state it + * aa_dfa_match 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,5 +349,79 @@ 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) { - return aa_dfa_match_len(dfa, start, str, strlen(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 <state>, 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 <state>, 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; } diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 9d070a7c3ffc..2daeea4f9266 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c @@ -83,31 +83,29 @@ 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); - connected = 0; + } else { + res = d_absolute_path(path, buf, buflen); + if (!our_mnt(path->mnt)) + connected = 0; } - res = d_absolute_path(path, buf, buflen); - - *name = res; /* handle error conditions - and still allow a partial path to * be returned. */ - if (IS_ERR(res)) { - error = PTR_ERR(res); - *name = buf; - goto out; - } - if (!our_mnt(path->mnt)) + 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)) + 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 @@ -138,7 +136,7 @@ ok: /* disconnected path, don't return pathname starting * with '/' */ - error = -ESTALE; + error = -EACCES; if (*res == '/') *name = res + 1; } @@ -159,7 +157,7 @@ out: * Returns: %0 else error on failure */ static int get_name_to_buffer(struct path *path, int flags, char *buffer, - int size, char **name) + int size, char **name, const char **info) { int adjust = (flags & PATH_IS_DIR) ? 1 : 0; int error = d_namespace_path(path, buffer, size - adjust, name, flags); @@ -171,15 +169,27 @@ 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_get_name - compute the pathname of a file + * aa_path_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 @@ -192,7 +202,8 @@ static int get_name_to_buffer(struct path *path, int flags, char *buffer, * * Returns: %0 else error code if could retrieve name */ -int aa_get_name(struct path *path, int flags, char **buffer, const char **name) +int aa_path_name(struct path *path, int flags, char **buffer, const char **name, + const char **info) { char *buf, *str = NULL; int size = 256; @@ -206,7 +217,7 @@ int aa_get_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); + error = get_name_to_buffer(path, flags, buf, size, &str, info); if (error != -ENAMETOOLONG) break; @@ -214,6 +225,7 @@ int aa_get_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/security/apparmor/policy.c b/security/apparmor/policy.c index 4f0eadee78b8..906414383022 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c @@ -93,7 +93,7 @@ /* root profile namespace */ struct aa_namespace *root_ns; -const char *profile_mode_names[] = { +const char *const profile_mode_names[] = { "enforce", "complain", "kill", @@ -749,6 +749,7 @@ 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/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 741dd13e089b..25fd51edc8da 100644 --- a/security/apparmor/policy_unpack.c +++ b/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 (NOT NULL) + * @e: buffer position info * @error: error code * * Returns: %0 or error @@ -95,7 +95,8 @@ 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); - sa.aad.iface.pos = e->pos - e->start; + if (e) + sa.aad.iface.pos = e->pos - e->start; sa.aad.iface.target = new; sa.aad.name = name; sa.aad.info = info; @@ -468,7 +469,7 @@ static struct aa_profile *unpack_profile(struct aa_ext *e) { struct aa_profile *profile = NULL; const char *name = NULL; - int error = -EPROTO; + int i, error = -EPROTO; kernel_cap_t tmpcap; u32 tmp; @@ -554,11 +555,35 @@ 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/security/apparmor/resource.c b/security/apparmor/resource.c index a4136c10b1c6..72c25a4f2cfd 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c @@ -23,6 +23,11 @@ */ #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/security/capability.c b/security/capability.c index 2f680eb02b59..5bb21b1c448c 100644 --- a/security/capability.c +++ b/security/capability.c @@ -358,6 +358,10 @@ 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; @@ -954,6 +958,7 @@ 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/security/commoncap.c b/security/commoncap.c index 7ce191ea29a0..0cf4b53480a7 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -28,6 +28,7 @@ #include <linux/prctl.h> #include <linux/securebits.h> #include <linux/user_namespace.h> +#include <linux/binfmts.h> /* * If a non-root user executes a setuid-root binary in diff --git a/security/integrity/ima/Kconfig b/security/integrity/ima/Kconfig index 4f554f20dc97..35664fe6daa1 100644 --- a/security/integrity/ima/Kconfig +++ b/security/integrity/ima/Kconfig @@ -9,8 +9,8 @@ config IMA select CRYPTO_HMAC select CRYPTO_MD5 select CRYPTO_SHA1 - select TCG_TPM if !S390 && !UML - select TCG_TIS if TCG_TPM + select TCG_TPM if HAS_IOMEM && !UML + select TCG_TIS if TCG_TPM && X86 help The Trusted Computing Group(TCG) runtime Integrity Measurement Architecture(IMA) maintains a list of hash diff --git a/security/integrity/ima/ima_audit.c b/security/integrity/ima/ima_audit.c index 2ad942fb1e23..21e96bf188df 100644 --- a/security/integrity/ima/ima_audit.c +++ b/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 ? 0 : 1); + audit_log_format(ab, " res=%d", !result); audit_log_end(ab); } diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index d45061d02fee..d8edff209bf3 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c @@ -62,6 +62,7 @@ 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, @@ -417,7 +418,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/security/keys/keyctl.c b/security/keys/keyctl.c index 0b3f5d72af1c..6523599e9ac0 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -388,11 +388,24 @@ 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/security/keys/process_keys.c b/security/keys/process_keys.c index 1068cb1939b3..be7ecb2018dd 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -657,7 +657,8 @@ try_again: goto error; down_read(&cred->request_key_auth->sem); - if (cred->request_key_auth->flags & KEY_FLAG_REVOKED) { + if (test_bit(KEY_FLAG_REVOKED, + &cred->request_key_auth->flags)) { key_ref = ERR_PTR(-EKEYREVOKED); key = NULL; } else { diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 293b8c45b1d1..8b8f0902f6e5 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -313,12 +313,8 @@ static void dump_common_audit_data(struct audit_buffer *ab, } case AF_UNIX: u = unix_sk(sk); - if (u->dentry) { - struct path path = { - .dentry = u->dentry, - .mnt = u->mnt - }; - audit_log_d_path(ab, " path=", &path); + if (u->path.dentry) { + audit_log_d_path(ab, " path=", &u->path); break; } if (!u->addr) diff --git a/security/security.c b/security/security.c index d7542493454d..bf619ffc9a4d 100644 --- a/security/security.c +++ b/security/security.c @@ -19,6 +19,8 @@ #include <linux/integrity.h> #include <linux/ima.h> #include <linux/evm.h> +#include <linux/fsnotify.h> +#include <net/flow.h> #define MAX_LSM_EVM_XATTR 2 @@ -187,25 +189,11 @@ 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); @@ -729,6 +717,11 @@ 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/security/selinux/hooks.c b/security/selinux/hooks.c index 6a3683e28426..304929909375 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -81,6 +81,8 @@ #include <linux/syslog.h> #include <linux/user_namespace.h> #include <linux/export.h> +#include <linux/msg.h> +#include <linux/shm.h> #include "avc.h" #include "objsec.h" diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index e8af5b0ba80f..cd667b4089a5 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -36,6 +36,9 @@ #include <linux/magic.h> #include <linux/dcache.h> #include <linux/personality.h> +#include <linux/msg.h> +#include <linux/shm.h> +#include <linux/binfmts.h> #include "smack.h" #define task_security(task) (task_cred_xxx((task), security)) diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index 5ca47ea3049f..7ef9fa3e37e0 100644 --- a/security/tomoyo/audit.c +++ b/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". + * @wait: Pointer to "poll_table". Maybe NULL. * * Returns POLLIN | POLLRDNORM when ready to read an audit log. */ -int tomoyo_poll_log(struct file *file, poll_table *wait) +unsigned int tomoyo_poll_log(struct file *file, poll_table *wait) { if (tomoyo_log_count) return POLLIN | POLLRDNORM; diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index c47d3ce6c733..8656b16eef7b 100644 --- a/security/tomoyo/common.c +++ b/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. + * Returns 0 on success, negative value otherwise. * * 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 0; + return -EINTR; /* Is there an active domain? */ list_for_each_entry_rcu(domain, &tomoyo_domain_list, list) { /* Never delete tomoyo_kernel_domain */ @@ -1164,15 +1164,16 @@ 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) - tomoyo_delete_domain(data); + ret = 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 0; + return ret; } if (!domain) return -EINVAL; @@ -2111,7 +2112,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 || ptr->answer) + if (ptr->serial != serial) continue; domain = ptr->domain; break; @@ -2130,28 +2131,13 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by_qid * * Waits for access requests which violated policy in enforcing mode. */ -static int tomoyo_poll_query(struct file *file, poll_table *wait) +static unsigned int tomoyo_poll_query(struct file *file, poll_table *wait) { - 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); - } + 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; return 0; } @@ -2175,8 +2161,6 @@ 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; @@ -2194,8 +2178,6 @@ 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; /* @@ -2243,8 +2225,10 @@ 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; - if (!ptr->answer) - ptr->answer = answer; + ptr->answer = answer; + /* Remove from tomoyo_query_list. */ + if (ptr->answer) + list_del_init(&ptr->list); break; } spin_unlock(&tomoyo_query_list_lock); @@ -2477,18 +2461,17 @@ 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". + * @wait: Pointer to "poll_table". Maybe NULL. * - * 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. + * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write, + * POLLOUT | POLLWRNORM otherwise. */ -int tomoyo_poll_control(struct file *file, poll_table *wait) +unsigned int tomoyo_poll_control(struct file *file, poll_table *wait) { struct tomoyo_io_buffer *head = file->private_data; - if (!head->poll) - return -ENOSYS; - return head->poll(file, wait); + if (head->poll) + return head->poll(file, wait) | POLLOUT | POLLWRNORM; + return POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM; } /** diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 9512222d5581..30fd98369700 100644 --- a/security/tomoyo/common.h +++ b/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 *); - int (*poll) (struct file *file, poll_table *wait); + unsigned 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); -int tomoyo_poll_control(struct file *file, poll_table *wait); -int tomoyo_poll_log(struct file *file, poll_table *wait); +unsigned int tomoyo_poll_control(struct file *file, poll_table *wait); +unsigned 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/security/tomoyo/mount.c b/security/tomoyo/mount.c index bee09d062057..fe00cdfd0267 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -199,30 +199,32 @@ int tomoyo_mount_permission(char *dev_name, struct path *path, if (flags & MS_REMOUNT) { type = tomoyo_mounts[TOMOYO_MOUNT_REMOUNT]; flags &= ~MS_REMOUNT; - } - if (flags & MS_MOVE) { - type = tomoyo_mounts[TOMOYO_MOUNT_MOVE]; - flags &= ~MS_MOVE; - } - if (flags & MS_BIND) { + } else if (flags & MS_BIND) { type = tomoyo_mounts[TOMOYO_MOUNT_BIND]; flags &= ~MS_BIND; - } - if (flags & MS_UNBINDABLE) { - type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_UNBINDABLE]; - flags &= ~MS_UNBINDABLE; - } - if (flags & MS_PRIVATE) { + } 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; type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_PRIVATE]; flags &= ~MS_PRIVATE; - } - if (flags & MS_SLAVE) { + } else if (flags & MS_SLAVE) { + if (flags & (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE)) + return -EINVAL; type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SLAVE]; flags &= ~MS_SLAVE; - } - if (flags & MS_SHARED) { - type = tomoyo_mounts[TOMOYO_MOUNT_MAKE_SHARED]; - flags &= ~MS_SHARED; + } 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 (!type) type = "<NULL>"; diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c index 482b2a5f48f0..8592f2fc6ebb 100644 --- a/security/tomoyo/securityfs_if.c +++ b/security/tomoyo/securityfs_if.c @@ -157,9 +157,10 @@ 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". + * @wait: Pointer to "poll_table". Maybe NULL. * - * Returns 0 on success, negative value otherwise. + * Returns POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM if ready to read/write, + * POLLOUT | POLLWRNORM otherwise. */ static unsigned int tomoyo_poll(struct file *file, poll_table *wait) { diff --git a/security/yama/Kconfig b/security/yama/Kconfig new file mode 100644 index 000000000000..51d6709d8bbd --- /dev/null +++ b/security/yama/Kconfig @@ -0,0 +1,13 @@ +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/security/yama/Makefile b/security/yama/Makefile new file mode 100644 index 000000000000..8b5e06588456 --- /dev/null +++ b/security/yama/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_SECURITY_YAMA) := yama.o + +yama-y := yama_lsm.o diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c new file mode 100644 index 000000000000..573723843a04 --- /dev/null +++ b/security/yama/yama_lsm.c @@ -0,0 +1,323 @@ +/* + * Yama Linux Security Module + * + * Author: Kees Cook <keescook@chromium.org> + * + * 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 <linux/security.h> +#include <linux/sysctl.h> +#include <linux/ptrace.h> +#include <linux/prctl.h> +#include <linux/ratelimit.h> + +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); |